]> git.proxmox.com Git - package-rebuilds.git/commitdiff
open-iscsi: add source of 2.1.8-1
authorThomas Lamprecht <t.lamprecht@proxmox.com>
Fri, 3 May 2024 17:09:31 +0000 (19:09 +0200)
committerThomas Lamprecht <t.lamprecht@proxmox.com>
Mon, 6 May 2024 07:25:03 +0000 (09:25 +0200)
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
345 files changed:
pkgs/open-iscsi/open-iscsi-2.1.8/.gitignore [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/.travis.yml [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/COPYING [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/Changelog [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/Makefile [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/README [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/THANKS [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/TODO [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/NEWS [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/README.Debian [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/README.source [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/autoreconf [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/buildconfig.build-deb [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/buildconfig.build-udeb [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/buildconfig.common [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/changelog [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/control [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/copyright [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/extra/activate-storage.sh [new file with mode: 0755]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/extra/initramfs/hooks/iscsi [new file with mode: 0755]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/extra/initramfs/hooks/iscsiuio [new file with mode: 0755]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/extra/initramfs/local-bottom/iscsi [new file with mode: 0755]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/extra/initramfs/local-top/iscsi [new file with mode: 0755]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/extra/logout-all.sh [new file with mode: 0755]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/extra/net-interface-handler [new file with mode: 0755]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/extra/startup-checks.sh [new file with mode: 0755]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/extra/udeb/finish-install.d/10open-iscsi [new file with mode: 0755]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/extra/udeb/iscsi-start [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/extra/udev/70-iscsi-network-interface.rules [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/extra/udev/70-open-iscsi.rules [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/extra/umountiscsi.sh [new file with mode: 0755]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/gbp.conf [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/iscsid.init [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/iscsid.service [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/iscsiuio.init [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/iscsiuio.install [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/iscsiuio.manpages [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/iscsiuio.service [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/libopeniscsiusr-dev.install [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/libopeniscsiusr-dev.manpages [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/libopeniscsiusr.install [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/not-installed [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/open-iscsi-udeb.install [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/open-iscsi.default [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/open-iscsi.finalrd [new file with mode: 0755]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/open-iscsi.init [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/open-iscsi.install [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/open-iscsi.links [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/open-iscsi.manpages [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/open-iscsi.postinst [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/open-iscsi.postrm [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/open-iscsi.preinst [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/open-iscsi.prerm [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/open-iscsi.service [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/open-iscsi.templates [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/patches/lp1755858-default-iscsid_conf-to-iscsid_socket.patch [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/patches/multiarch-path.patch [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/patches/series [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/po/POTFILES.in [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/po/cs.po [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/po/da.po [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/po/de.po [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/po/es.po [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/po/fr.po [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/po/it.po [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/po/nl.po [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/po/pt.po [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/po/pt_BR.po [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/po/ru.po [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/po/templates.pot [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/rules [new file with mode: 0755]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/source/format [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/tests/control [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/tests/control.nested [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/tests/find_free_ip.py [new file with mode: 0755]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/tests/install [new file with mode: 0755]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/tests/login [new file with mode: 0755]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/tests/nested [new file with mode: 0755]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/upstream/metadata [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/debian/watch [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/doc/.gitignore [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/doc/Makefile [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/doc/iscsi-gen-initiatorname.8.template [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/doc/iscsi-iname.8 [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/doc/iscsi_discovery.8 [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/doc/iscsi_fw_login.8 [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/doc/iscsiadm.8.template [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/doc/iscsid.8.template [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/doc/iscsistart.8.template [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/etc/Makefile [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/etc/iface.example [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/etc/initd/initd.debian [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/etc/initd/initd.redhat [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/etc/iscsid.conf [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/etc/systemd/.gitignore [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/etc/systemd/ibft-rule-generator [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/etc/systemd/iscsi-init.service.template [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/etc/systemd/iscsi.service.template [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/etc/systemd/iscsid.service.template [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/etc/systemd/iscsid.socket [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/etc/systemd/iscsiuio.service.template [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/etc/systemd/iscsiuio.socket [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/include/fw_context.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/include/iscsi_err.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/include/iscsi_if.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/include/iscsi_net_util.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/include/iscsi_proto.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/include/list.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/include/sysdeps.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/.gitignore [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/AUTHORS [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/ChangeLog [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/INSTALL [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/Makefile.am [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/NEWS [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/README [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/RELEASE.TXT [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/configure.ac [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/docs/iscsiuio.8 [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/iscsiuiolog [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/.gitignore [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/Makefile.am [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/README [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/apps/Makefile.am [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/apps/README [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/apps/brcm-iscsi/Makefile.am [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/apps/brcm-iscsi/Makefile.brcm-iscsi [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/apps/brcm-iscsi/brcm_iscsi.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/apps/brcm-iscsi/brcm_iscsi.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/apps/dhcpc/Makefile.am [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/apps/dhcpc/Makefile.dhcpc [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/apps/dhcpc/dhcpc.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/apps/dhcpc/dhcpc.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/apps/dhcpc/dhcpv6.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/apps/dhcpc/dhcpv6.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip-1.0-changelog.txt [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/Makefile.am [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/Makefile.include [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/clock.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/debug.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/icmpv6.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/ipv6.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/ipv6.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/ipv6_ndpc.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/ipv6_ndpc.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/ipv6_pkt.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/lc-addrlabels.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/lc-switch.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/lc.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/psock.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/psock.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/pt.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/timer.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/timer.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/uip-neighbor.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/uip-neighbor.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/uip.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/uip.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/uip_arch.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/uip_arp.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/uip_arp.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/uip_eth.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/uip_eth.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/uipopt.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/.gitignore [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/Makefile.am [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/build_date.sh [new file with mode: 0755]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/clock-arch.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/clock-arch.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/iscsid_ipc.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/iscsid_ipc.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/libs/Makefile.am [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/libs/bnx2.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/libs/bnx2.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/libs/bnx2x.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/libs/bnx2x.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/libs/cnic.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/libs/cnic.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/libs/qedi.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/libs/qedi.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/logger.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/logger.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/main.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/nic.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/nic.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/nic_id.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/nic_id.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/nic_nl.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/nic_nl.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/nic_utils.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/nic_utils.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/nic_vlan.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/nic_vlan.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/options.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/packet.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/packet.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/ping.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/ping.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/uip-conf.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/Makefile [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/TODO [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/context.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/context.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/default.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/default.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/docs/kernel-doc [new file with mode: 0755]
pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/docs/libopeniscsiusr.h.3 [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/docs/list-man-pages.sh [new file with mode: 0755]
pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/idbm.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/idbm.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/idbm_fields.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/iface.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/iface.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/libopeniscsiusr.pc.in [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/libopeniscsiusr/libopeniscsiusr.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/libopeniscsiusr/libopeniscsiusr_common.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/libopeniscsiusr/libopeniscsiusr_iface.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/libopeniscsiusr/libopeniscsiusr_node.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/libopeniscsiusr/libopeniscsiusr_session.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/misc.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/misc.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/node.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/node.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/rfc.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/session.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/sysfs.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/sysfs.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/tests/runtest.sh [new file with mode: 0755]
pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/tests/test_context.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/tests/test_iface.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/tests/test_node.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/tests/test_session.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/meson_options.txt [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/sysdeps/Makefile [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/sysdeps/sysdeps.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/sysfs-documentation [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/test/.gitignore [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/test/README [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/test/TODO [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/test/harness/.gitignore [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/test/harness/__init__.py [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/test/harness/iscsi.py [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/test/harness/tests.py [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/test/harness/util.py [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/test/regression.dat [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/test/regression.sh [new file with mode: 0755]
pkgs/open-iscsi/open-iscsi-2.1.8/test/test-open-iscsi.py [new file with mode: 0755]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/.gitignore [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/Makefile [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/actor.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/actor.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/auth.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/auth.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/be2iscsi.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/be2iscsi.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/config.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/cxgbi.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/cxgbi.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/discovery.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/discovery.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/discoveryd.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/discoveryd.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/ethtool-copy.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/event_poll.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/event_poll.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/flashnode.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/flashnode.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/fwparam_ibft/Makefile [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/fwparam_ibft/README [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/fwparam_ibft/fw_entry.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/fwparam_ibft/fwparam.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/fwparam_ibft/fwparam_ppc.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/fwparam_ibft/fwparam_sysfs.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/fwparam_ibft/iscsi_obp.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/fwparam_ibft/prom_lex.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/fwparam_ibft/prom_lex.l [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/fwparam_ibft/prom_parse.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/fwparam_ibft/prom_parse.tab.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/fwparam_ibft/prom_parse.tab.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/fwparam_ibft/prom_parse.y [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/host.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/host.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/idbm.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/idbm.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/idbm_fields.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/iface.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/iface.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/initiator.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/initiator.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/initiator_common.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/io.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/iscsi_err.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/iscsi_ipc.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/iscsi_net_util.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/iscsi_netlink.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/iscsi_settings.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/iscsi_sysfs.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/iscsi_sysfs.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/iscsi_timer.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/iscsi_timer.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/iscsi_util.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/iscsi_util.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/iscsiadm.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/iscsid.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/iscsid.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/iscsid_req.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/iscsid_req.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/iscsistart.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/iser.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/iser.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/kern_err_table.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/kern_err_table.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/local_strings.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/local_strings.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/log.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/log.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/login.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/mgmt_ipc.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/mgmt_ipc.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/mntcheck.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/netlink.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/scsi.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/scsi.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/session_info.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/session_info.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/session_mgmt.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/session_mgmt.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/sysfs.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/sysfs.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/transport.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/transport.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/types.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/uip_mgmt_ipc.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/uip_mgmt_ipc.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/usr/version.h [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/utils/.gitignore [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/utils/50-iscsi-firmware-login.rules.template [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/utils/Makefile [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/utils/iscsi-gen-initiatorname.sh.template [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/utils/iscsi-iname.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/utils/iscsi_discovery.sh [new file with mode: 0755]
pkgs/open-iscsi/open-iscsi-2.1.8/utils/iscsi_fw_login.sh.template [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/utils/iscsi_offload.sh [new file with mode: 0755]
pkgs/open-iscsi/open-iscsi-2.1.8/utils/md5.c [new file with mode: 0644]
pkgs/open-iscsi/open-iscsi-2.1.8/utils/md5.h [new file with mode: 0644]

diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/.gitignore b/pkgs/open-iscsi/open-iscsi-2.1.8/.gitignore
new file mode 100644 (file)
index 0000000..287dba0
--- /dev/null
@@ -0,0 +1,21 @@
+*.o
+cscope.files
+cscope.out
+cscope.in.out
+cscope.po.out
+GPATH
+GRTAGS
+GTAGS
+TAGS
+tags
+*.swp
+*.so
+*.so.*
+libopeniscsiusr/docs/man/
+# ^ This folder is used for kernel-doc generated manpages.
+libopeniscsiusr/tests/test_context
+libopeniscsiusr/tests/test_session
+libopeniscsiusr/tests/test_iface
+libopeniscsiusr/tests/test_node
+# used for testing
+.setup
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/.travis.yml b/pkgs/open-iscsi/open-iscsi-2.1.8/.travis.yml
new file mode 100644 (file)
index 0000000..f11db8b
--- /dev/null
@@ -0,0 +1,33 @@
+language: c
+compiler: gcc
+os: linux
+dist: bionic
+
+env:
+  global:
+  # This is an excrypted setting of COVERITY_SCAN_TOKEN=<token>
+  # Travis-CI has the private key to decrypt this and set the environment
+  # variable with the token needed for Coverity API access
+  - secure: kUIw3pil4akjNycH+R2mq8oUszQrt/TCwkQb20oBRXoqsRzYLF6I9VT5wdAERjPsD7BDSiWLxLnisYrdRAs/tQ9h3xvnOJQAX8wKvVF/B883kOwOdI17DkY/dKdzWT+LbojjaXCHZf2yaKVAjibRPO2E8J9zsvpuDLDlon7zD123Amnb/XrSVJH4jefscs1OXFVtaMIKNs7AQPoPK7V9oMZoIbBF5NhYSPpytlf5/VL6ePQlXdd4xAiQR+dg5PvEbMquJh4GvcTo5DzOAJN8L9nGvlGlH5YKxHo7tkOpKFRnCATyenbpVaUBTb/TzA9OsVmxfSr/WrzLLXQxCwfOG6ktZp+1+ANRuL5wLCtDJLooGCw4Wxsicgw69snBoFPWoPW8w4osNQAaGINZnPKM2WSFxq2DBrqHrccGk1lze7upNHikBrwSTgv+SklmZUfcDQjWYxC2owH21BHhVTV6hgNShwS5q9gwWtSWAHc4f34Qvn1gjdV2/791Skk/t4GgTSmt0j0ZVcfsQJaZBvDwkot1yDJ0u/3av+ElMAmCb/9wG3dSqUXv9/V6mAutNb243igIZko6Vmpcosp2bJKXyeVbRkgbMoIfH2VQf9n1sbb01+V9lZsk9usIZZYRcW9Bz6d2H+ooDrM/ha1kQjVqMDP2EyCdBKmQjr8iAi9E4yQ=
+
+addons:
+  apt:
+    update: true
+    packages:
+    - libsystemd-dev
+    - libkmod-dev
+    - libmount-dev
+    - libisns-dev
+    - openssl
+    - flex
+    - bison
+  coverity_scan:
+    project:
+      name: open-iscsi/open-iscsi
+    notification_email: cleech@redhat.com
+    build_command: make
+    branch_pattern: coverity_scan
+
+before_install: echo -n | openssl s_client -connect scan.coverity.com:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' | sudo tee -a /etc/ssl/certs/ca-
+
+script: if [ "${COVERITY_SCAN_BRANCH}" != 1 ]; then make; fi
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/COPYING b/pkgs/open-iscsi/open-iscsi-2.1.8/COPYING
new file mode 100644 (file)
index 0000000..d159169
--- /dev/null
@@ -0,0 +1,339 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    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.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/Changelog b/pkgs/open-iscsi/open-iscsi-2.1.8/Changelog
new file mode 100644 (file)
index 0000000..a225ee9
--- /dev/null
@@ -0,0 +1,1082 @@
+-> open-iscsi-2.1.7 - open-iscsi-2.1.8
+
+Chris Hofstaedtler (1):
+      make: avoid hard-coding path to sed (#357)
+
+Christian Hesse (1):
+      etc: install system unit with without executable bit (#354)
+
+Eric Mackay (2):
+      Add ability for MGMT IPC to check UID only
+      Use config for iscsistart and iscsiadm fw login
+
+Khem Raj (1):
+      iscsiuio: Use pthread_t for INVALID_THREAD (#363)
+
+Lee Duncan (5):
+      Add a 'distclean' Makefile top-level target
+      Cleanup fwparam makefile (#360)
+      Small bug fixes (#364)
+      Use meson as the main build system (#365)
+      libopeniscsiusr: cleanup recent reallocarray->realloc change (#369)
+
+Max Cheng (1):
+      Added examples in man file for iscsiadm session commands.
+
+Mike Christie (2):
+      iscsid: fix logout pdu send failure handling
+      Update README's error handler/timeout section
+
+Sam James (1):
+      iscsiuio: fix LDADD
+
+TIAN Yuanhao (1):
+      libopeniscsiusr: use realloc instead of reallocarray (#368)
+
+Wenchao Hao (1):
+      iscsiadm: enable specify iface name-value parameters when creating iface
+
+shugaley (1):
+      Fix a possible passing null pointer in usr/iface.c (#356)
+
+
+-> open-iscsi-2.1.6 - open-iscsi-2.1.7
+
+Lee Duncan (48):
+      Remove HEREIS usage from iscsi-gen-initiatorname
+      Fix iscsi-init.service start time
+      test: Rename README to README.orig
+      test: Add new README, update old README and TODO
+      test: Fix bug/spelling error, cleanup messages
+      test: Fix mispelling of MaxBurst
+      test: fix error with verifying mkfs command
+      test: remove the ".setup" file, used for development
+      test: Cleanup README and TODO
+      test: Track time spent calling subprocesses
+      test: Add suggested test setup info to README
+      test: Add missing verbose print, and track more time values
+      test: Track time spent in sleep() more easily/accurately
+      test: fix message mispelling of "umount"
+      test: add item to TODO list
+      test: further improve test suite time display
+      Remove SUSE init.d startup files
+      Cleanup iscsiadm man page
+      Allow name/value args for firmware logins.
+      Update iscsiadm.8 for firmware name/value pairs
+      General Makefile/README cleanup
+      Clean up Makefile build system.
+      Clean up the usage info for iscsid
+      Remove no-longer-used Makefile target for subdir
+      Make DB and ISCSIHOME directories configurable.
+      Build: Cleanup fwparam_ibft and sysdeps subdirs.
+      Add a README for fwparam_ibft subdirectory.
+      Build: cleanup usr Makefile: remove obj files on "clean"
+      Remove unused fwparam_ibft.[ch] files in fwparam_ibft.
+      Build: upate "depend" target to include sysdeps
+      Fix gcc issues with unused params in fwparam
+      Use DESTDIR correctly for HOMEDIR and DBROOT
+      Be smarter about creating iscsiuio.8 man page
+      Build: remove unused Makefile HOMEDIR creation
+      Build: use upper- vs lower-case variable names correctly
+      Build: libopeniscsiusr install should install docs
+      Remove debug messages from libopeniscsiusr/Makefile
+      Build: cleanup libopeniscsiusr/Makefile
+      Build: add libsystemd CFLAGS for building objects
+      Build: remove redundant definition in utils Makefile
+      Build: add RULESDIR to top-level Makefile
+      Create an systemd iBFT rule generator
+      Build: install systemd generator file with svc files
+      Use kernel initiatorname when setting local iname
+      utils: remove errant spaces in script
+      Check for root in iscsi-gen-initiatorname
+      Make fwparam_ibft build more reliable.
+      Fix ibft-rule-generator shell error
+
+Sam James (5):
+      iscsiuio: don't clobber LDFLAGS in configure.ac
+      iscsiuio: respect LDFLAGS fully
+      Makefiles: respect $(CC) fully (don't hardcode GCC); use $(RM)
+      Makefiles: don't hardcode sed, pkg-config
+      libopeniscsiusr: fix version in installed pkgconfig (.pc) file
+
+Wenchao Hao (5):
+      Add conn_xxx() macros to print connection info in more details
+      Make session and connect log readable and helpful to locate problem
+      mgmt: print connection info when write qtask response failed
+      initiator: return ENOMEM if failed to get ev_context in iscsi_send_logout()
+      initiator:print failure reason of iscsi_send_logout() if failed
+
+ryancaicse (1):
+      Fix a missing-unlocking bug
+
+scaleoutSean (1):
+      Fix minor error string typos
+
+
+-> open-iscsi-2.1.5 - open-iscsi-2.1.6
+
+Chris Leech (1):
+      libopeniscsiusr: extend sysfs ignore_error to include EINVAL
+
+Lee Duncan (15):
+      Fix compiler error introduced with recent IPv6 commit.
+      Remove dependences from iscsi-init.service
+      Use "sbindir" for path in systemd service files
+      Updated README a bit
+      Finish ability to have binary location configurable.
+      Fix iscsi-init so that it runs when root writable
+      remove redundant params in Makefile
+      Fixing last parts of sbindir configuration
+      Cosmetic cleanup on recent addition
+      Update the iscsi-gen-initiatorname script: harden and generalize
+      change iscsi-gen-initiatorname option -b => -p
+      Add man page for the iscsi-gen-initiatorname script.
+      Install new man page for iscsi-gen-initiatorname
+      Fix issues discovered by gcc12
+      Fix more issues discovered by gcc12
+
+Mike Christie (4):
+      iscsi sysfs: check state before onlining devs
+      iscsistart: fix login timeout handling
+      iscsid: use infinite timeout if passed in
+      iscsid: add error code for req timeouts
+
+Samy Mahmoudi (1):
+      Improve 'iscsid.conf'
+
+Wenchao Hao (8):
+      iscsiadm: Call log_init() first to fix a segmentation fault
+      iscsi_err: Add iscsid request timed out error messages
+      Fix wrong install_systemd destination path
+      actor: add name to struct actor and init it with function name
+      actor: print thread name in log
+      actor: enhanced: print error log when init a initilized thread
+      initiator_common: make set operational parameter log easy to read
+      iscsid: Check session id before start sync a thread
+
+
+open-iscsi-2.1.4 - open-iscsi-2.1.5
+
+Chris Leech (1):
+      iscsistart: fix null pointer deref before exit
+
+Lee Duncan (8):
+      Add iscsiadm "no wait" option for firmware login.
+      Set default 'startup' to 'onboot' for FW nodes
+      Support the "qede" CNA-card driver.
+      Handle qedi correctly in NPAR mode
+      Change iscsi IP type from defines to enum.
+      Update iface.example for ipv6
+      Update iscsiadm man page
+      Handle IPv6 interfaces correctly.
+
+Manish Rangankar (1):
+      bnx2x.c: Re-initialize bp->version with baseline version.
+
+Mike Christie (1):
+      iscsid: set PR_SET_IO_FLUSHER
+
+gulams (3):
+      Log error message when auth debug status is set
+      Check ISCSI_ERR_ISCSID_NOTCONN in iscsistart login
+      Handle recv() returning 0 in iscsid_response()
+
+
+open-iscsi-2.1.3 - open-iscsi-2.1.4
+
+Abhinav Rajagopalan (1):
+      Fix typo in util.py
+
+Chris Leech (3):
+      libopeniscsiusr: fix error messages
+      libopeniscsiusr: skip over removed sessions
+      libopeniscsiusr: dont error loudly if a session isn't found when working through iscsi_sessions_get()
+
+Fabian Möller (1):
+      iscsid: Add NO_SYSTEMD to CFLAGS
+
+Helmut Grohne (1):
+      Avoid hardcoding pkg-config to fix cross build
+
+John Schaeffer (1):
+      Add etc/systemd/iscsi-init.service to SYSTEMDFILES Makefile variable
+
+Lee Duncan (4):
+      iscsid: Do not allow conflicting pid-file options
+      Fix iscsiadm segfault when exiting
+      Fix iscsistart login issue when target is delayed.
+      Enable iscsi.service asynchronous logins, cleanup services
+
+Matwey V. Kornilov (1):
+      Wants=network-online.target in iscsi.service
+
+Patrick Lawrence (1):
+      Change mkdir permissions to 0770, adjust usmask
+
+Wenchao Hao (4):
+      idbm: Fix memory leak and NULL pointer dereference in idbm_rec_update_param()
+      libopeniscsiusr: Fix memory leak in iscsi_nodes_get()
+      libopeniscsiusr: Fix memory leak in iscsi_sessions_get()
+      iscsiadm: Fix memory leak in iscsiadm
+
+---------------------------------------------------------------------------
+
+open-iscsi-2.1.2 - open-iscsi-2.1.3
+
+Chris Leech (4):
+      iscsiadm buffer overflow regression when discovering many targets at once
+      check for header length underflow during checksum calculation
+      check for u8 overflow when processing TCP options
+      check for TCP urgent pointer past end of frame
+
+Gulam Mohamed (1):
+      iscsid: Poll timeout value to 1 minute for iscsid
+
+Khem Raj (1):
+      libopeniscsiusr: Compare with max int instead of max long
+
+Lee Duncan (4):
+      Add ability to attempt target logins asynchronously
+      Implement login "no_wait" for iscsiadm NODE mode
+      Updated iscsiadm man page.
+      iscsiadm: fix host stats mode coredump
+
+Wenchao Hao (15):
+      Fix memory leak in sysfs_get_str
+      iscsiadm: Optimize the the verification of mode paramters
+      Update .gitignore for cscope and gtags data base
+      iscsi_sysfs: Fix NULL pointer deference in iscsi_sysfs_read_iface
+      iscsi-iname: Verify open() return value before calling read()
+      iscsiuio: Fix invalid parameter when call fstat()
+      open-iscsi: Fix invalid pointer deference in find_initiator()
+      open-iscsi: Fix NULL pointer dereference in mgmt_ipc_read_req()
+      iscsi_net_util: Fix NULL pointer dereference in find_vlan_dev()
+      open-iscsi: Clean user_param list when process exit
+      fwparam_ppc: Fix NULL pointer dereference in find_devtree()
+      sysfs: Verify parameter of sysfs_device_get()
+      fwparam_ppc: Fix illegal memory access in fwparam_ppc.c
+      iscsiuio: Remove unused macro IFNAMSIZ defined in iscsid_ipc.c
+      fwparam_ppc: Fix memory leak in fwparam_ppc.c
+
+Yoshifumi Kinoshita (1):
+      iscsid: fix logging level when starting and shutting down daemon
+
+gulams (1):
+      iscsid: Check Invalid Session id for stop connection
+
+sonukumar159842@gmail.com (1):
+      TODO: Update to todo list.
+
+open-iscsi-2.1.0 - open-iscsi-2.1.2
+
+Christian Glombek (1):
+      Add iscsi-init.service
+
+David Disseldorp (2):
+      use openssl for random data generation
+      drop unused get_random_bytes()
+
+Lee Duncan (10):
+      Fix iscsi.service so it handles restarts better
+      Fix issue where "iscsi-iname -p" core dumps.
+      Add Wants=remote-fs-pre.target for sequencing.
+      Change include of <sys/poll.h> to <poll.h>
+      Fix type mismatch under musl.
+      More changes for musl.
+      Ignore iface.example in iface match checks
+      Fix issue with zero-length arrays at end of struct
+      Fix a compiler complaint about writing one byte
+      Fix compiler complaint about string copy in iscsiuio
+
+Luis.wu (1):
+      Update iscsi-iname.c
+
+Rafael David Tinoco (1):
+      Misspelled socket name might cause confusion to inexperienced user.
+
+Wu Bo (2):
+      iscsi-iname: fix iscsi-iname -p access NULL pointer without given IQN prefix
+      log:modify iSCSI shared memory permissions for logs
+
+fredvx (1):
+      Fix SIGPIPE loop in signal handler
+
+gulams (1):
+      Proper disconnect of TCP connection
+
+wubo009 (3):
+      iscsi: Add break to while loop
+      iscsi: fix fd leak
+      iscsi/libopeniscsiusr:add libopeniscsiuser_node.h to HEADERS
+
+
+open-iscsi-2.1.0 - open-iscsi-2.1.1
+
+# output from "git shortlog --no-merges 2.1.0..HEAD"
+
+Chris Leech (2):
+      configuration support for CHAP algorithms
+      Revert "Out-of-bounds read: Overrunning array of 8 2-byte elements"
+
+Kiyotaka Nakamura (1):
+      Avoid logout of iscsi boot session
+
+Lee Duncan (13):
+      Fixed Changelog message, first line
+      Enabled compiler checking options, fixed issues.
+      Updates to support gcc -fno-common option.
+      Fix 586 compiler issues.
+      Beginning to get python tests set up.
+      First 32 tests working?
+      64 tests now working and passing
+      Update TODO list
+      Add in "-V" for version info
+      Test code rearranged to make discovery work.
+      more things to do
+      Allow sub-tests to be specified.
+      Fix memory leaks in libopeniscsiusr/idbm.c
+
+Patrick McCarty (1):
+      Fix bug with libopeniscsiusr.pc
+
+l00464806 (1):
+      Check whether socket is opened successfully in find_vlan_dev func
+
+
+open-iscsi-2.0.878 - open-iscsi-2.1.0
+
+# output from "git shortlog --no-merges 2.0.878..HEAD"
+
+Chris Leech (29):
+      CHAP SHA-1, SHA-256, SHA3-256 via OpenSSL's libcrypto
+      setup Travis-CI builds and Coverity scans
+      fix Coverity scan
+      Resource leak: returning without freeing netdev
+      Out-of-bounds-write: Overrunning array link_target
+      Resource leak: Variable rec going out of scope leaks the storage it points to
+      Out-of-bounds write: Overrunning array link_target
+      Buffer not null terminated: Calling strncpy with a maximum size argument on destination array might leave the destination string unterminated
+      Out-of-bounds access: Overrunning array value_list
+      Resource leak: Variable startup_cmd going out of scope leaks the storage it point to.
+      Buffer not null terminated: Calling strncpy with a maximum size argument on destination array
+      Uninitialized scalar variable
+      Uninitialized pointer read: Using uninitialized value ifaces.next
+      Uninitialized scalar variable: Using uninitialized value number when calling acl_text_to_number
+      Resource leak: Handle variable sockfd going out of scope leaks the handle.
+      Resource leak: Variable chap_info going out of scope leaks the storage it points to.
+      Resource leak: Variable matched_ses going out of scope leaks the storage it points to.
+      Resource leak: Handle variable fd going out of scope leaks the handle.
+      Resource leak: Handle variable fd going out of scope leaks the handle.
+      Out-of-bounds read: Overrunning array of 4 bytes at byte offset 7 by dereferencing pointer
+      iscsi-iname: change default IQN prefix
+      iscsi-iname: verify prefix length is at most 210 characters
+      iscsi-iname remove unneeded temp buffer
+      iscsistart -b probably never worked with PPC OF parsing?
+      fwparam_pcc mulitple resource leaks
+      Resource leak: Handle variable fd going out of scope leaks the handle.
+      Out-of-bounds read: Overrunning array of 8 2-byte elements
+      Resource leak: Variable raw going out of scope leaks the storage it points to.
+      Uninitialized scalar value rc
+
+Lee Duncan (2):
+      Initialize timeout for printing specific session info.
+      Fix version strings in ChangeLog
+
+open-iscsi-2.0.877 - open-iscsi-2.0.878
+
+# output from "git shortlog --no-merges 2.0.877..HEAD"
+
+Daniel Schaefer (1):
+      Add target to install systemd units
+
+Lee Duncan (18):
+      iscsistart is not installed
+      Fix i586 build issues with string length overflow.
+      Use pkg-config in Makefiles for newer libraries.
+      Updated iscsiadm man page: add "onboot" handling.
+      Fix output for iscsiadm node/iface print level P1
+      When displaying interfaces, skip "iface.example"
+      Fix node print return value when no nodes.
+      Fix printing of node database again.
+      Fix output of node printing for multiple paths.
+      Stop using /var directory for PIDfile and locks
+      Improve daemon synchronization, fix err msgs
+      Fix pipe notification code
+      Add systemd support for iscsiuio
+      Make iscsid systemd usage optional
+      Fix possible discovery hang when timing out
+      Handle systemd disablement correctly in iscsiuio
+      The iscsi login/logout service requires iscsid.
+      Remove redundant Requires= from iscsi.service
+
+Manish Rangankar (3):
+      iscsiuio: Do not flush tx queue on each uio interrupt.
+      qedi: Set buf_size in case of ICMP and ARP packet.
+      qedi: Use uio BD index instead on buffer index.
+
+Nilesh Javali (3):
+      iscsiuio: v0.7.8.5
+      iscsiuio: allow processing of iscsid requests in DHCP failure condition
+      iscsiuio: update version to 0.7.8.6
+
+Xiubo Li (1):
+      rec update: disable the idbm_lock in read/write when updating the rec
+
+fredvx (1):
+      Add Restart=on-failure option to iscsid.service
+
+igo95862 (2):
+      Make iscsid.service a requirement.
+      Fixed iscsi.service considering every signal and exit code as successful. Now only code 21 (no objects found to execute on) and normal exit conditions are valid.
+
+open-iscsi-2.0.876 - open-iscsi-2.0.877
+
+Antoine de Maleprade (1):
+      iscsid: fix logging level when starting daemon
+
+Cathy Zhou (1):
+      Reduce delays to improve iscsi boot performance
+
+Chris Leech (16):
+      libopeniscsiusr: fixes err on prefix_len
+      vlan setting sync across ipv4/ipv6 for be2iscsi
+      iscsid logging blank messages at level EMERG
+      iscsistart: prevent unix socket cross-talk
+      libopeniscsiusr: hosts can have multiple ifaces
+      libopeniscsiusr: clear errno before calling strtoll
+      libopeniscsiusr: setup ipv6 records based on iface name
+      libopeniscsiusr: use asprintf and remove PATH_MAX stack buffers
+      Merge pull request #110 from cleech/libopeniscsiusr_fixes
+      Merge pull request #111 from cleech/for_upstream
+      Merge pull request #106 from phmccarty/lib-symlinks
+      enable MaxOutstandingR2T negotiation
+      Merge pull request #114 from njavali/iscsiuio-bug-fixes
+      Merge pull request #115 from cleech/for_upstream
+      Merge pull request #120 from maxnet/va
+      Merge pull request #122 from njavali/iscsiuio-bug-fixes
+
+Christian Ehrhardt (2):
+      iscsiuio: avoid loosing bad rc in nic_nl_open
+      iscsiuio: fail on nic_nl_open failing
+
+Floris Bos (1):
+      context.h: add missing stdarg.h include
+
+Gris Ge (8):
+      libopeniscsiusr: Fix iscsi_sessions_free() on 0 se_count.
+      libopeniscsiusr: Add full iscsi interface support.
+      Makefile: Trivial change on aligning output.
+      libopeniscsiusr: Fix incorrect debug message for iface query.
+      libopeniscsiusr: Add node query support
+      libopeniscsiusr: Fix iscsi_iface_get() on default interfaces.
+      iscsiadm: Use libopeniscsiusr in `iscsiadm -m iface -P1`
+      libopeniscsiusr: Fix compile error on GCC 8.
+
+Khem Raj (6):
+      libopeniscsiusr: Include limit.h for PATH_MAX
+      libopeniscsiusr: Add CFLAGS to linker cmdline
+      qedi.c: Removed unused linux/ethtool.h
+      idbm.c: Include fcnl.h for O_RDWR and O_CREAT definitions
+      bnx2x.c: Reorder the includes to avoid duplicate defines with musl
+      fwparam_ppc.c: Do not use __compar_fn_t
+
+Lee Duncan (55):
+      Merge pull request #91 from njavali/iscsiuio-bug-fixes
+      Merge pull request #92 from az0uz/master
+      Use correct size when copying nic name.
+      Do not overload global sysfs_path locally.
+      libopeniscsiusr: ensure sysfs pathname doesn't overflow.
+      Ensure sysfs pathname doesn't overflow.
+      Merge pull request #89 from kraj/kraj/musl-fixes
+      Merge pull request #94 from gonzoleeman/gcc-8-fixes
+      Merge branch 'master' into api
+      Merge pull request #93 from cathay4t/api
+      Keep iscsi_if in sync with kernel version.
+      Add a TODO item on iscsi_if.h.
+      Merge pull request #98 from gonzoleeman/update-iscsi_if-to-latest
+      Add error message for new ISCSI_ERR_NOP_TIMEDOUT
+      Merge pull request #99 from gonzoleeman/handle-new-kernel-error-code
+      Allow a host_id value of zero.
+      Merge pull request #100 from gonzoleeman/libopeniscsiusr-allow-zero-host_id
+      Merge pull request #101 from gonzoleeman/fix-qedi-iface-name
+      Fix iscsiuio segfault when shutting down.
+      Remove unused file fwparam_ibft_sysfs.c.
+      Merge pull request #96 from cathay4t/api
+      Merge pull request #103 from cathy-zhou/perf_fix
+      Plugging a memory leak from discovery.
+      Merge pull request #123 from gonzoleeman/fix-discovery-leak
+      Allow reading sysfs "port" to fail gracefully.
+      Fix incorrect sysfs logic for port and ip address.
+      Fix reading of sysfs signed integers when negative.
+      Create a new error for "target not connected".
+      Fix bug in error message when reading sysfs numbers.
+      Handle ENOTCONN error separately when reading sysfs values.
+      Limit session relogin attempts using config value.
+      Merge pull request #127 from smoser/fix/iscsid-pidfile-write
+      Merge pull request #129 from cpaelzer/cleanup-nic_nl_open-usage
+      Merge pull request #131 from gonzoleeman/fix-reconnect-forever
+      Removed unused value 'one'.
+      Include stdio.h for use of snprintf().
+      Fix qsort() comparator function call.
+      Merge pull request #132 from gonzoleeman/small-cleanups
+      Do not allow multiple sessions when nr_sessions=1
+      Merge pull request #136 from gonzoleeman/no-parallel-sessions
+      When reopen_max=0 retry reopening forever.
+      Merge pull request #137 from gonzoleeman/add-no-timeout-relogin-option
+      Use libkmod instead of fork/exec of modprobe.
+      Merge pull request #138 from gonzoleeman/remove-fork-exec-for-modprobe
+      Update GPLv2 License information.
+      Merge pull request #139 from gonzoleeman/fix-fsf-address
+      Make reconnect to session on startup forever default.
+      Merge pull request #141 from gonzoleeman/master
+      Restore space in node-mode level 0 output
+      Merge pull request #142 from gonzoleeman/fix-mode-node-level-0-print
+      Merge pull request #4 from open-iscsi/master
+      Added service file for iscsi logins
+      Use sd_notify() to tell systemd when iscsid is ready.
+      Update systemd unit files for iscsid
+      Merge pull request #143 from gonzoleeman/use-sd_notify-for-systemd
+
+Manish Rangankar (3):
+      iscsiuio: Add inter-host mutex while doing xmit
+      iscsid: Update boot gateway information during sync_session.
+      iscsiuio: Release xmit_mutex in error code path.
+
+Nilesh Javali (4):
+      iscsiuio: allow ARP for non-matching src and dst addresses
+      iscsiuio: v0.7.8.4
+      iscsiadm: get transport_name correctly for offload iface
+      iscsiuio: limit retries of performing dhcpv6 before declaring dhcp failure
+
+Patrick McCarty (1):
+      Fix installation of libopeniscsiusr symlinks
+
+Scott Moser (2):
+      Close file handles when writing pid files.
+      Better error message and failure if netlink socket fails.
+
+
+open-iscsi-2.0.875 - open-iscsi-2.0.876
+
+Chris Leech (2):
+      delete old kernel code
+      delete unused BSD stub code
+
+Gris Ge (6):
+      Remove white spaces.
+      Fix memory leak of session_info_print_tree() in usr/session_info.c.
+      Introducing iSCSI userspace library.
+      libopeniscsiusr: Add iSCSI session support.
+      libopeniscsiusr: Add basic iface support into iscsi session.
+      libopeniscsiusr: Use libopeniscsiusr in iscsiadm
+
+Khazhismel Kumykov (1):
+      iscsi_if.h: use attribute instead of '__packed'
+
+Lee Duncan (37):
+      Fix duplicate define of __bitwise
+      Fix compiler warning: possible string truncation
+      Replace deprecated _SVID_SOURCE with _DEFAULT_SOURCE
+      Rename local strings.[ch] to local_strings.[ch]
+      Fix compiler warnings about string overflows in prom_parse
+      Ignore library file for iscsiuio/src
+      Fix undefined call to writev(): include <sys/uio.h>
+      Remove unused variables. No functional change.
+      Include <sys/sysmacros.h> to properly define minor()
+      Declare inline best_match_bufcmp() as static.
+      Merge pull request #69 from gonzoleeman/new-compiler-fixes
+      Merge pull request #3 from open-iscsi/master
+      Check for root peer user for iscsiuio IPC
+      iscsiuio should ignore bogus iscsid broadcast packets
+      Ensure all fields in iscsiuio IPC response are set
+      Do not double-close IPC file stream to iscsid
+      Ensure strings from peer are copied correctly.
+      Skip useless strcopy, and validate CIDR length
+      Check iscsiuio ping data length for validity
+      tell git to ignore the iscsiuio binary
+      Merge pull request #72 from gonzoleeman/iscsiuio-fixes
+      Automate logging into iSCSI FW targets.
+      Ignore common build output files
+      Merge pull request #78 from gonzoleeman/updates/ignore-standard-build-files
+      Merge pull request #79 from gonzoleeman/updates/add-iscsi_fw_login
+      Merge pull request #80 from cleech/master
+      Cleanup iscsiuio master Makefile template.
+      Update iscsid.conf attribute iscsid.startup.
+      Merge pull request #81 from gonzoleeman/updates/iscsid.conf-changes-v2
+      Merge pull request #82 from gonzoleeman/updates/iscsiuio-Makefile.am-updates
+      Add in tracking IP prefix length, in addition to mask.
+      Add some scripts and manpages to the top Makefile.
+      Merge pull request #83 from gonzoleeman/fixes/update-top-level-makefile
+      Merge pull request #84 from gonzoleeman/fixes/add_ip_prefix
+      Discovery via non-tcp transport needs "ipc" value
+      Merge pull request #85 from gonzoleeman/fixes/ipc-should-not-be-null
+      Do not set LDFLAGS directly in usr/Makefile
+      remove kernel subdir from clean Makefile target
+
+
+open-iscsi-2.0.874 - open-iscsi-2.0.875
+
+Andrew Patterson (3):
+      iscsiuio must be present to use hardware offload for bnx2{,x}
+      iscsistart: move offload discovery/setup to fw_get_targets()
+      iscsiuio: fix long options
+
+Chris Leech (8):
+      fix timeout setting on discoverydb commands
+      Merge pull request #41 from cleech/master
+      Merge pull request #40 from Akrog/feature/autoscan_en
+      Merge pull request #42 from m4z/uniform-headings
+      Merge pull request #43 from m4z/whitespace
+      Merge pull request #44 from m4z/typos
+      Merge pull request #45 from m4z/punctuation
+      Merge pull request #49 from Akrog/fix/autoscan_en
+
+Christopher 'm4z' Holm (7):
+      Unify README headings.
+      Cleanup README whitespace.
+      Fix a bunch of typos and a bit of wording.
+      Improve README punctuation.
+      Merge branch 'master' into punctuation
+      Unify invocation examples, option documentation, and more.
+      Add actual "iscsiadm --help" output (on openSUSE).
+
+Christopher Holm (1):
+      Merge branch 'master' into uniform-invocation-examples
+
+Edward Kigwana (2):
+      Update bnx2.c
+      Update bnx2x.c
+
+Gorka Eguileor (2):
+      Allow disabling auto LUN scans
+      Fix manual LUN scans feature
+
+Hannes Reinecke (1):
+      Use timeout when waiting for responses from iscsid
+
+Lee Duncan (17):
+      iBFT 'origin' is an enum, not a string
+      Merge pull request #32 from gonzoleeman/master
+      iscsid: treat SIGTERM like "iscsiadm -k 0"
+      Make event_loop_stop volatile for safer access
+      Merge pull request #34 from gonzoleeman/master
+      Merge pull request #1 from open-iscsi/master
+      Fix coredump when printing session info.
+      Merge pull request #52 from gonzoleeman/master
+      Merge pull request #53 from gonzoleeman/master
+      Merge pull request #54 from njavali/iscsiuio-bug-fixes
+      Merge pull request #57 from y011/patch-1
+      Merge pull request #2 from open-iscsi/master
+      Clear errno before calling strtoull.
+      Merge pull request #60 from gonzoleeman/strtoull-fix
+      Merge pull request #61 from ekigwana/master
+      Merge pull request #46 from m4z/uniform-invocation-examples
+      Merge pull request #55 from apatters/bnx2-software-ibft-support
+
+Neal Wise (1):
+      Fixed typo for spelling of 'default'
+
+Nilesh Javali (5):
+      iscsid: Changes to support the new qedi transport
+      iscsiuio: Add support for the new qedi transport
+      iscsiuio: v0.7.8.3
+      iscsiuio: fix dhcpv6 transaction-id mismatch error
+      iscsiuio: serialize xmit_mutex lock to prevent iscsiuio seg fault
+
+Nilesh Javili (1):
+      iscsid: Add qedi ping transport hook
+
+
+open-iscsi-2.0.873 - open-iscsi-2.0.874
+
+Adam Jackson (6):
+      actor: Mark actor_check static
+      actor: simplify actor_check
+      actor: s/ACTOR_TICKS/actor_jiffies/
+      actor: Remove ACTOR_TICKS_10MS()
+      actor: Unobfuscate ACTOR_MAX_LOOPS
+      actor: Simplify actor_poll a little
+
+Adheer Chandravanshi (26):
+      Manpage changes for flashnode submode support for host mode.
+      README changes for flashnode submode support for host mode.
+      iscsiadm: Check for mode is not required when creating params list
+      iscsiadm: Correctly check for invalid hostno and flashnode index
+      flashnode: Add support to set ISCSI_FLASHNODE_CHAP_OUT_IDX param
+      iscsiadm: Use '-x' option instead of '-v' to specify chap_tbl_idx
+      iscsiadm: Man page changes to use -x option for chap_tbl_idx
+      README changes to use long option --index instead of --flashnode_idx
+      iscsiadm: Add support to set CHAP entry using host chap mode
+      iscsi tools: Correctly get username_in and password_in flashnode params
+      README changes for adding support to set CHAP entry
+      iscsi tools: Setup iface conf file with all iface attrs exported in sysfs
+      iscsi_if.h: Additional parameters for network param settings
+      iscsi tools: iface params should be updated for node_rec as well.
+      iscsi tools: Let default type of iface be ipv4
+      iscsi tools: Show iface params based on iface type
+      iscsi tools: Fix the iscsiadm help options for host mode
+      Man page correction for host mode options of iscsiadm
+      iscsiadm: Fix the compile time warning
+      iscsiuio: Correct the handling of Multi Function mode
+      iscsiuio: Add QLogic Vendor ID to support newer NX2 HBAs
+      iscsid: Changes to support ping through iscsiuio
+      iscsiuio: Add ping support through iscsiuio
+      iscsiadm: let ping be tried after iface config is initialized
+      iscsiuio: Wait for iface to be ready before issuing the ping
+      iscsiuio: Get the library to use based on uio sysfs name
+
+Andy Grover (20):
+      Update README for removal of DBM requirement
+      Fix build warnings for unused variables
+      Fix warning about possibly-uninitialized variable
+      Fix bad sizeof in memset
+      Fix missing header
+      iscsiuio: Fix warning about non-matching types
+      iscsiuio: Fix strict-aliasing warning with struct mac_address
+      iscsiuio: Resolve strict aliasing issue in iscsiuio/src/unix/nic.c
+      iscsiuio: Fix aliasing issue with IPV6_IS_ADDR_UNSPECIFIED
+      iscsiuio: Use attribute(unused) for variables that are unused but needed
+      iscsiuio: Use attribute(unused) for *icmpv6_hdr
+      iscsiuio: Change nic_disable to return void
+      iscsiuio: Remove set but unused variables
+      iscsiuio: Check return value from nic_queue_tx_packet
+      Remove actor_init and rename actor_new to actor_init
+      Make running actors event-driven
+      Wake up to reap children
+      Fix incorrect list operation leading to out-of-order items on pend_list
+      Prevent spinning over poll() when reconnecting to an inaccessible target
+      Add some more debug logging to actor.c
+
+Anish Bhatt (1):
+      iscsiadm : make iface.ipaddress optional in iface configs for transports that don't have a hard requirement on it.
+
+Chris Leech (19):
+      iscsiadm: Fix the hostno check for stats submode of host mode
+      fix regression in iscsi_tcp iface binding
+      guard against NULL ptr during discovery from unexpected event
+      add discovery as a valid mode in iscsiadm.8
+      iscsid: fix order of setting uid/gid and drop supplementary groups
+      iscsiuio CFLAGS fixes
+      iscsiuio systemd socket activation support
+      iscsid safe session logout
+      iscsid: don't re-read config file for every session logout
+      make use of all 24 bits of ISID qualifier space
+      iscsi_tcp set SO_LINGER to abort connection for error handling
+      iscsiadm: fix parallel rescan handling of exit codes
+      iscsistart: support booting over a VLAN
+      iscsid: safe_logout fix device path canonicalization by using libmount cache
+      iscsid: make safe_logut session checks apply for flashnode session
+      remove sysfs attr_list
+      Merge pull request #25 from cleech/master
+      Merge pull request #29 from chris-se/debian-patches
+      Replace open-iscsi.org with open-iscsi.com in docs
+
+Christian Hesse (1):
+      typo in man iscsiadm(8)
+
+Christian Seiler (8):
+      buildsys: make 'make clean' idempotent
+      buildsys: respect CFLAGS and LDFLAGS from the outside
+      Remove outdated Debian packaging code.
+      Reformat man page synopsis sections
+      Build system: sort object file lists
+      iscsiuio: Make builds reproducible if SOURCE_DATE_EPOCH is set
+      Additional spelling fixes
+      iscsiuio/Makefile.am: fix typo introduced by reproducibility patch
+
+Christophe Vu-Brugier (1):
+      Fix typos in iscsiadm man page
+
+Christopher Unkel (1):
+      Fix typo in man page.
+
+Duane Northcutt (1):
+      iscsid: Fix double close of mgmt ipc fd
+
+Eddie Wai (13):
+      ISCSISTART: Bring up the corresponding network interface for iboot
+      ISCSID: Passing more net params from ibft to iface
+      ISCSID: Modified the Makefile for iscsiuio compilation
+      ISCSID: Added iscsiuio source to the open-iscsi pkg
+      ISCSIUIO: Updated iscsiuio to version 0.7.8.1b for perf optimization
+      ISCSID: Added the extraction of the session boot info
+      ISCSID: Added iface content override fix
+      ISCSIUIO: Added tx doorbell override mechanism
+      ISCSIUIO: Added fix for the iface.subnet_mask decoding for IPv6
+      ISCSIUIO: Added fix for the ARP cache flush mechanism
+      ISCSIUIO: Updated RELEASE note and version
+      ISCSIUIO: Removed the auto-generated COPYING file
+      ISCSIUIO: Fixed a pthread resc leak from excessive session recovery
+
+Frank Fegert (2):
+      Prevent iscsiuio from segfaulting due to un-lock of a not locked mutex.
+      iscsiuio: ensure unlock of mutex in case of an error.
+
+Hannes Reinecke (14):
+      iscsiuio: Remove autogenerated files from tracking
+      iscsiuio: Update automake files
+      iscsiuio: Add .gitignore files
+      Remove unused variable 'path'
+      Parse 'origin' value from iBFT
+      Added new utility script to generate initiator name
+      Added new util script to aid in CNA setup
+      Code cleanup: no functional changes
+      Represent DHCP "origin" as an enum, not a string.
+      fwparam_ibft: Check iBFT target and NIC flags
+      Allow modifications for iface.gateway and iface.subnet_mask
+      iscsiuio: Do not memcpy identical locations
+      iscsiuio: Clear memory after allocation
+      iscsiuio: fixup race condition
+
+Harish Zunjarrao (6):
+      iscsi_if.h: Remove numbers used for network parameter settings
+      iscsi tools: Use macro to set IPv4/IPv6 IP addresses
+      iscsi tools: Use single function to enable/disable network parameters
+      iscsi tools: Use single function to set integer network parameters
+      iscsi tools: Ignore network parameter if not enabled/disabled
+      iscsi tools: Additional parameters for network settings
+
+Heinrich Schuchardt (1):
+      Kernel include path
+
+Jan Vesely (2):
+      iscsid: Fix strlen parameter
+      iscsiuio: Change socket bind to use the same struct size as iscsid
+
+Jim Ramsay (1):
+      iscsi tools: Convert '-r' argument to an integer before checking if it is a path
+
+John Soni Jose (2):
+      be2iscsi: Fix MaxXmitDataLenght of the driver.
+      Fix StatSN in Open-iSCSI Stack.
+
+Kamalneet Singh (1):
+      fix typo
+
+Lalit Chandivade (3):
+      iscsi_tool: Add offload host statistics support.
+      README: Updated for host statistics.
+      iscsiadm.8: Updated man page for host statistics.
+
+Lee Duncan (13):
+      PATCH 1 of 1] correctly check return value of nice()
+      iscsiadm: return error when login fails
+      Fix discovery error return without return value
+      Add missing DESTDIR
+      isns: Add docs for deregistering discovery domains.
+      Supply strings for newly-added error numbers
+      Allow setting host params to return EAGAIN errors.
+      Remove duplicate newlines in log messages.
+      Fix iBFT target flags check.
+      Use system-wide open-isns, not internal version.
+      ARP table too small when switches involved.
+      Merge pull request #22 from frank-fegert/master
+      Merge pull request #26 from cvubrugier/master
+
+Manish Rangankar (1):
+      iscsiadm: Initialize param_count in set_host_chap_info
+
+Mark Karpeles (1):
+      fixed typo in iscsi_discovery usage()
+
+Mike Christie (22):
+      iscsid: fix iscsid segfault during qla4xxx login
+      iscsi tools: fix compile error when OFFLOAD_BOOT_SUPPORT defined
+      iscsi tools: fix get_random_bytes error handling
+      ISCSID: Added socket communication hooks for uip
+      From: Adheer Chandravanshi <adheer.chandravanshi@qlogic.com>
+      Allow firmware mode to use debug flag
+      iscsiadm: bind ifaces to portals found using isns
+      iscsid/iscsiadm: add support for emulex one connect storage
+      Make rescan run in parallel
+      iscsi tools: sync iscsi_if.h with kernel space
+      ISCSISTART: Saved ibft boot info to the session
+      iscsi tools: Bug fix on IPC address copy (version 2)
+      ISCSIUIO: Updated the configure file to reflect the new version
+      iscsiuio: fix compilation
+      iscsi tools: set non negotiated params early.
+      iscsid: Fix handling of iscsi async events.
+      iscsid: retry login for ISCSI_ERR_HOST_NOT_FOUND
+      iscsid: don't round up when modifying padding len
+      iscsi: remove local copy of open-isns
+      iscsid: make sure actor is delated before rescheduling
+      iscsid/iscsiuio: remove uio poll
+      iscsid: fix iscsi_host_set_net_params return code
+
+Ritesh Raj Sarraf (1):
+      Spelling and escaping error fixes.
+
+Salvatore Bonaccorso (1):
+      Fix small typo in iscsid.conf
+
+Tomasz Torcz (3):
+      iscsid,iscsiadm: fix abstract socket length in bind() call
+      iscsid: implement systemd-compatible socket activation
+      iscsid: add example unit files for systemd
+
+Vikas Chaudhary (3):
+      iscsi tools: Print additional session info for flashnode session
+      iscsiadm: Added document for description of iface attributes
+      iscsiuio: Rebranding iscsiuio
+
+Ville Skyttä (2):
+      man page syntax fixes
+      Spelling fixes
+
+mikechristie (3):
+      Merge pull request #11 from deepankar/master
+      Merge pull request #8 from dscunkel/master
+      Merge pull request #9 from xypron/kernel_source_path
+
+open-iscsi-2.0.872 - open-iscsi-2.0.873
+
+Ales Kozumplik (1):
+      fwparam_sysfs: fix pathname manipulation error in fwparam_sysfs_boot_info.
+
+Eddie Wai (3):
+      ISCSID: Fixed a race condition in the INVALID_HOST path
+      ISCSID: Fixed iface update for the new iface net config params
+      ISCSIADM: Included the new iface net params to the node creation
+
+Hannes Reinecke (6):
+      iscsid sends SIGTERM to PID 0
+      iscsid: Implement --no-pid-file
+      Keep startup mode in sync when specified in config file
+      Allow LOCK_DIR to be set via CFLAGS
+      Allow 'onboot' as loginall parameter
+      boot.suse: Update with latest fixes
+
+Jim Ramsay (12):
+      Add specific session information to session_rec_t
+      Add support for multiple sessions per iface to iscsid
+      Add multiple sessions per iface commandline syntax
+      Add new node.session.nr_sessions config parameter
+      Implement leading-login support
+      Fix dcb_app.c compile error with old kernels
+      Check all ifaces during discovery even if some timeout
+      iscsid: In foreground mode, treat SIGINT like SIGTERM
+      Revise bind_conn_to_iface logic
+      iscsi tools: Fix warnings reported by gcc-4.5.2
+      fwparam_ibft: Fix warnings reported by gcc-4.5.2
+      open-isns: Fix warnings reported by gcc-4.5.2
+
+Karen Xie (1):
+      open-iscsi: add transport cxgb4i
+
+Lalit Chandivade (2):
+      iscsiadm: add netconfig support
+      iscsi tools: manage qla4xxx iscsi sessions with iscsiadm
+
+Manish Rangankar (1):
+      iscsid: Fixed iscsid restart issue for offload iSCSI login
+
+Mark Rustad (7):
+      Add some consts to char * parameters that are not changed
+      Add dcb_app.h for DCB support
+      Add dcb_app.c for DCB support
+      Add initial DCB support
+      iscsid: Fix netdev check
+      Remove redundant initialization
+      iscsid: Add IEEE DCB support
+
+Mike Christie (86):
+      iscsid: remove bogus debug log msg in isns_disc_new_portals
+      isns: Fix endless loop when pollhup is returned
+      iscsi tools: fix multi pdu sendtargets discovery sequences
+      iscsi boot: fix iscsi_boot sysfs parsing
+      Use pass through interface for sendtargets (take4) Currently offload cards like bnx2i, be2iscsi, cxgb3i must use a normal eth for discovery. This patch allows us to do discovery using the iscsi class passthrough interface.
+      Add userspace/tools iscsi error code defs
+      iscsi tools: fix iscsiadm exit codes
+      iscsid: modify data drop
+      iscsi doc: document iscsiadm host argument
+      iscsid: add new auth error code
+      iscsi tools: convert discovery code to iscsi error codes
+      iscsi tools: document iface rp_filter use
+      iscsi tools: disable isns dsa code
+      iscsi tools: support hostnames in node mode
+      iscsi tools: fix discovery return code
+      iscsiadm: fix offload discovery retry
+      iscsid: fix signal handler debug msg
+      iscsiadm: fix discovery exit code
+      iscsi tools: fix dcbnl.h compile error
+      iscsid: retry initial connect
+      iscsi tools/kernel: switch make defaults
+      iscsi tools: fix comment about sysfs lookup failures
+      iscsi tools: fix netlink bug allocation
+      iscsi tools: Don't try to bind offload EPs to sockets
+      iscsi tools: fix oom_adj use
+      iscsi tools: fix bnx2i boot due to MAC mismatch
+      iscsiadm: fix discoverydb help
+      Update SUSE init script
+      iscsi tools: revert commit c440cbe7ba2464f8baadedb55b00754c36773c2c
+      Add a TODO
+      TODO: mark down Jose as working on idr
+      Update TODO
+      iscsi tools: fix iname sysfs handling
+      iscsi tools: handle compile warnings about unused variables
+      iscsiadm: print kernel iface info
+      iscsi tools: add tgt reset to session info and fix unknown values
+      iscsi tools: fix default iface binding setup
+      iscsi tools: fix iscsiadm return value on failed login
+      iscsi tools: don't build with openssl
+      iscsi tools: check NULL pointer first and add limit check in str_remove_initial
+      iscsi tools: fix README sid lookup info
+      iscsid: print out more informative error string for kernel errors
+      iscsi tools: fix netlink msg setup
+      iscsi tools: fix up vlan support
+      update todo
+      iscsiadm: fix printing of unknown host values
+      Do not run configure for open-isns on every build
+      iscsi tools: fix ipv6 ibft/firmware boot
+      iscsid: don't sync qla4xxx flash sessions
+      iscsid: kill session if already exists.
+      isns: remove rfc files.
+      iscsistart: allow any rec/iscsid.conf setting as arg
+      iscsistart: support params in offload/ibft mode
+      iscsi tools: never use hdr digest with iser
+      iscsi tools: update iscsi_if.h for host event
+      iscsi tools: added ping support
+      iscsi tools: Add support to display a host's CHAP list and delete
+      iscsi tools: fix conn state compilation warnings
+      iscsi tools: allow default to have different transort names
+      iscsiadm: print ping status string
+      iscsi tools: fix hostname with port handling
+      iscsi tools: have iscsid/iscsiadm load modules as needed
+      iscsi tools: have iscsiadm load offload modules
+      init: update red hat init script for module changes
+      iscsi tools: create def ifaces on demand
+      iscsi tools: iscsiadm modprobe support
+      iscsi tools: remove class version check
+      iscsi tools: remove unused len variable
+      iscsiadm: support multiple params in one call
+      iscsid: remove DCB support
+      iscsiadm: print port speed and link state
+      iscsi tools: check for loaded module before loading
+      iscsistart: have iscsistart use same multi param code as iscsiadm
+      iscsi tools: print and load boot transport
+      iscsiadm: load iface before checking for hostno/mac match
+      iscsistart: fix iface overriding
+      iscsiadm: make sure offload drivers are loaded in host mode
+      iscsi tools: have iscsi tools bring up offload net iface
+      iscsi tools: fix bnx2i login
+      iscsi tools: fix ipv6 handling
+      iscsistart: fix invalid param handling
+      iscsiadm: added command line option '--interval'
+      iscsi tools: fix unknown param warnings
+      iscsi tools: fix socket leak in transport probe
+      iscsi tools: remove useless NULL iface check
+      iscsi tools: use strlpy in net code
+
+Nilesh Javali (1):
+      iscsi tools: update documents for CHAP command
+
+Rahul Gupta (1):
+      iscsi tools: Displaying timeout and CHAP in iscisadm info
+
+Vikas Chaudhary (2):
+      iscsi tools: update documents for ping command
+      iscsi tools: remove un-necessary print message
+
+Wang Sheng-Hui (1):
+      usr/config.h: fix comment for struct iscsi_session_timeout_config
+
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/Makefile b/pkgs/open-iscsi/open-iscsi-2.1.8/Makefile
new file mode 100644 (file)
index 0000000..09bda07
--- /dev/null
@@ -0,0 +1,141 @@
+#
+# Makefile for the Open-iSCSI Initiator
+#
+
+# if you are packaging open-iscsi, set this variable to the location
+# that you want everything installed into.
+DESTDIR ?=
+
+# our VERSION String
+ISCSI_VERSION_STR ?= 2.1.8
+
+prefix = /usr
+exec_prefix =
+mandir = $(prefix)/share/man
+etcdir = /etc
+
+SBINDIR = $(exec_prefix)/sbin
+HOMEDIR = $(etcdir)/iscsi
+DBROOT = $(etcdir)/iscsi
+RULESDIR = $(etcdir)/udev/rules.d
+
+INSTALL = /usr/bin/install
+
+# pass these on to sub-Makefiles
+export DESTDIR prefix INSTALL SBINDIR HOMEDIR DBROOT RULESDIR ISCSI_VERSION_STR
+
+# Compatibility: parse old OPTFLAGS argument
+ifdef OPTFLAGS
+CFLAGS = $(OPTFLAGS)
+endif
+
+# Export it so configure of iscsiuio will
+# pick it up.
+ifneq (,$(CFLAGS))
+export CFLAGS
+endif
+
+# export systemd disablement if set
+ifneq ($(NO_SYSTEMD),)
+export NO_SYSTEMD
+WITHOUT_ARG = --without-systemd
+else
+WITHOUT_ARG =
+endif
+
+# Random comments:
+# using '$(MAKE)' instead of just 'make' allows make to run in parallel
+# over multiple makefile.
+
+all: user
+
+make_utils:
+       $(MAKE) $(MFLAGS) -C utils
+
+deprecation_msg:
+       @echo "***"
+       @echo "*** Warning: using 'make' is being deprecated, in favor of 'meson'"
+       @echo "***    Please see the README file for more information."
+       @echo "***"
+
+user: deprecation_msg iscsiuio/Makefile
+       $(MAKE) $(MFLAGS) -C libopeniscsiusr
+       $(MAKE) $(MFLAGS) -C sysdeps
+       $(MAKE) $(MFLAGS) -C usr
+       $(MAKE) $(MFLAGS) -C utils
+       $(MAKE) $(MFLAGS) -C etc
+       $(MAKE) $(MFLAGS) -C iscsiuio
+       $(MAKE) $(MFLAGS) -C doc
+       @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 "Built libopeniscsiusr library:       libopeniscsiusr/libopeniscsiusr.so"
+       @echo
+       @echo "Read README file for detailed information."
+
+iscsiuio/Makefile: iscsiuio/configure iscsiuio/Makefile.in
+       cd iscsiuio; ./configure $(WITHOUT_ARG) --sbindir=$(SBINDIR)
+
+iscsiuio/configure: iscsiuio/configure.ac iscsiuio/Makefile.am
+       cd iscsiuio; autoreconf --install
+
+force: ;
+
+clean distclean:
+       $(MAKE) $(MFLAGS) -C sysdeps $@
+       $(MAKE) $(MFLAGS) -C utils $@
+       $(MAKE) $(MFLAGS) -C usr $@
+       $(MAKE) $(MFLAGS) -C etc $@
+       $(MAKE) $(MFLAGS) -C libopeniscsiusr $@
+       $(MAKE) $(MFLAGS) -C doc $@
+       [ ! -f iscsiuio/Makefile ] || $(MAKE) $(MFLAGS) -C iscsiuio $@
+
+# this is for safety
+# now -jXXX will still be safe
+# note that make may still execute the blocks in parallel
+.NOTPARALLEL: install_user install_programs install_initd \
+       install_initd_redhat install_initd_debian \
+       install_doc install_iname install_etc install_etc_all
+
+install: install_programs install_doc \
+       install_systemd install_iname install_libopeniscsiusr \
+       install_iscsiuio install_etc_all
+
+install_iscsiuio:
+       $(MAKE) $(MFLAGS) -C iscsiuio install
+
+install_user: install_programs install_doc install_systemd install_iname
+
+install_udev_rules:
+       $(MAKE) $(MFLAGS) -C utils $@
+
+install_programs:
+       $(MAKE) $(MFLAGS) -C utils install
+       $(MAKE) $(MFLAGS) -C usr install
+
+install_initd install_initd_redhat install_initd_debian install_iface install_systemd install_etc install_iname:
+       $(MAKE) $(MFLAGS) -C etc $@
+
+install_etc_all:
+       $(MAKE) $(MFLAGS) -C etc install
+
+install_doc:
+       $(MAKE) $(MFLAGS) -C doc $@
+
+install_libopeniscsiusr:
+       $(MAKE) $(MFLAGS) -C libopeniscsiusr install
+
+depend:
+       for dir in usr utils utils/fwparam_ibft sysdeps; do \
+               $(MAKE) $(MFLAGS) -C $$dir $@; \
+       done
+
+.PHONY: all user install force clean install_user install_udev_rules install_systemd \
+       install_programs install_initrd install_initrd_redhat install_initrd_debian \
+       install_doc install_iname install_libopeniscsiusr install_etc install_etc_all \
+       distclean depend install_initd install_initd_redhat install_initd_debian \
+       install_iscsiuio
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/README b/pkgs/open-iscsi/open-iscsi-2.1.8/README
new file mode 100644 (file)
index 0000000..118f001
--- /dev/null
@@ -0,0 +1,1925 @@
+=================================================================
+
+                Linux* Open-iSCSI
+
+=================================================================
+
+                                                   Jun 6, 2022
+Contents
+========
+
+- 1. In This Release
+- 2. Introduction
+- 3. Installation
+- 4. Open-iSCSI daemon
+- 5. Open-iSCSI Configuration Utility
+- 6. Configuration
+- 7. Getting Started
+- 8. Advanced Configuration
+- 9. iSCSI System Info
+
+
+1. In This Release
+==================
+
+This file describes the Linux* Open-iSCSI Initiator. The software was
+tested on AMD Opteron (TM) and Intel Xeon (TM).
+
+The latest development release is available at:
+
+       https://github.com/open-iscsi/open-iscsi
+
+For questions, comments, contributions post an issue on github, or
+send e-mail to:
+
+       open-iscsi@googlegroups.com
+
+You can also raise an issue on the github page.
+
+
+1.1. Features
+=============
+
+- highly optimized and very small-footprint data path
+- persistent configuration database
+- SendTargets discovery
+- CHAP
+- PDU header Digest
+- multiple sessions
+
+
+2. Introduction
+===============
+
+The Open-iSCSI project is a high-performance, transport independent,
+multi-platform implementation of RFC3720 iSCSI.
+
+Open-iSCSI is partitioned into user and kernel parts.
+
+The kernel portion of Open-iSCSI was originally part of this project
+repository, but now is built into the linux kernel itself. It
+includes loadable modules: scsi_transport_iscsi.ko, libiscsi.ko and
+scsi_tcp.ko. The kernel code handles the "fast" path, i.e. data flow.
+
+User space contains the entire control plane: configuration
+manager, iSCSI Discovery, Login and Logout processing,
+connection-level error processing, Nop-In and Nop-Out handling,
+and (perhaps in the future:) Text processing, iSNS, SLP, Radius, etc.
+
+The user space Open-iSCSI consists of a daemon process called
+iscsid, and a management utility iscsiadm. There are also helper
+programs, and iscsiuio, which is used for certain iSCSI adapters.
+
+
+3. Installation
+===============
+
+NOTE:  You will need to be root to install the Open-iSCSI code, and
+       you will also need to be root to run it.
+
+As of today, the Open-iSCSI Initiator requires a host running the
+Linux operating system with kernel.
+
+The userspace components iscsid, iscsiadm and iscsistart require the
+open-isns library.
+
+If this package is not available for your distribution, you can download
+and install it yourself.  To install the open-isns headers and library
+required for Open-iSCSI, download the current release from:
+
+       https://github.com/open-iscsi/open-isns
+
+Then, from the top-level directory, run:
+
+       ./configure [<OPTIONS>]
+       make
+       make install
+
+For the open-iscsi project and iscsiuio, the original build
+system used make and autoconf the build the project. These
+build systems are being depcreated in favor of meson (and ninja).
+See below for how to build using make and autoconf, but
+migrating as soon as possible to meson would be a good idea.
+
+Building open-iscsi/iscsiuio using meson
+----------------------------------------
+For Open-iSCSI and iscsiuio, the system is built using meson and ninja
+(see https://github.com/mesonbuild/meson). If these packages aren't
+available to you on your Linux distribution, you can download
+the latest release from: https://github.com/mesonbuild/meson/releases).
+The README.md file describes in detail how to build it yourself, including
+how to get ninja.
+
+To build the open-iscsi project, including iscsiuio, first run meson
+to configure the build, from the top-level open-iscsi directory, e.g.:
+
+       rm -rf builddir
+       mkdir builddir
+       meson [<MESON-OPTIONS>] builddir
+
+Then, to build the code:
+
+       ninja -C builddir
+
+If you change any code and want to rebuild, you simply run ninja again.
+
+When you are ready to install:
+
+       [DESTDIR=<SOME-DIR>] ninja -C builddir install
+
+This will install the iSCSI tools, configuration files, interfaces, and
+documentation. If you do not set DESTDIR, it defaults to "/".
+
+
+MESON-OPTIONS:
+--------------
+One can override several default values when building with meson:
+
+- Library files are installed in /lib64 by default, but this
+  can be overridden by passing '--libdir=<LIBDIR>' to meson.
+
+- Extra flags can be passed to the C compiler using '-Dc_flags="<C-FLAGS>"'.
+
+- In newer version of meson (>=0.63) you can override location where binaries
+  are installed, which by default is "/usr/sbin", using the '--sbindir=<DIR>'
+  option to meson.
+
+- The default "home" directory is "/etc/iscsi", but this can be overridden
+  using '-Dhomedir=<SOMEDIR>'. This is where the configuration files are kept
+
+- The default "database" directory is also "/etc/iscsi", but can be
+  overridden using '-Ddbroot=<SOMEDIR>'
+
+
+Building open-iscsi/iscsiuio using make/autoconf
+------------------------------------------------
+If you wish to build using the older deprecated system, you can
+simply run:
+
+       make [<MAKE-OPTIONS>]
+       make [DESTDIR=<SOME-DIR>] install
+
+Where MAKE-OPTIONS are from:
+       * SBINDIR=<some-dir>  [/usr/bin]   for executables
+       * DBROOT=<some-dir>   [/etc/iscsi] for iscsi database files
+       * HOMEDIR=<some-dir>  [/etc/iscsi] for iscsi config files
+
+
+4. Open-iSCSI daemon
+====================
+
+The iscsid daemon implements control path of iSCSI protocol, plus some
+anagement facilities. For example, the daemon could be configured to
+utomatically re-start discovery at startup, based on the contents of
+ersistent iSCSI database (see next section).
+
+For help, run:
+
+       iscsid --help
+
+The output will be similar to the following (assuming a default install):
+
+Usage: iscsid [OPTION]
+
+  -c, --config=[path]     Execute in the config file (/etc/iscsi/iscsid.conf).
+  -i, --initiatorname=[path]     read initiatorname from file (/etc/iscsi/initiatorname.iscsi).
+  -f, --foreground        run iscsid in the foreground
+  -d, --debug debuglevel  print debugging information
+  -u, --uid=uid           run as uid, default is current user
+  -g, --gid=gid           run as gid, default is current user group
+  -n, --no-pid-file       do not use a pid file
+  -p, --pid=pidfile       use pid file (default /run/iscsid.pid).
+  -h, --help              display this help and exit
+  -v, --version           display version and exit
+
+
+5. Open-iSCSI Configuration and Administration Utility
+======================================================
+
+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 (see "dbroot" in the meson
+options discussed earlier).
+
+Configuration is contained in directories for:
+
+       - 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, as well manage discovery,
+session establishment (login), and ending sessions (logout).
+
+This utility presents set of operations that a user can perform
+on iSCSI node, session, connection, and discovery records.
+
+Open-iSCSI does not use the term node as defined by the iSCSI RFC,
+where a node is a single iSCSI initiator or target. Open-iSCSI uses the
+term node to refer to a portal on a target, so tools like iscsiadm
+require that the '--targetname' and '--portal' arguments be used when
+in node mode.
+
+For session mode, a session id (sid) is used. The sid of a session can be
+found by running:
+
+       iscsiadm -m session -P 1
+
+The session id is not currently persistent and is partially determined by
+when the session is setup.
+
+Note that some of the iSCSI Node and iSCSI Discovery operations
+do not require iSCSI daemon (iscsid) loaded.
+
+For help on the command, run:
+
+       iscsiadm --help
+
+The output will be similar to the following.
+
+iscsiadm -m discoverydb [-hV] [-d debug_level] [-P printlevel] [-t type -p ip:port -I ifaceN ... [-Dl]] | [[-p ip:port -t type] [-o operation] [-n name] [-v value] [-lD]]
+iscsiadm -m discovery [-hV] [-d debug_level] [-P printlevel] [-t type -p ip:port -I ifaceN ... [-l]] | [[-p ip:port] [-l | -D]] [-W]
+iscsiadm -m node [-hV] [-d debug_level] [-P printlevel] [-L all,manual,automatic,onboot] [-W] [-U all,manual,automatic,onboot] [-S] [[-T targetname -p ip:port -I ifaceN] [-l | -u | -R | -s]] [[-o operation ] [-n name] [-v value]]
+iscsiadm -m session [-hV] [-d debug_level] [-P printlevel] [-r sessionid | sysfsdir [-R | -u | -s] [-o operation] [-n name] [-v value]]
+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]]
+iscsiadm -m fw [-d debug_level] [-l] [-W] [[-n name] [-v value]]
+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]]
+iscsiadm -k priority
+
+
+The first parameter specifies the mode to operate in:
+
+  -m, --mode <op>      specify operational mode op =
+                       <discoverydb|discovery|node|session|iface|fw|host>
+
+Mode "discoverydb"
+------------------
+
+  -m discoverydb --type=[type] --interface=[iface…] --portal=[ip:port] \
+                       --print=[N] \
+                       --op=[op]=[NEW | UPDATE | DELETE | NONPERSISTENT] \
+                       --discover
+
+                         This command will use the discovery record settings
+                         matching the record with type=type and
+                         portal=ip:port]. If a record does not exist, it will
+                         create a record using the iscsid.conf discovery
+                         settings.
+
+                         By default, it will then remove records for
+                         portals no longer returned. And,
+                         if a portal is returned by the target, then the
+                         discovery command will create a new record or modify
+                         an existing one with values from iscsi.conf and the
+                         command line.
+
+                         [op] can be passed in multiple times to this
+                         command, and it will alter the node DB manipulation.
+
+                         If [op] is passed in and the value is
+                         "new", iscsiadm will add records for portals that do
+                         not yet have records in the db.
+
+                         If [op] is passed in and the value is
+                         "update", iscsiadm will update node records using
+                         info from iscsi.conf and the command line for portals
+                         that are returned during discovery and have
+                         a record in the db.
+
+                         If [op] is passed in and the value is "delete",
+                         iscsiadm will delete records for portals that
+                         were not returned during discovery.
+
+                         If [op] is passed in and the value is
+                         "nonpersistent", iscsiadm will not store
+                         the portals found in the node DB. This is
+                         only useful with the --login command.
+
+                         See the example section for more info.
+
+                         See below for how to setup iSCSI ifaces for
+                         software iSCSI or override the system defaults.
+
+                         Multiple ifaces can be passed in during discovery.
+
+                         For the above commands, "print" is optional. If
+                         used, N can be 0 or 1.
+                         0 = The old flat style of output is used.
+                         1 = The tree style with the inteface info is used.
+
+                         If print is not used, the old flat style is used.
+
+  -m discoverydb --interface=[iface...] --type=[type] --portal=[ip:port] \
+                       --print=[N] \
+                       --op=[op]=[NEW | UPDATE | DELETE | NONPERSISTENT] \
+                       --discover --login
+
+                         This works like the previous discoverydb command
+                         with the --login argument passed in will also
+                         log into the portals that are found.
+
+  -m discoverydb --portal=[ip:port] --type=[type] \
+                       --op=[op] [--name=[name] --value=[value]]
+
+                         Perform specific DB operation [op] for
+                         discovery portal. It could be one of:
+                         [new], [delete], [update] or [show]. In case of
+                         [update], you have to provide [name] and [value]
+                         you wish to update
+
+                         Setting op=NEW will create a new discovery record
+                         using the iscsid.conf discovery settings. If it
+                         already exists, it will be overwritten using
+                         iscsid.conf discovery settings.
+
+                         Setting op=DELETE will delete the discovery record
+                         and records for the targets found through
+                         Phat discovery source.
+
+                         Setting op=SHOW will display the discovery record
+                         values. The --show argument can be used to
+                         force the CHAP passwords to be displayed.
+
+Mode "discovery"
+----------------
+
+  -m discovery --type=[type] --interface=iscsi_ifacename \
+                       --portal=[ip:port] --login --print=[N] \
+                       --op=[op]=[NEW | UPDATE | DELETE | NONPERSISTENT]
+
+                         Perform [type] discovery for target portal with
+                         ip-address [ip] and port [port].
+
+                         This command will not use the discovery record
+                         settings. It will use the iscsid.conf discovery
+                         settings and it will overwrite the discovery
+                         record with iscsid.conf discovery settings if it
+                         exists. By default, it will then remove records for
+                         portals no longer returned. And,
+                         if a portal is returned by the target, then the
+                         discovery command will create a new record or modify
+                         an existing one with values from iscsi.conf and the
+                         command line.
+
+                         [op] can be passed in multiple times to this
+                         command, and it will alter the DB manipulation.
+
+                         If [op] is passed in and the value is
+                         "new", iscsiadm will add records for portals that do
+                         not yet have records in the db.
+
+                         If [op] is passed in and the value is
+                         "update", iscsiadm will update node records using
+                         info from iscsi.conf and the command line for portals
+                         that are returned during discovery and have
+                         a record in the db.
+
+                         If [op] is passed in and the value is "delete",
+                         iscsiadm will delete records for portals that
+                         were not returned during discovery.
+
+                         If [op] is passed in and the value is
+                         "nonpersistent", iscsiadm will not store
+                         the portals found in the node DB.
+
+                         See the example section for more info.
+
+                         See below for how to setup iSCSI ifaces for
+                         software iSCSI or override the system defaults.
+
+                         Multiple ifaces can be passed in during discovery.
+
+  -m discovery --print=[N]
+
+                         Display all discovery records from internal
+                         persistent discovery database.
+
+Mode "node"
+-----------
+
+  -m node                display all discovered nodes from internal
+                         persistent discovery database
+
+  -m node --targetname=[name] --portal=[ip:port] \
+                       --interface=iscsi_ifacename] \
+                       [--login|--logout|--rescan|--stats] [-W]
+
+  -m node --targetname=[name] --portal=[ip:port]
+                       --interface=[driver,HWaddress] \
+                       --op=[op] [--name=[name] --value=[value]]
+
+  -m node --targetname=[name] --portal=[ip:port]
+                       --interface=iscsi_ifacename] \
+                       --print=[level]
+
+                         Perform specific DB operation [op] for specific
+                         interface on host that will connect to portal on
+                         target. targetname, portal and interface are optional.
+                         See below for how to setup iSCSI ifaces for
+                         software iSCSI or override the system defaults.
+
+                         The op could be one of [new], [delete], [update] or
+                         [show]. In case of [update], you have to provide
+                         [name] and [value] you wish to update.
+                         For [delete], note that if a session is using the
+                         node record, the session will be logged out then
+                         the record will be deleted.
+
+                         Using --rescan will perform a SCSI layer scan of the
+                         session to find new LUNs.
+
+                         Using --stats prints the iSCSI stats for the session.
+
+                         Using --login normally sends a login request to the
+                         specified target and normally waits for the results.
+                         If -W/--no_wait is supplied return success if we are
+                         able to send the login request, and do not wait
+                         for the response. The user will have to poll for
+                         success
+
+                         Print level can be 0 to 1.
+
+  -m node --logoutall=[all|manual|automatic]
+                         Logout "all" the running sessions or just the ones
+                         with a node startup value manual or automatic.
+                         Nodes marked as ONBOOT are skipped.
+
+  -m node --loginall=[all|manual|automatic] [-W]
+                         Login "all" the running sessions or just the ones
+                         with a node startup value manual or automatic.
+                         Nodes marked as ONBOOT are skipped.
+
+                         If -W is supplied then do not wait for the login
+                         response for the target, returning success if we
+                         are able to just send the request. The client
+                         will have to poll for success.
+
+Mode "session"
+--------------
+
+  -m session             display all active sessions and connections
+
+  -m session --sid=[sid] [ --print=level | --rescan | --logout ]
+                       --op=[op] [--name=[name] --value=[value]]
+
+                         Perform operation for specific session with
+                         session id sid. If no sid is given, the operation
+                         will be performed on all running sessions if possible.
+                         --logout and --op work like they do in node mode,
+                         but in session mode targetname and portal info
+                         is not passed in.
+
+                         Print level can be 0 to 2.
+                         1 = Print basic session info like node we are
+                         connected to and whether we are connected.
+                         2 = Print iSCSI params used.
+                         3 = Print SCSI info like LUNs, device state.
+
+                         If no sid and no operation is given print out the
+                         running sessions.
+
+Mode "iface"
+------------
+
+  -m iface --interface=iscsi_ifacename --op=[op] [--name=[name] --value=[value]]
+                       --print=level
+
+                         Perform operation on given interface with name
+                         iscsi_ifacename.
+
+                         See below for examples.
+
+  -m iface --interface=iscsi_ifacename -C ping --ip=[ipaddr] --packetsize=[size]
+                       --count=[count] --interval=[interval]
+
+Mode "host"
+-----------
+
+  -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
+                         for all hosts is printed.
+
+                         Print level can be 0 to 4.
+                         1 = Print info for how like its state, MAC, and
+                             netinfo if possible.
+                         2 = Print basic session info for nodes the host
+                             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]
+
+                         Setting op=DELETE|LOGIN|LOGOUT will perform
+                         deletion/login/ logout operation on the specified
+                         flash node.
+
+                         Setting op=SHOW will list all params with the values
+                         for the specified flash node. This is the default
+                         operation.
+
+                         See the iscsiadm example section below for more info.
+
+Other arguments
+---------------
+
+  -d, --debug debuglevel  print debugging information
+
+  -V, --version                  display version and exit
+
+  -h, --help             display this help and exit
+
+
+5.1 iSCSI iface setup
+=====================
+
+The next sections describe how to setup iSCSI ifaces so you can bind
+a session to a NIC port when using software iSCSI (section 5.1.1), and
+it describes how to setup ifaces for use with offload cards from Chelsio
+and Broadcom (section 5.1.2).
+
+
+5.1.1 How to setup iSCSI interfaces (iface) for binding
+=======================================================
+
+If you wish to allow the network susbsystem to figure out
+the best path/NIC to use, then you can skip this section. For example
+if you have setup your portals and NICs on different subnets, then
+the following is not needed for software iSCSI.
+
+Warning!!!!!!
+This feature is experimental. The interface may change. When reporting
+bugs, if you cannot do a "ping -I ethX target_portal", then check your
+network settings first. Make sure the rp_filter setting is set to 0 or 2
+(see Prep section below for more info). If you cannot ping the portal,
+then you will not be able to bind a session to a NIC.
+
+What is a scsi_host and iface for software, hardware and partial
+offload iSCSI?
+
+Software iSCSI, like iscsi_tcp and iser, allocates a scsi_host per session
+and does a single connection per session. As a result
+/sys/class_scsi_host and /proc/scsi will report a scsi_host for
+each connection/session you have logged into. Offload iSCSI, like
+Chelsio cxgb3i, allocates a scsi_host for each PCI device (each
+port on a HBA will show up as a different PCI device so you get
+a scsi_host per HBA port).
+
+To manage both types of initiator stacks, iscsiadm uses the interface (iface)
+structure. For each HBA port or for software iSCSI for each network
+device (ethX) or NIC, that you wish to bind sessions to you must create
+a iface config /etc/iscsi/ifaces.
+
+Prep
+----
+
+The iface binding feature requires the sysctl setting
+net.ipv4.conf.default.rp_filter to be set to 0 or 2.
+This can be set in /etc/sysctl.conf by having the line:
+       net.ipv4.conf.default.rp_filter = N
+
+where N is 0 or 2. Note that when setting this you may have to reboot
+for the value to take effect.
+
+
+rp_filter information from Documentation/networking/ip-sysctl.txt:
+
+rp_filter - INTEGER
+       0 - No source validation.
+       1 - Strict mode as defined in RFC3704 Strict Reverse Path
+           Each incoming packet is tested against the FIB and if the interface
+           is not the best reverse path the packet check will fail.
+           By default failed packets are discarded.
+       2 - Loose mode as defined in RFC3704 Loose Reverse Path
+           Each incoming packet's source address is also tested against the FIB
+           and if the source address is not reachable via any interface
+           the packet check will fail.
+
+Running
+-------
+
+The command:
+
+       iscsiadm -m iface
+
+will report iface configurations that are setup in /etc/iscsi/ifaces:
+
+       iface0 qla4xxx,00:c0:dd:08:63:e8,20.15.0.7,default,iqn.2005-06.com.redhat:madmax
+       iface1 qla4xxx,00:c0:dd:08:63:ea,20.15.0.9,default,iqn.2005-06.com.redhat:madmax
+
+The format is:
+
+       iface_name transport_name,hwaddress,ipaddress,net_ifacename,initiatorname
+
+For software iSCSI, you can create the iface configs by hand, but it is
+recommended that you use iscsiadm's iface mode. There is an iface.example in
+/etc/iscsi/ifaces which can be used as a template for the daring.
+
+For each network object you wish to bind a session to, you must create
+a separate iface config in /etc/iscsi/ifaces and each iface config file
+must have a unique name which is less than or equal to 64 characters.
+
+Example
+-------
+
+If you have NIC1 with MAC address 00:0F:1F:92:6B:BF and NIC2 with
+MAC address 00:C0:DD:08:63:E7, and you wanted to do software iSCSI over
+TCP/IP, then in /etc/iscsi/ifaces/iface0 you would enter:
+
+       iface.transport_name = tcp
+       iface.hwaddress = 00:0F:1F:92:6B:BF
+
+and in /etc/iscsi/ifaces/iface1 you would enter:
+
+       iface.transport_name = tcp
+       iface.hwaddress = 00:C0:DD:08:63:E7
+
+Warning: Do not name an iface config file  "default" or "iser".
+They are special values/files that are used by the iSCSI tools for
+backward compatibility. If you name an iface default or iser, then
+the behavior is not defined.
+
+To use iscsiadm to create an iface0 similar to the above example, run:
+
+       iscsiadm -m iface -I iface0 --op=new
+
+(This will create a new empty iface config. If there was already an iface
+with the name "iface0", this command will overwrite it.)
+
+Next, set the hwaddress:
+
+       iscsiadm -m iface -I iface0 --op=update \
+               -n iface.hwaddress -v 00:0F:1F:92:6B:BF
+
+If you had sessions logged in, iscsiadm will not update or overwrite
+an iface. You must log out first. If you have an iface bound to a node/portal
+but you have not logged in, then iscsiadm will update the config and
+all existing bindings.
+
+You should now skip to 5.1.3 to see how to log in using the iface, and for
+some helpful management commands.
+
+
+5.1.2 Setting up an iface for an iSCSI offload card
+===================================================
+
+This section describes how to setup ifaces for use with Chelsio, Broadcom and
+QLogic cards.
+
+By default, iscsiadm will create an iface for each Broadcom, QLogic and Chelsio
+port. The iface name will be of the form:
+
+       $transport/driver_name.$MAC_ADDRESS
+
+Running the following command:
+
+       iscsiadm -m iface
+
+will report iface configurations that are setup in /etc/iscsi/ifaces:
+
+       default tcp,<empty>,<empty>,<empty>,<empty>
+       iser iser,<empty>,<empty>,<empty>,<empty>
+       cxgb3i.00:07:43:05:97:07 cxgb3i,00:07:43:05:97:07,<empty>,<empty>,<empty>
+       qla4xxx.00:0e:1e:04:8b:2e qla4xxx,00:0e:1e:04:8b:2e,<empty>,<empty>,<empty>
+
+The format is:
+
+       iface_name transport_name,hwaddress,ipaddress,net_ifacename,initiatorname
+
+where: iface_name:             name of iface
+       transport_name:         name of driver
+       hwaddress:              MAC address
+       ipaddress:              IP address to use for this port
+       net_iface_name:         will be <empty> because change between reboots.
+                               It is used for software iSCSI's vlan or alias binding.
+       initiatorname:          Initiatorname to be used if you want to override the
+                               default one in /etc/iscsi/initiatorname.iscsi.
+
+To display these values in a more friendly way, run:
+
+       iscsiadm -m iface -I cxgb3i.00:07:43:05:97:07
+
+Example output:
+
+       # BEGIN RECORD 2.0-871
+       iface.iscsi_ifacename = cxgb3i.00:07:43:05:97:07
+       iface.net_ifacename = <empty>
+       iface.ipaddress = <empty>
+       iface.hwaddress = 00:07:43:05:97:07
+       iface.transport_name = cxgb3i
+       iface.initiatorname = <empty>
+       # END RECORD
+
+Before you can use the iface, you must set the IP address for the port.
+We determine the corresponding variable name that we want to update from
+the output above, which is "iface.ipaddress".
+Then we fill this empty variable with the value we desire, with this command:
+
+       iscsiadm -m iface -I cxgb3i.00:07:43:05:97:07 -o update \
+               -n iface.ipaddress -v 20.15.0.66
+
+Note for QLogic ports: After updating the iface record, you must apply or
+applyall the settings for the changes to take effect:
+
+       iscsiadm -m iface -I qla4xxx.00:0e:1e:04:8b:2e -o apply
+       iscsiadm -m iface -H 00:0e:1e:04:8b:2e -o applyall
+
+With "apply", the network settings for the specified iface will take effect.
+With "applyall", the network settings for all ifaces on a specific host will
+take effect. The host can be specified using the -H/--host argument by either
+the MAC address of the host or the host number.
+
+Here is an example of setting multiple IPv6 addresses on a single iSCSI
+interface port.
+First interface (no need to set iface_num, it is 0 by default):
+
+       iscsiadm -m iface -I qla4xxx.00:0e:1e:04:8b:2a -o update \
+                -n iface.ipaddress -v fec0:ce00:7014:0041:1111:2222:1e04:9392
+
+Create the second interface if it does not exist (iface_num is mandatory here):
+
+       iscsiadm -m iface -I qla4xxx.00:0e:1e:04:8b:2a.1 -op=new
+       iscsiadm -m iface -I qla4xxx.00:0e:1e:04:8b:2a -o update \
+                -n iface.iface_num -v 1
+       iscsiadm -m iface -I qla4xxx.00:0e:1e:04:8b:2a -o update \
+                -n iface.ipaddress -v fec0:ce00:7014:0041:1111:2222:1e04:9393
+       iscsiadm -m iface -H 00:0e:1e:04:8b:2a --op=applyall
+
+Note: If there are common settings for multiple interfaces then the
+settings from 0th iface would be considered valid.
+
+Now, we can use this iface to login into targets, which is described in the
+next section.
+
+
+5.1.3 Discovering iSCSI targets/portals
+========================================
+
+Be aware that iscsiadm will use the default route to do discovery. It will
+not use the iface specified. So if you are using an offload card, you will
+need a separate network connection to the target for discovery purposes.
+
+*This should be fixed in the some future version of Open-iSCSI*
+
+For compatibility reasons, when you run iscsiadm to do discovery, it
+will check for interfaces in /etc/iscsi/iscsi/ifaces that are using
+tcp for the iface.transport, and it will bind the portals that are discovered
+so that they will be logged in through those ifaces. This behavior can also
+be overridden by passing in the interfaces you want to use. For the case
+of offload, like with cxgb3i and bnx2i, this is required because the transport
+will not be tcp.
+
+For example if you had defined two interfaces but only wanted to use one,
+you can use the --interface/-I argument:
+
+       iscsiadm -m discoverydb -t st -p ip:port -I iface1 --discover -P 1
+
+If you had defined interfaces but wanted the old behavior, where we do not
+bind a session to an iface, then you can use the special iface "default":
+
+       iscsiadm -m discoverydb -t st -p ip:port -I default --discover -P 1
+
+And if you did not define any interfaces in /etc/iscsi/ifaces and do
+not pass anything into iscsiadm, running iscsiadm will do the default
+behavior, allowing the network subsystem to decide which device to use.
+
+If you later want to remove the bindings for a specific target and
+iface, then you can run:
+
+       iscsiadm -m node -T my_target -I iface0 --op=delete
+
+To do this for a specific portal on a target, run:
+
+       iscsiadm -m node -T my_target -p ip:port -I iface0 --op=delete
+
+If you wanted to delete all bindinds for iface0, then you can run:
+
+       iscsiadm -m node -I iface0 --op=delete
+
+And for equalogic targets it is sometimes useful to remove just by portal:
+
+       iscsiadm -m node -p ip:port -I iface0 --op=delete
+
+
+Now logging into targets is the same as with software iSCSI. See section 7
+for how to get started.
+
+
+5.2 iscsiadm examples
+=====================
+
+Usage examples using the one-letter options (see iscsiadm man page
+for long options):
+
+Discovery mode
+--------------
+
+- SendTargets iSCSI Discovery using the default driver and interface and
+               using the discovery settings for the discovery record with the
+               ID [192.168.1.1:3260]:
+
+       iscsiadm -m discoverydb -t st -p 192.168.1.1:3260 --discover
+
+  This will search /etc/iscsi/send_targets for a record with the
+  ID [portal = 192.168.1.1:3260 and type = sendtargets. If found it
+  will perform discovery using the settings stored in the record.
+  If a record does not exist, it will be created using the iscsid.conf
+  discovery settings.
+
+  The argument to -p may also be a hostname instead of an address:
+
+               iscsiadm -m discoverydb -t st -p somehost --discover
+
+  For the ifaces, iscsiadm will first search /etc/iscsi/ifaces for
+  interfaces using software iSCSI. If any are found then nodes found
+  during discovery will be setup so that they can logged in through
+  those interfaces. To specify a specific iface, pass the
+  -I argument for each iface.
+
+- SendTargets iSCSI Discovery updating existing target records:
+
+       iscsiadm -m discoverydb -t sendtargets -p 192.168.1.1:3260 \
+               -o update --discover
+
+  If there is a record for targetX, and portalY exists in the DB, and
+  is returned during discovery, it will be updated with the info from
+  the iscsi.conf. No new portals will be added and stale portals
+  will not be removed.
+
+- SendTargets iSCSI Discovery deleting existing target records:
+
+       iscsiadm -m discoverydb -t sendtargets -p 192.168.1.1:3260 \
+               -o delete --discover
+
+  If there is a record for targetX, and portalY exists in the DB, but
+  is not returned during discovery, it will be removed from the DB.
+  No new portals will be added and existing portal records will not
+  be changed.
+
+  Note: If a session is logged into portal we are going to delete
+  a record for, it will be logged out then the record will be
+  deleted.
+
+- SendTargets iSCSI Discovery adding new records:
+
+       iscsiadm -m discoverydb -t sendtargets -p 192.168.1.1:3260 \
+               -o new --discover
+
+  If there is targetX, and portalY is returned during discovery, and does
+  not have a record, it will be added. Existing records are not modified.
+
+- SendTargets iSCSI Discovery using multiple ops:
+
+       iscsiadm -m discoverydb -t sendtargets -p 192.168.1.1:3260 \
+               -o new -o delete --discover
+
+  This command will add new portals and delete records for portals
+  no longer returned. It will not change the record information for
+  existing portals.
+
+- SendTargets iSCSI Discovery in nonpersistent mode:
+
+       iscsiadm -m discoverydb -t sendtargets -p 192.168.1.1:3260 \
+               -o nonpersistent --discover
+
+  This command will perform discovery, but not manipulate the node DB.
+
+- SendTargets iSCSI Discovery with a specific interface.  If you wish
+  to only use a subset of the interfaces in
+  /etc/iscsi/ifaces, then you can pass them in during discovery:
+
+       iscsiadm -m discoverydb -t sendtargets -p 192.168.1.1:3260 \
+               --interface=iface0 --interface=iface1 --discover
+
+  Note that for software iSCSI, we let the network layer select
+  which NIC to use for discovery, but for later logins iscsiadm
+  will use the NIC defined in the iface configuration.
+
+  qla4xxx support is very basic and experimental. It does not store
+  the record info in the card's FLASH or the node DB, so you must
+  rerun discovery every time the driver is reloaded.
+
+- Manipulate SendTargets DB: Create new SendTargets discovery record or
+  overwrite an existing discovery record with iscsid.conf
+  discovery settings:
+
+       iscsiadm -m discoverydb -t sendtargets -p 192.168.1.1:3260 -o new
+
+- Manipulate SendTargets DB: Display discovery settings:
+
+       iscsiadm -m discoverydb -t sendtargets -p 192.168.1.1:3260 -o show
+
+- Manipulate SendTargets DB: Display hidden discovery settings like
+                CHAP passwords:
+
+       iscsiadm -m discoverydb -t sendtargets -p 192.168.1.1:3260 \
+               -o show --show
+
+- Manipulate SendTargets DB: Set discovery setting.
+
+       iscsiadm -m discoverydb -t sendtargets -p 192.168.1.1:3260 \
+               -o update -n name -v value
+
+- Manipulate SendTargets DB: Delete discovery record. This will also delete
+  the records for the targets found through the discovery source.
+
+       iscsiadm -m discoverydb -t sendtargets -p 192.168.1.1:3260 -o delete
+
+- Show all records in discovery database:
+
+       iscsiadm -m discovery
+
+- Show all records in discovery database and show the targets that were
+  discovered from each record:
+
+       iscsiadm -m discovery -P 1
+
+Node mode
+---------
+
+In node mode you can specify which records you want to log
+into by specifying the targetname, ip address, port or interface
+(if specifying the interface it must already be setup in the node db).
+iscsiadm will search the node db for records which match the values
+you pass in, so if you pass in the targetname and interface, iscsiadm
+will search for records with those values and operate on only them.
+Passing in none of them will result in all node records being operated on.
+
+- iSCSI Login to all portals on every node/starget through each interface
+  set in the db:
+
+       iscsiadm -m node -l
+
+- iSCSI login to all portals on a node/target through each interface set
+  in the db, but do not wait for the login response:
+
+       iscsiadm -m node -T iqn.2005-03.com.max -l -W
+
+- iSCSI login to a specific portal through each interface set in the db:
+
+       iscsiadm -m node -T iqn.2005-03.com.max -p 192.168.0.4:3260 -l
+
+  To specify an iPv6 address, the following can be used:
+
+       iscsiadm -m node -T iqn.2005-03.com.max \
+               -p 2001:c90::211:9ff:feb8:a9e9 -l
+
+  The above command would use the default port, 3260. To specify a
+  port, use the following:
+
+       iscsiadm -m node -T iqn.2005-03.com.max \
+               -p [2001:c90::211:9ff:feb8:a9e9]:3260 -l
+
+  To specify a hostname, the following can be used:
+
+       iscsiadm -m node -T iqn.2005-03.com.max -p somehost -l
+
+- iSCSI Login to a specific portal through the NIC setup as iface0:
+
+       iscsiadm -m node -T iqn.2005-03.com.max -p 192.168.0.4:3260 \
+               -I iface0  -l
+
+- iSCSI Logout of all portals on every node/starget through each interface
+  set in the db:
+
+       iscsiadm -m node -u
+
+  Warning: this does not check startup values like the logout/login all
+  option. Do not use this if you are running iSCSI on your root disk.
+
+- iSCSI logout of all portals on a node/target through each interface set
+  in the db:
+
+       iscsiadm -m node -T iqn.2005-03.com.max -u
+
+- iSCSI logout of a specific portal through each interface set in the db:
+
+       iscsiadm -m node -T iqn.2005-03.com.max -p 192.168.0.4:3260 -u
+
+- iSCSI Logout of a specific portal through the NIC setup as iface0:
+
+       iscsiadm -m node -T iqn.2005-03.com.max -p 192.168.0.4:3260 \
+               -I iface0
+
+- Changing iSCSI parameter:
+
+       iscsiadm -m node -T iqn.2005-03.com.max -p 192.168.0.4:3260 \
+               -o update -n node.cnx[0].iscsi.MaxRecvDataSegmentLength -v 65536
+
+  You can also change parameters for multiple records at once, by
+  specifying different combinations of target, portal and interface
+  like above.
+
+- Adding custom iSCSI portal:
+
+       iscsiadm -m node -o new -T iqn.2005-03.com.max \
+               -p 192.168.0.1:3260,2 -I iface4
+
+  The -I/--interface is optional. If not passed in, "default" is used.
+  For tcp or iser, this would allow the network layer to decide what is
+  best.
+
+  Note that for this command, the Target Portal Group Tag (TPGT) should
+  be passed in. If it is not passed in on the initial creation command,
+  then the user must run iscsiadm again to set the value. Also,
+  if the TPGT is not initially passed in, the old behavior of not
+  tracking whether the record was statically or dynamically created
+  is used.
+
+- Adding custom NIC config to multiple targets:
+
+       iscsiadm -m node -o new -I iface4
+
+  This command will add an interface config using the iSCSI and SCSI
+  settings from iscsid.conf to every target that is in the node db.
+
+- Removing iSCSI portal:
+
+       iscsiadm -m node -o delete -T iqn.2005-03.com.max -p 192.168.0.4:3260
+
+  You can also delete multiple records at once, by specifying different
+  combinations of target, portal and interface like above.
+
+- Display iSCSI portal onfiguration:
+
+       iscsiadm -m node [-o show] -T iqn.2005-03.com.max -p 192.168.0.4:3260
+
+  You can also display multiple records at once, by specifying different
+  combinations of target, portal and interface like above.
+
+  Note: running "iscsiadm -m node" will only display the records. It
+  will not display the configuration info. For the latter, run:
+
+       iscsiadm -m node -o show
+
+- Show all node records:
+
+       iscsiadm -m node
+
+  This will print the nodes using the old flat format where the
+  interface and driver are not displayed. To display that info
+  use the -P option with the argument "1":
+
+       iscsiadm -m node -P 1
+
+Session mode
+------------
+
+- Display session statistics:
+
+       iscsiadm -m session -r 1 --stats
+
+  This function also works in node mode. Instead of the "-r $sid"
+  argument, you would pass in the node info like targetname and/or portal,
+  and/or interface.
+
+- Perform a SCSI scan on a session
+
+       iscsiadm -m session -r 1 --rescan
+
+  This function also works in node mode. Instead of the "-r $sid"
+  argument, you would pass in the node info like targetname and/or portal,
+  and/or interface.
+
+  Note: Rescanning does not delete old LUNs. It will only pick up new
+  ones.
+
+- Display running sessions:
+
+       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
+  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 the
+  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|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
+  the 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
+       Logout can be performed either using the flash node index:
+
+       iscsiadm -m host -H 6 -C flashnode -x 1 -o logout
+
+  or by using the corresponding session index:
+
+       iscsiadm -m session -r $sid -u
+
+- 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
+
+- 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 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 a new 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
+================
+
+The default configuration file is /etc/iscsi/iscsid.conf, but the
+directory is configurable with the top-level make option "homedir".
+The remainder of this document will assume the /etc/iscsi directory.
+This file contains only configuration that could be overwritten by iSCSI
+discovery, or manually updated via iscsiadm utility. Its OK if this file
+does not exist, in which case compiled-in default configuration will take place
+for newer discovered Target nodes.
+
+See the man page and the example file for the current syntax.
+The manual pages for iscsid, iscsiadm are in the doc subdirectory and can be
+installed in the appropriate man page directories and need to be manually
+copied into e.g. /usr/local/share/man8.
+
+
+7. Getting Started
+==================
+
+There are three steps needed to set up a system to use iSCSI storage:
+
+7.1. iSCSI startup using the systemd units or manual startup.
+7.2. Discover targets.
+7.3. Automate target logins for future system reboots.
+
+The systemd startup units will start the iSCSI daemon and log into any
+portals that are set up for automatic login (discussed in 7.2)
+or discovered through the discover daemon iscsid.conf params
+(discussed in 7.1.2).
+
+If your distro does not have systemd units for iSCSI, then you will have
+to start the daemon and log into the targets manually.
+
+
+7.1.1 iSCSI startup using the init script
+=========================================
+
+Red Hat or Fedora:
+-----------------
+To start Open-iSCSI in Red Hat/Fedora you can do:
+
+       systemctl start open-iscsi
+
+To get Open-iSCSI to automatically start at run time you may have to
+run:
+       systemctl enable open-iscsi
+
+And, to automatically mount a file system during startup
+you must have the partition entry in /etc/fstab marked with the "_netdev"
+option. For example this would mount an iSCSI disk sdb:
+
+       /dev/sdb /mnt/iscsi ext3 _netdev 0 0
+
+SUSE or Debian:
+---------------
+The Open-iSCSI service is socket activated, so there is no need to
+enable the Open-iSCSI service. Likewise, the iscsi.service login
+service is enabled automatically, so setting 'startup' to "automatic'
+will enable automatic login to Open-iSCSI targets.
+
+
+7.1.2 Manual Startup
+====================
+
+7.1.2.1 Starting up the iSCSI daemon (iscsid) and loading modules
+=================================================================
+
+If there is no initd script, you must start the tools by hand. First load the
+iSCSI modules:
+
+       modprobe -q iscsi_tcp
+
+After that, start iSCSI as a daemon process:
+
+       iscsid
+
+or alternatively, start it with debug enabled, in a separate window,
+which will force it into "foreground" mode:
+
+       iscsid -d 8
+
+
+7.1.2.2 Logging into Targets
+============================
+
+Use the configuration utility, iscsiadm, to add/remove/update Discovery
+records, iSCSI Node records or monitor active iSCSI sessions (see above or the
+iscsiadm man files and see section 7.2 below for how to discover targets):
+
+       iscsiadm  -m node
+
+This will print out the nodes that have been discovered as:
+
+       10.15.85.19:3260,3 iqn.1992-08.com.netapp:sn.33615311
+       10.15.84.19:3260,2 iqn.1992-08.com.netapp:sn.33615311
+
+The format is:
+
+       ip:port,target_portal_group_tag targetname
+
+If you are using the iface argument or want to see the driver
+info, use the following:
+
+       iscsiadm -m node -P 1
+
+Example output:
+
+       Target: iqn.1992-08.com.netapp:sn.33615311
+               Portal: 10.15.84.19:3260,2
+                       Iface Name: iface2
+               Portal: 10.15.85.19:3260,3
+                       Iface Name: iface2
+
+The format is:
+
+       Target: targetname
+               Portal ip_address:port,tpgt
+                       Iface: ifacename
+
+Here, where targetname is the name of the target and ip_address:port
+is the address and port of the portal. tpgt is the Target Portal Group
+Tag of the portal, and is not used in iscsiadm commands except for static
+record creation. ifacename is the name of the iSCSI interface
+defined in /etc/iscsi/ifaces. If no interface was defined in
+/etc/iscsi/ifaces or passed in, the default behavior is used.
+Default here is iscsi_tcp/tcp to be used over whichever NIC the
+network layer decides is best.
+
+To login, take the ip, port and targetname from above and run:
+
+       iscsiadm -m node -T targetname -p ip:port -l
+
+In this example we would run:
+
+       iscsiadm -m node -T iqn.1992-08.com.netapp:sn.33615311 \
+               -p 10.15.84.19:3260 -l
+
+Note: drop the portal group tag from the "iscsiadm -m node" output.
+
+If you wish, for example to login to all targets represented in the node
+database, but not wait for the login responses:
+
+       iscsiadm -m node -l -W
+
+After this, you can use "session" mode to detect when the logins complete:
+
+       iscsiadm -m session
+
+
+7.2. Discover Targets
+=====================
+
+Once the iSCSI service is running, you can perform discovery using
+SendTarget with:
+
+       iscsiadm -m discoverydb -t sendtargets -p ip:port --discover
+
+Here, "ip" is the address of the portal and "port" is the port.
+
+To use iSNS you can run the discovery command with the type as "isns"
+and pass in the ip:port:
+
+       iscsiadm -m discoverydb -t isns -p ip:port --discover
+
+Both commands will print out the list of all discovered targets and their
+portals, e.g.:
+
+       iscsiadm -m discoverydb -t st -p 10.15.85.19:3260 --discover
+
+This might produce:
+
+       10.15.84.19:3260,2 iqn.1992-08.com.netapp:sn.33615311
+       10.15.85.19:3260,3 iqn.1992-08.com.netapp:sn.33615311
+
+The format for the output is:
+
+       ip:port,tpgt targetname
+
+In this example, for the first target the ip address is 10.15.85.19, and
+the port is 3260. The target portal group is 3. The target name
+is iqn.1992-08.com.netapp:sn.33615311.
+
+If you would also like to see the iSCSI inteface which will be used
+for each session then use the --print=[N]/-P [N] option:
+
+       iscsiadm -m discoverydb -t sendtargets -p ip:port -P 1 --discover
+
+This might print:
+
+    Target: iqn.1992-08.com.netapp:sn.33615311
+        Portal: 10.15.84.19:3260,2
+           Iface Name: iface2
+        Portal: 10.15.85.19:3260,3
+           Iface Name: iface2
+
+In this example, the IP address of the first portal is 10.15.84.19, and
+the port is 3260. The target portal group is 3. The target name
+is iqn.1992-08.com.netapp:sn.33615311. The iface being used is iface2.
+
+While discovery targets are kept in the discovery db, they are
+useful only for re-discovery. The discovered targets (a.k.a. nodes)
+are stored as records in the node db.
+
+The discovered targets are not logged into yet. Rather than logging
+into the discovered nodes (making LUs from those nodes available as
+storage), it is better to automate the login to the nodes we need.
+
+If you wish to log into a target manually now, see section
+"7.1.2.2 Logging in targets" above.
+
+
+7.3. Automate Target Logins for Future System Startups
+======================================================
+
+Note: this may only work for distros with systemd iSCSI login scripts.
+
+To automate login to a node, use the following with the record ID
+(record ID is the targetname and portal) of the node discovered in the
+discovery above:
+
+       iscsiadm -m node -T targetname -p ip:port --op update -n node.startup -v automatic
+
+To set the automatic setting to all portals on a target through every
+interface setup for each protal, the following can be run:
+
+       iscsiadm -m node -T targetname --op update -n node.startup -v automatic
+
+Or to set the "node.startup" attribute to "automatic" as default for
+all sessions add the following to the /etc/iscsi/iscsid.conf:
+
+       node.startup = automatic
+
+Setting this in iscsid.conf will not affect existing nodes. It will only
+affect nodes that are discovered after setting the value.
+
+To login to all automated nodes, simply restart the iSCSI login service, e.g. with:
+
+       systemctl restart iscsi.service
+
+On your next startup the nodes will be logged into automatically.
+
+
+7.4 Automatic Discovery and Login
+=================================
+
+Instead of running the iscsiadm discovery command and editing the
+startup setting, iscsid can be configured so that every X seconds
+it performs discovery and logs in and out of the portals returned or
+no longer returned. In this mode, when iscsid starts it will check the
+discovery db for iSNS records with:
+
+       discovery.isns.use_discoveryd = Yes
+
+This tells iscsi to check for SendTargets discovery records that have the
+setting:
+
+       discovery.sendtargets.use_discoveryd = Yes
+
+If set, iscsid will perform discovery to the address every
+discovery.isns.discoveryd_poll_inval or
+discovery.sendtargets.discoveryd_poll_inval seconds,
+and it will log into any portals found from the discovery source using
+the ifaces in /etc/iscsi/ifaces.
+
+Note that for iSNS the poll_interval does not have to be set. If not set,
+iscsid will only perform rediscovery when it gets a SCN from the server.
+
+#   iSNS Note:
+#   For servers like Microsoft's where they allow SCN registrations, but do not
+#   send SCN events, discovery.isns.poll_interval should be set to a non zero
+#   value to auto discover new targets. This is also useful for servers like
+#   linux-isns (SLES's iSNS server) where it sometimes does not send SCN
+#   events in the proper format, so they may not get handled.
+
+Examples
+--------
+
+SendTargets
+-----------
+
+- Create a SendTargets record by passing iscsiadm the "-o new" argument in
+               discoverydb mode:
+
+       iscsiadm -m discoverydb -t st -p 20.15.0.7:3260 -o new
+
+  On success, this will output something like:
+
+  New discovery record for [20.15.0.7,3260] added.
+
+- Set the use_discoveryd setting for the record:
+
+       iscsiadm -m discoverydb -t st -p 20.15.0.7:3260  -o update \
+               -n discovery.sendtargets.use_discoveryd -v Yes
+
+- Set the polling interval:
+
+       iscsiadm -m discoverydb -t st -p 20.15.0.7:3260  -o update \
+               -n discovery.sendtargets.discoveryd_poll_inval -v 30
+
+To have the new settings take effect, restart iscsid by restarting the
+iSCSI services.
+
+NOTE:  When iscsiadm is run with the -o new argument, it will use the
+       discovery.sendtargets.use_discoveryd and
+       discovery.sendtargets.discoveryd_poll_inval
+       settings in iscsid.conf for the records initial settings. So if those
+       are set in iscsid.conf, then you can skip the iscsiadm -o update
+       commands.
+
+iSNS
+----
+
+- Create an iSNS record by passing iscsiadm the "-o new" argument in
+               discoverydb mode:
+
+       iscsiadm -m discoverydb -t isns -p 20.15.0.7:3205 -o new
+
+  Response on success:
+
+       New discovery record for [20.15.0.7,3205] added.
+
+- Set the use_discoveryd setting for the record:
+
+       iscsiadm -m discoverydb -t isns -p 20.15.0.7:3205  -o update \
+               -n discovery.isns.use_discoveryd -v Yes
+
+- [OPTIONAL: see iSNS note above] Set the polling interval if needed:
+
+       iscsiadm -m discoverydb -t st -p 20.15.0.7:3205  -o update \
+               -n discovery.isns.discoveryd_poll_inval -v 30
+
+To have the new settings take effect, restart iscsid by restarting the
+iscsi services.
+
+Note:  When iscsiadm is run with the -o new argument, it will use the
+       discovery.isns.use_discoveryd and discovery.isns.discoveryd_poll_inval
+       settings in iscsid.conf for the record's initial settings. So if those
+       are set in iscsid.conf, then you can skip the iscsiadm -o update
+       commands.
+
+
+8. Advanced Configuration
+=========================
+
+8.1 iSCSI settings for dm-multipath
+===================================
+
+When using dm-multipath, the iSCSI timers should be set so that commands
+are quickly failed to the dm-multipath layer. For dm-multipath you should
+then set values like queue if no path, so that IO errors are retried and
+queued if all paths are failed in the multipath layer.
+
+
+8.1.1 iSCSI ping/Nop-Out settings
+=================================
+To quickly detect problems in the network, the iSCSI layer will send iSCSI
+pings (iSCSI NOP-Out requests) to the target. If a NOP-Out times out, the
+iSCSI layer will respond by failing the connection and starting the
+replacement_timeout. It will then tell the SCSI layer to stop the device queues
+so no new IO will be sent to the iSCSI layer and to requeue and retry the
+commands that were running if possible (see the next section on retrying
+commands and the replacement_timeout).
+
+To control how often a NOP-Out is sent, the following value can be set:
+
+       node.conn[0].timeo.noop_out_interval = X
+
+Where X is in seconds and the default is 10 seconds. To control the
+timeout for the NOP-Out the noop_out_timeout value can be used:
+
+       node.conn[0].timeo.noop_out_timeout = X
+
+Again X is in seconds and the default is 15 seconds.
+
+Normally for these values you can use:
+
+       node.conn[0].timeo.noop_out_interval = 5
+       node.conn[0].timeo.noop_out_timeout = 10
+
+If there are a lot of IO error messages like
+
+       detected conn error (22)
+
+in the kernel log then the above values may be too aggressive. You may need to
+increase the values for your network conditions and workload, or you may need
+to check your network for possible problems.
+
+
+8.1.2 SCSI command retries
+==========================
+
+SCSI disk commands get 5 retries by default. In newer kernels this can be
+controlled via the sysfs file:
+
+       /sys/block/$sdX/device/scsi_disk/$host:$bus:$target:LUN/max_retries
+
+by writing a integer lower than 5 to reduce retries or setting to -1 for
+infinite retries.
+
+The number of actual retries a command gets may be less than 5 or what is
+requested in max_retries if the replacement timeout expires. When that timer
+expires it tells the SCSI layer to fail all new and queued commands.
+
+
+8.1.3 replacement_timeout
+=========================
+
+The iSCSI layer timer:
+
+       node.session.timeo.replacement_timeout = X
+
+controls how long to wait for session re-establishment before failing all SCSI
+commands:
+
+       1. commands that have been requeued and awaiting a retry
+       2. commands that are being operated on by the SCSI layer's error handler
+       3. all new commands that are queued to the device
+
+up to a higher level like multipath, filesystem layer, or to the application.
+
+The setting is in seconds. zero means to fail immediately. -1 means an infinite
+timeout which will wait until iscsid does a relogin, the user runs the iscsiadm
+logout command or until the node.session.reopen_max limit is hit.
+
+When this timer is started, the iSCSI layer will stop new IO from executing
+and requeue running commands to the Block/SCSI layer. The new and requeued
+commands will then sit in the Block/SCSI layer queue until the timeout has
+expired, there is userspace intervention like a iscsiadm logout command, or
+there is a successful relogin. If the command has run out of retries, the
+command will be failed instead of being requeued.
+
+After this timer has expired iscsid can continue to try to relogin. By default
+iscsid will continue to try to relogin until there is a successful relogin or
+until the user runs the iscsiadm logout command. The number of relogin retries
+is controlled by the Open-iSCSI setting node.session.reopen_max. If that is set
+too low, iscsid may give up and forcefully logout the session (equivalent to
+running the iscsiadm logout command on a failed session) before replacement
+timeout seconds. This will result in all commands being failed at that time.
+The user would then have to manually relogin.
+
+This timer starts when you see the connection error messsage:
+
+       detected conn error (%d)
+
+in the kernel log. The %d will be a integer with the following mappings
+and meanings:
+
+Int     Kernel define           Description
+value
+------------------------------------------------------------------------------
+1      ISCSI_ERR_DATASN        Low level iSCSI protocol error where a data
+                               sequence value did not match the expected value.
+2      ISCSI_ERR_DATA_OFFSET   There was an error where we were asked to
+                               read/write past a buffer's length.
+3      ISCSI_ERR_MAX_CMDSN     Low level iSCSI protocol error where we got an
+                               invalid MaxCmdSN value.
+4      ISCSI_ERR_EXP_CMDSN     Low level iSCSI protocol error where the
+                               ExpCmdSN from the target didn't match the
+                               expected value.
+5      ISCSI_ERR_BAD_OPCODE    The iSCSI Target has sent an invalid or unknown
+                               opcode.
+6      ISCSI_ERR_DATALEN       The iSCSI target has send a PDU with a data
+                               length that is invalid.
+7      ISCSI_ERR_AHSLEN        The iSCSI target has sent a PDU with an invalid
+                               Additional Header Length.
+8      ISCSI_ERR_PROTO         The iSCSI target has performed an operation that
+                               violated the iSCSI RFC.
+9      ISCSI_ERR_LUN           The iSCSI target has requested an invalid LUN.
+10     ISCSI_ERR_BAD_ITT       The iSCSI target has sent an invalid Initiator
+                               Task Tag.
+11     ISCSI_ERR_CONN_FAILED   Generic error that can indicate the transmission
+                               of a PDU, like a SCSI cmd or task management
+                               function, has timed out. Or, we are not able to
+                               transmit a PDU because the network layer has
+                               returned an error, or we have detected a
+                               network error like a link down. It can
+                               sometimes be an error that does not fit the
+                               other error codes like a kernel function has
+                               returned a failure and there no other way to
+                               recovery from it except to try and kill the
+                               existing session and relogin.
+12     ISCSI_ERR_R2TSN         Low level iSCSI protocol error where the R2T
+                               sequence numbers to not match.
+13     ISCSI_ERR_SESSION_FAILED
+                               Unused.
+14     ISCSI_ERR_HDR_DGST      iSCSI Header Digest error.
+15     ISCSI_ERR_DATA_DGST     iSCSI Data Digest error.
+16     ISCSI_ERR_PARAM_NOT_FOUND
+                               Userspace has passed the kernel an unknown
+                               setting.
+17     ISCSI_ERR_NO_SCSI_CMD   The iSCSI target has sent a ITT for an unknown
+                               task.
+18     ISCSI_ERR_INVALID_HOST  The iSCSI Host is no longer present or being
+                               removed.
+19     ISCSI_ERR_XMIT_FAILED   The software iSCSI initiator or cxgb was not
+                               able to transmit a PDU becuase of a network
+                               layer error.
+20     ISCSI_ERR_TCP_CONN_CLOSE
+                               The iSCSI target has closed the connection.
+21     ISCSI_ERR_SCSI_EH_SESSION_RST
+                               The SCSI layer's Error Handler has timed out
+                               the SCSI cmd, tried to abort it and possibly
+                               tried to send a LUN RESET, and it's now
+                               going to drop the session.
+22     ISCSI_ERR_NOP_TIMEDOUT  An iSCSI Nop as a ping has timed out.
+
+
+8.1.4 Running Commands, the SCSI Error Handler, and replacement_timeout
+=======================================================================
+
+Each SCSI command has a timer controlled by:
+
+       /sys/block/sdX/device/timeout
+
+The value is in seconds and the default ranges from 30 - 60 seconds
+depending on the distro's udev scripts.
+
+When a command is sent to the iSCSI layer the timer is started, and when it's
+returned to the SCSI layer the timer is stopped. This could be for successful
+completion or due to a retry/requeue due to a conn error like described
+previously. If a command is retried the timer is reset.
+
+When the command timer fires, the SCSI layer will ask the iSCSI layer to abort
+the command by sending an ABORT_TASK task management request. If the abort
+is successful the SCSI layer retries the command if it has enough retries left.
+If the abort times out, the iSCSI layer will report failure to the SCSI layer
+and will fire a ISCSI_ERR_SCSI_EH_SESSION_RST error. In the logs you will see:
+
+       detected conn error (21)
+
+The ISCSI_ERR_SCSI_EH_SESSION_RST will cause the connection/session to be
+dropped and the iSCSI layer will start the replacement_timeout operations
+described in that section.
+
+The SCSI layer will then eventually call the iSCSI layer's target/session reset
+callout which will wait for the replacement timeout to expire, a successful
+relogin to occur, or for userspace to logout the session.
+
+- If the replacement timeout fires, then commands will be failed upwards as
+described in the replacement timeout section. The SCSI devices will be put
+into an offline state until iscsid performs a relogin.
+
+- If a relogin occurs before the timer fires, commands will be retried if
+possible.
+
+To check if the SCSI error handler is running, iscsiadm can be run as:
+
+       iscsiadm -m session -P 3
+
+and you will see:
+
+       Host Number: X State: Recovery
+
+To modify the timer that starts the SCSI EH, you can either write
+directly to the device's sysfs file:
+
+       echo X > /sys/block/sdX/device/timeout
+
+where X is in seconds.
+Alternatively, on most distros you can modify the udev rule.
+
+To modify the udev rule open /etc/udev/rules.d/50-udev.rules, and find the
+following lines:
+
+       ACTION=="add", SUBSYSTEM=="scsi" , SYSFS{type}=="0|7|14", \
+               RUN+="/bin/sh -c 'echo 60 > /sys$$DEVPATH/timeout'"
+
+And change the "echo 60" part of the line to the value that you want.
+
+The default timeout for normal File System commands is 30 seconds when udev
+is not being used. If udev is used the default is the above value which
+is normally 60 seconds.
+
+
+8.1.4 Optimal replacement_timeout Value
+=======================================
+
+The default value for replacement_timeout is 120 seconds, but because
+multipath's queue_if_no_path and no_path_retry setting can prevent IO errors
+from being propagated to the application, replacement_timeout can be set to a
+shorter value like 5 to 15 seconds. By setting it lower, pending IO is quickly
+sent to a new path and executed while the iSCSI layer attempts
+re-establishment of the session. If all paths end up being failed, then the
+multipath and device mapper layer will internally queue IO based on the
+multipath.conf settings, instead of the iSCSI layer.
+
+
+8.2 iSCSI settings for iSCSI root
+=================================
+
+When accessing the root partition directly through an iSCSI disk, the
+iSCSI timers should be set so that iSCSI layer has several chances to try to
+re-establish a session and so that commands are not quickly requeued to
+the SCSI layer. Basically you want the opposite of when using dm-multipath.
+
+For this setup, you can turn off iSCSI pings by setting:
+
+       node.conn[0].timeo.noop_out_interval = 0
+       node.conn[0].timeo.noop_out_timeout = 0
+
+And you can turn the replacement_timer to a very long value:
+
+       node.session.timeo.replacement_timeout = 86400
+
+
+9. iSCSI System Info
+====================
+
+To get information about the running sessions: including the session and
+device state, session ids (sid) for session mode, and some of the
+negotiated parameters, run:
+
+       iscsiadm -m session -P 2
+
+If you are looking for something shorter, like just the sid to node mapping,
+run:
+
+       iscsiadm -m session [-P 0]
+
+This will print the list of running sessions with the format:
+
+       driver [sid] ip:port,target_portal_group_tag targetname
+
+Example output of "iscsiadm -m session":
+
+       tcp [2] 10.15.84.19:3260,2 iqn.1992-08.com.netapp:sn.33615311
+       tcp [3] 10.15.85.19:3260,3 iqn.1992-08.com.netapp:sn.33615311
+
+To print the hw address info use the -P option with "1":
+
+       iscsiadm -m session -P 1
+
+This will print the sessions with the following format:
+
+       Target: targetname
+               Current Portal: portal currently logged into
+               Persistent Portal: portal we would fall back to if we had got
+                                  redirected during login
+                       Iface Transport: driver/transport_name
+                       Iface IPaddress: IP address of iface being used
+                       Iface HWaddress: HW address used to bind session
+                       Iface Netdev: netdev value used to bind session
+                       SID: iscsi sysfs session id
+                       iSCSI Connection State: iscsi state
+
+Note: if an older kernel is being used or if the session is not bound,
+then the keyword "default" is printed to indicate that the default
+network behavior is being used.
+
+Example output of "iscsiadm -m session -P 1":
+
+       Target: iqn.1992-08.com.netapp:sn.33615311
+               Current Portal: 10.15.85.19:3260,3
+               Persistent Portal: 10.15.85.19:3260,3
+                       Iface Transport: tcp
+                       Iface IPaddress: 10.11.14.37
+                       Iface HWaddress: default
+                       Iface Netdev: default
+                       SID: 7
+                       iSCSI Connection State: LOGGED IN
+                       Internal iscsid Session State: NO CHANGE
+
+The connection state is currently not available for qla4xxx.
+
+To get a HBA/Host view of the session, there is the host mode:
+
+       iscsiadm -m host
+
+This prints the list of iSCSI hosts in the system with the format:
+
+       driver [hostno] ipaddress,[hwaddress],net_ifacename,initiatorname
+
+Example output:
+
+       cxgb3i: [7] 10.10.15.51,[00:07:43:05:97:07],eth3 <empty>
+
+To print this info in a more user friendly way, the -P argument can be used:
+
+       iscsiadm -m host -P 1
+
+Example output:
+
+       Host Number: 7
+               State: running
+               Transport: cxgb3i
+               Initiatorname: <empty>
+               IPaddress: 10.10.15.51
+               HWaddress: 00:07:43:05:97:07
+               Netdev: eth3
+
+Here, you can also see the state of the host.
+
+You can also pass in any value from 1 - 4 to print more info, like the
+sessions running through the host, what ifaces are being used and what
+devices are accessed through it.
+
+To print the info for a specific host, you can pass in the -H argument
+with the host number:
+
+       iscsiadm -m host -P 1 -H 7
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/THANKS b/pkgs/open-iscsi/open-iscsi-2.1.8/THANKS
new file mode 100644 (file)
index 0000000..2b4dd68
--- /dev/null
@@ -0,0 +1,10 @@
+contribution: Wang Zhenyu <zhenyu.z.wang at intel.com>
+contribution: Albert Pauw <pauw at o2.ie>
+contribution: Arne Redlich <arne.redlich at xiranet.com>
+contribution: Christoph Hellwig <hch at infradead.org>
+contribution: Mike Christie <mikenc at us.ibm.com>
+contribution: Ming Zhang <mingz at ele.uri.edu>
+packaging: Chad Tindel <ctindel at gmail.com>
+testing: FUJITA Tomonori <fujita.tomonori at lab.ntt.co.jp>
+testing: Harald Kubota <hkubota at gmx.net>
+testing: Pascal Renauld <prenauld at istorageinc.com>
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/TODO b/pkgs/open-iscsi/open-iscsi-2.1.8/TODO
new file mode 100644 (file)
index 0000000..a3d1d91
--- /dev/null
@@ -0,0 +1,392 @@
+iSCSI DEVELOPMENT HOWTO AND TODO
+--------------------------------
+July 7th 2011
+
+
+If you are admin or user and just want to send a fix, just send the fix any
+way you can. We can port the patch to the proper tree and fix up the patch
+for you. Engineers that would like to do more advanced development then the
+following guideline should be followed.
+
+Submitting Patches
+------------------
+Code should follow the Linux kernel codying style doc:
+http://www.kernel.org/doc/Documentation/CodingStyle
+
+Patches should be submitted to the open-iscsi list open-iscsi@googlegroups.com.
+They should be made with "git diff" or "diff -up" or "diff -uprN", and
+kernel patches must have a "Signed-off-by" line. See section 12
+http://www.kernel.org/doc/Documentation/SubmittingPatches for more
+information on the the signed off line.
+
+Getting the Code
+----------------
+Kernel patches should be made against the linux-2.6-iscsi tree. This can
+be downloaded from kernel.org with git with the following commands:
+
+git clone git://git.kernel.org/pub/scm/linux/kernel/git/mnc/linux-2.6-iscsi.git
+
+Userspace patches should be made against the open-iscsi git tree:
+
+git clone git://git.kernel.org/pub/scm/linux/kernel/git/mnc/open-iscsi.git
+
+
+
+KERNEL TODO ITEMS
+-----------------
+
+1. Make iSCSI log messages humanly readable. In many cases the iscsi tools
+and modules will log a error number value. The most well known is conn
+error 1011. Users should not have to search on google for what this means.
+
+We should:
+
+1. Write a simple table to convert the error values to a string and print
+them out.
+
+2. Document the values, how you commonly hit them and common solutions
+in the iSCSI docs.
+
+See scsi_transport_iscsi.c:iscsi_conn_error_event for where the evil
+"detected conn error 1011" is printed. See the enum iscsi_err in iscsi_if.h
+for a definition of the error code values.
+
+---------------------------------------------------------------------------
+
+2. Implement iSCSI dev loss support.
+
+Currently if a session is down for longer than replacement/recovery_timeout
+seconds, the iscsi layer will unblock the devices and fail IO. Other
+transport, like FC and SAS, will do something similar. FC has a
+fast_io_fail tmo which will unblock devices and fail IO, then it has a
+dev_loss_tmo which will delete the devices accessed through that port.
+
+iSCSI needs to implement dev_loss_tmo behavior, because apps are beginning
+to expect this behavior. An initial path was made here:
+http://groups.google.com/group/open-iscsi/msg/031510ab4cecccfd?dmode=source 
+
+Since all drivers want this behavior we want to make it common. We need to
+change the patch in that link to add a dev_loss_tmo handler callback to the
+scsi_transport_template struct, and add some common sysfs and helpers
+functions to manage the dev_loss_tmo variable.
+
+
+*Being worked on by Vikek S
+
+---------------------------------------------------------------------------
+
+3. Reduce locking contention between session lock.
+
+The session lock is basically one big lock that protects everything
+in the iscsi_session. This lock could be broken down into smaller locks
+and maybe even replaced with something that would not require a lock.
+
+For example:
+
+1. The session lock serializes access to the current R2T the initiator is
+handling (a R2T from the target or the initialR2T if being used). libiscsi/
+libiscsi_tcp will call iscsi_tcp_get_curr_r2t and grab the session lock in
+the xmit path from the xmit thread and then in the recv path
+libiscsi_tcp/iscsi_tcp will call iscsi_tcp_r2t_rsp (this function is called
+with the session lock held). We could add a new per iscsi_task lock and
+use that to guard the R2T.
+
+2. For iscsi_tcp and cxgb*i, libiscsi uses the session->cmdqueue linked list
+and the session lock to queue IO from the queuecommand function (run from
+scsi softirq or kblockd context) to the iscsi xmit thread. Once the task is
+sent from that thread, it is deleted from the list.
+
+It seems we should be able to remove the linked list use here. The tasks
+are all preallocated in the session->cmds array. We can access that
+array and check the task->state (see fail_scsi_tasks for an example).
+We just need to come up with a way to safely set the task state,
+wake the xmit thread and make sure that tasks are executed in the order
+that the scsi layer sent them to our queuecommand function.
+
+A starting point on the queueing:
+We might be able to create a workqueue per processor, queue the work,
+which in this case is the execution of the task, from the queuecommand,
+then rely on the work queue synchronization and serialization code.
+Not 100% sure about this.
+
+Alternative to changing the threading:
+Can we figure out a way to just remove the xmit thread? We currently
+cannot because the network may only be able to send 1000 bytes, but
+to send the current command we need to send 2000. We cannot sleep
+from the queuecommand context until another 1000 bytes frees up and for
+iscsi_tcp we cannot sleep from the recv conext (this happens because we
+could have got a R2T from target and are handling it from the recv path).
+
+
+Note: that for iser and offload drivers like bnx2i and be2iscsi their
+is no xmit thread used.
+
+Note2: cxgb*i does not actually need the xmit thread so a side project
+could be to convert that driver.
+
+
+---------------------------------------------------------------------------
+
+4. Make memory access more efficient on multi-processor machines.
+We are moving twords per process queues in the block layer, so it would
+be a good idea to move the iscsi structs to be allocated on a per process
+basis.
+
+---------------------------------------------------------------------------
+
+5. Make blk_iopoll support (see block/blk-iopoll.c and be2iscsi for an
+example) being able to round robin IO across processors or complete
+on the processor it was queued on
+(today it always completes the IO on the processor the softirq was raised on),
+and convert bnx2i, ib_iser and cxgb*i to it.
+
+Not sure if it will help iscsi_tcp and cxgb, because their completion is done
+from the network softirq which does polling already. With irq balancing it
+can also be spread over all processors too.
+
+---------------------------------------------------------------------------
+
+7. When userspace calls into the kernel using the iscsi netlink interface
+to execute oprations like creating/destroying a session, create a connection
+to a target, etc the rx_queue_mutex is held the entire time (see
+iscsi_if_rx for the iscsi netlink interface entry point). This means
+if the driver should block every thing will be held up.
+
+iscsi_tcp does not block, but some offload drivers might for a couple seconds
+to 10 or 15 secs while it figures out what is going on or cleans up. This a 
+major problem for things like multipath where one connection blocking up the
+recovery of every other connection will delay IO from re-flowing quickly.
+
+We should looking into breaking up the rx_queue_mutex into finer grained
+locks or making it multi threaded. For the latter we could queue operations
+into workqueues.
+
+---------------------------------------------------------------------------
+
+7. Add tracing support to iscsi modules. See the scsi layer's
+trace_scsi_dispatch_cmd_start for an example.
+
+Well, actually in general look into all the tracing stuff available
+(trace_printk/ftrace, etc) and use one.
+
+See http://lwn.net/Articles/291091/ for some details on what is out
+there. We can only use something that is upstream though.
+
+---------------------------------------------------------------------------
+
+8. Improve the iscsi driver logging. Each driver has a different
+way to control logging. We should unify them and make it manageable
+by iscsiadm. So each driver would use a common format, there would
+be a common kernel interface to set the logging level, etc.
+
+---------------------------------------------------------------------------
+
+9. Implement more features from the iSCSI RFC if they are worth it.
+
+- Error Recovery Level (ERL) 1 support - will help tape support.
+- Multi R2T support - Might improve write performance.
+- OutOfOrder support - Might imrpove performance.
+
+---------------------------------------------------------------------------
+
+10. Add support for digest/CRC offload.
+
+---------------------------------------------------------------------------
+
+11. Finish intel IOAT support. I started this here:
+http://groups.google.com/group/open-iscsi/msg/2626b8606edbe690?dmode=source
+but could only test on boxes with 1 gig interfaces which showed no
+difference in performance. Intel had said they saw significant throughput
+gains when using 10 gig.
+
+---------------------------------------------------------------------------
+
+12. Remove the login buffer preallocated buffer. Storage drivers must be able
+to make forward process, so that they can always write out a page incase the
+kernel needs to allocate the page to another process. If the connection were
+to be disconnected and the initiator needed to relogin to the target at this
+time, we might not be abe to allocate a page for the login commands buffer.
+
+To work around the problem the initiator prealloctes a 8K (sometimes
+more depending on the page size) buffer for each session (see iscsi_conn_setup'
+s __get_free_pages call). This is obviously very wasteful since it will be
+a rare occurrence. Can we think of a way to allow multiple sessions to
+be relogged in at the same time, but not have to preallocate so many
+buffers?
+
+---------------------------------------------------------------------------
+
+13. Support iSCSI over swap safely.
+
+Basically just need to hook iscsi_tcp into the patches that
+were submitted here for NBD.
+
+https://lwn.net/Articles/446831/
+
+
+---------------------------------------------------------------------------
+
+
+
+
+
+USERSPACE TODO ITEMS
+--------------------
+1. The iscsi tools, iscsid, iscsiadm and iscsid, have a debug flag, -d N, that
+allows the user to control the amount of output that is logged. The argument
+N is a integer from 1 to 8, with 8 printing out the most output.
+
+The problem is that the values from 1 to 8 do not really mean much. It would
+helpful if we could replace them with something that controls what exactly
+the iscsi tools and kernel modules log.
+
+For example, if we made the debug level argument a bitmap then
+
+iscsiadm -m node --login -d LOGIN_ERRS,PDUS,FUNCTION
+
+might print out extended iscsi login error information (LOGIN_ERRS),
+the iSCSI packets that were sent/receieved (PDUS), and the functions
+that were run (FUNCTION). Note, the use of a bitmapp and the debug
+levels are just an example. Feel free to do something else.
+
+
+We would want to be able to have iscsiadm control the iscsi kernel
+logging as well. There are interfaces like
+/sys/module/libiscsi/paramters/*debug*
+/sys/module/libiscsi_tcp/paramters/*debug*
+/sys/module/iscsi_tcp/paramters/*debug*
+/sys/module/scsi_transport_iscsi/paramters/*debug*
+
+but we would want to extend the debugging options to be finer grained
+and we would want to make it supportable by all iscsi drivers.
+(see #8 on the kernel todo).
+
+---------------------------------------------------------------------------
+
+2. "iscsiadm -m session -P 3" can print out a lot of information about the
+session, but not all configuration values are printed.
+
+iscsiadm should be modified to print out other settings like timeouts,
+Chap settings,  the iSCSI values that were requested vs negotiated for, etc.
+
+---------------------------------------------------------------------------
+
+3. iscsiadm cannot update a setting of a running session. If you want
+to change a timeout you have to run the iscsiadm logout command,
+then update the record value, then login:
+
+iscsiadm -m node -T target -p ip -u
+iscsidm -m node -T target -p ip -o update -n node.session.timeo.replacement_timeout -v 30
+iscsiadm -m node -T target -p ip -l
+
+iscsiadm should be modified to allow updating of a setting without having
+to run the iscsiadm command.
+
+Note that for some settings like iSCSI ones (ImmediateData, FirstBurstLength,
+etc)  that must be negotiated with the target we will have to logout the
+target then re-login, but we should not have to completely destroy the session
+and scsi devices like is done when running the iscsiadm logout command. We
+should be able to pass iscsid the new values and then have iscsid logout and
+relogin.
+
+Other settings like the abort timeout will not need a logout/login. We can
+just pass those to the kernel or iscsid to use.
+
+
+*Being worked on by Tomoaki Nishimura
+
+---------------------------------------------------------------------------
+
+4. iscsiadm will attempt to perform logins/logouts in parallel. Running
+iscsiadm -m node -L, will cause iscsiadm to login to all portals with
+the startup=automatic field set at the same time.
+
+To log into a target, iscsiadm opens a socket to iscsid, sends iscsid a
+request to login to a target, iscsid performs the iSCSI login operation,
+then iscsid sends iscsiadm a reply.
+
+To perform multiple logins iscsiadm will open a socket for each login
+request, then wait for a reply. This is a problem because for 1000s of targets
+we will have 1000s of sockets open. There is a rlimit to control how many
+files a process can have open and iscsiadm currently runs setrlimit to
+increase this.
+
+With users creating lots of virtual iscsi interfaces on the target and
+initiator with each having multiple paths it beomes inefficient to open
+a socket for each requests.
+
+At the very least we want to handle setrlimit RLIMIT_NOFILE limit better,
+and it would be best to just stop openening a socket per login request.
+
+---------------------------------------------------------------------------
+
+6. Implement broadcast/multicasts support, so the initiator can
+find iSNS servers without the user having to set the iSNS server address.
+
+See
+5.6.5.14. Name Service Heartbeat (Heartbeat)
+in
+http://tools.ietf.org/html//rfc4171
+
+---------------------------------------------------------------------------
+
+7. Open-iscsi uses the open-isns iSNS library. The library might be a little
+too complicated and a little too heavy for what we need. Investigate
+replacing it.
+
+Also explore merging the open-isns and linux-isns projects, so we do not have
+to support multiple isns clients/servers in linux.
+
+---------------------------------------------------------------------------
+
+8. Implement the DHCP iSNS option support, so we the initiator can
+find the iSNS sever without the user having to set the iSNS server address.
+See:
+http://www.ietf.org/rfc/rfc4174.txt
+
+---------------------------------------------------------------------------
+
+9. Some iscsiadm/iscsid operations that access the iscsi DB and sysfs can be
+up to Big O(N^2). Some of the code was written when we thought 64 sessions
+would be a lot and the norm would be 4 or 8. Due to virtualization, cloud use,
+and targets like equallogic that do a target per logical unit (device) we can
+see 1000s of sessions.
+
+- We should look into making the record DB more efficient. Maybe
+time to use a real DB (something small simple and efficient since this
+needs to run in places like the initramfs).
+
+- Rewrite code to look up a running session so we do not have loop
+over every session in sysfs.
+
+
+---------------------------------------------------------------------------
+
+10. Look into using udev's libudev for our sysfs access in iscsiadm/iscsid/
+iscsistart.
+
+---------------------------------------------------------------------------
+
+11. iSCSI lib.
+
+I am working on this one. Hopefully it should be done soon.
+
+---------------------------------------------------------------------------
+
+12. Figure out how to stop using our own copy of iscsi_if.h, since
+it gets out of sync with the kernel version, and that's not good.
+
+---------------------------------------------------------------------------
+
+13. Node database
+
+Current implementation of node data is not scalable. It handles database using
+some bunch of files and directories. It has not locking and can not handle
+thousands of targets.
+
+---------------------------------------------------------------------------
+
+14. Migration of duplicate functionality out of iscsid/iscsiadm into libopeniscsi
+and add better error handling .
+
+---------------------------------------------------------------------------
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/NEWS b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/NEWS
new file mode 100644 (file)
index 0000000..7a3e0f8
--- /dev/null
@@ -0,0 +1,65 @@
+open-iscsi (2.1.2-1) unstable; urgency=medium
+
+  open-iscsi is now linked with the OpenSSL library. With the change,
+  the build of open-iscsi in Debian, is close to what upstream expects
+
+  The decision to link to OpenSSL library was made based on the recent
+  conclusions of Debian FTP Master team
+
+ -- Ritesh Raj Sarraf <rrs@debian.org>  Sun, 15 Nov 2020 12:48:14 +0530
+
+open-iscsi (2.0.873+git0.3b4b4500-10) unstable; urgency=low
+
+  RESTARTING OF ISCSID ON UPGRADES
+
+  On updates, iscsid is now restarted (it previously wasn't). This is
+  supported and as long as the new iscsid is able log in to the
+  targets again, everything will continue to work. Filesystems DO NOT
+  have to be unmounted, I/O will just block for a couple of seconds
+  until the connections with the targets are reestablished.
+
+  Note that to achieve this, open-iscsi now uses two init scripts /
+  systemd services:
+     - iscsid starts/stops the daemon (only this is restarted when
+       upgrading)
+     - open-iscsi logs in and out of targets (previously also started
+       the daemon)
+
+  The previous method of keeping the old iscsid running on upgrades
+  was not actually supported upstream.
+
+  Note that due to these changes, any attempt to downgrade to version
+  2.0.873+git0.3b4b4500-9 or earlier will badly break your open-iscsi
+  installation.
+
+
+
+  ROOT FILESYSTEMS ON ISCSI
+
+  Previously, if the root filesystem was on iSCSI, open-iscsi would
+  not log out of any session at shutdown. This behavior has changed,
+  only the session that carries the root filesystem will be kept, all
+  other sessions will be logged out. If for some reason your storage
+  setup is not properly detected, you may return to the old behavior
+  by setting ISCSI_ROOT_KEEP_ALL_SESSIONS_AT_SHUTDOWN=1 in
+  /etc/default/open-iscsi.
+
+
+
+  HANDLE_NETDEV=0 BEHAVIOR CHANGE
+
+  If you are running sysvinit and have HANDLE_NETDEV=0, please note
+  that this flag is now also checked at bootup, i.e. filesystems with
+  _netdev will not be mounted automatically at boot anymore by
+  open-iscsi. (Previously, this flag was only checked at shutdown.)
+  On systemd systems, HANDLE_NETDEV is now completely ignored, as
+  systemd handles mounting of network filesystems directly.
+
+
+
+  PURGING OPEN-ISCSI
+
+  If you purge open-iscsi, it will now remove the database in
+  /etc/iscsi (it previously didn't).
+
+ -- Christian Seiler <christian@iwakd.de>  Thu, 20 Aug 2015 11:08:37 +0200
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/README.Debian b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/README.Debian
new file mode 100644 (file)
index 0000000..f0c2568
--- /dev/null
@@ -0,0 +1,161 @@
+open-iscsi for Debian
+-----------------------------------
+
+The open-iscsi package contains the userspace portion the Open iSCSI
+project. It depends on iSCSI modules which are already present in
+current (>= 2.6.18) kernels.
+
+
+Safety of package upgrades
+-----------------------------------
+
+When upgrading this package, iscsid will be restarted. This is
+generally safe, in that the kernel will still keep iSCSI sessions open
+even if iscsid exits. (The kernel will not, however, automatically
+reconnect if the connection is dropped, because e.g. the target is
+unreachable for a couple of seconds - that only happens if iscsid is
+running.) iscsid will try to reconnect all currently open iSCSI
+sessions once it starts up again - and as long as that succeeds, it
+will be completely transparent for anything that is accessing iSCSI
+storage (I/O will block for up to a couple of seconds). The package's
+scripts (preinst, postinst) contain checks that make sure all iSCSI
+sessions are in a good state before attempting the upgrade (and will
+provide the option to abort upgrades if that is not the case).
+
+HINT: It is advisable to check the validity of the configuration
+before upgrading - to make sure that a restart of iscsid after the
+upgrade will in fact work.
+
+
+64 bit kernel with 32 bit userspace
+-----------------------------------
+open-iscsi running with a 64 bit kernel and 32 bit userspace
+can run into a hang during the iSCSI login phase. This is a known
+issue upstream. For details, please see Debian BTS #502845
+
+
+Automatic login and mount
+-----------------------------------
+
+If you want to automatically connect to all discovered targets, change
+the following line:
+node.startup = manual
+to:
+node.startup = automatic
+
+If you want to automatically mount filesystems on iSCSI volumes,
+change node.startup to automatic as above, and also add _netdev to
+the mount options (in /etc/fstab) for the filesystems you would like
+to mount automatically when open-iscsi is started. On sysvinit systems
+you should also make sure that HANDLE_NETDEV is set to 1 in
+/etc/default/open-iscsi (not required for systemd systems).
+
+
+iSCSI Qualified Names (IQN) and initiatorname.iscsi
+-----------------------------------
+
+The initiatorname.iscsi file defines the iSCSI Qualified Name (IQN) of the iSCSI 
+initiator. This IQN is used by the initiator to identify itself to the target.
+
+Example: InitiatorName=iqn.1993-08.org.debian:01:lnx-debian
+
+While this name can be adjusted to suit your needs, once set, it should not be 
+changed. If you later change the InitiatorName, existing access control lists 
+on the target may reject the initiator to log in. In case a name change is 
+required, the access control lists on the target will need to be updated.
+
+
+Root on iSCSI
+-----------------------------------
+
+The Debian open-iscsi package now supports root filesystem on iSCSI.  Support
+for this is controlled by the existence of the /etc/iscsi/iscsi.initramfs file.
+
+If you are booting from an iSCSI accelerator or NIC that supports iSCSI boot
+natively, you can likely have your iSCSI target mounted without any manual
+configuration. Either place the single line "ISCSI_AUTO=true" into
+/etc/iscsi/iscsi.initramfs, or use the kernel boot line option "iscsi_auto".
+
+If you use automatic configuration, and the iSCSI NIC is also the NIC that
+has the default route, you need to install the busybox (or busybox-initramfs
+on Ubunut) package, otherwise the default route will not be set when you
+boot the system.
+
+If manual configuration is necessary, there are two ways to include iSCSI boot 
+options in your initramfs:
+
+1) Touch /etc/iscsi/iscsi.initramfs and provide options on the command line.
+   This provides flexibility, but if passwords are used, is not very secure.
+   Available boot line options:
+       iscsi_initiator, iscsi_target_name, iscsi_target_ip,
+       iscsi_target_port, iscsi_target_group, iscsi_username,
+       iscsi_password, iscsi_in_username, iscsi_in_password
+   See iscsistart --help for a description of each option
+
+2) Provide iSCSI option in /etc/iscsi/iscsi.initramfs.
+   Available options:
+       ISCSI_INITIATOR, ISCSI_TARGET_NAME, ISCSI_TARGET_IP,
+       ISCSI_TARGET_PORT, ISCSI_TARGET_GROUP, ISCSI_USERNAME
+       ISCSI_PASSWORD, ISCSI_IN_USERNAME, ISCSI_IN_PASSWORD
+
+   Example Syntax:
+
+   ISCSI_INITIATOR="iqn.1993-08.org.debian:01:9b3e5634fdb9"
+   ISCSI_TARGET_NAME=iqn.2008-01.com.example:storage.foo
+   ISCSI_TARGET_IP=192.168.1.1
+   ISCSI_TARGET_PORT=3260
+   ISCSI_USERNAME="username"
+   ISCSI_PASSWORD="password"
+   ISCSI_IN_USERNAME="in_username"
+   ISCSI_IN_PASSWORD="in_password"
+   ISCSI_TARGET_GROUP=1
+
+   Remember to set proper permissions if username/passwords are used.
+
+If both facilities are used, command line options overwrite iscsi.initramfs
+options.  Also remember that iSCSI requires a working network device, so
+you'll need to get networking started via an ip= boot option (ex. ip=dhcp).
+You also won't want to restart the device during boot, so set it to manual
+mode in /etc/networking/interfaces.  Provide a root=/dev/sd* device as the
+iSCSI disk will look like a local disk.
+
+Note: If you need multiple sessions in the initramfs, you can provide multiple IPs
+to the ISCSI_TARGET_IP variable.
+Eg: ISCSI_TARGET_IP="192.168.1.1 192.168.2.1 192.168.3.1"
+This will allow login into all the Target IPs in the initrafs.
+
+
+QLogic/Broadcom (bnx2/bnx2x) Offloading
+-----------------------------------
+
+Cards managed by the bnx2 / bnx2x driver support hardware offloading of
+iSCSI sessions. To enable support for this, please install the iscsiuio
+package. Further details can be found in the package's README file,
+located in /usr/share/doc/iscsiuio/README.gz.
+
+
+Booting with Hardware Offloading
+-----------------------------------
+
+Booting from volumes accessed via hardware offloaded devices is
+supported. For bnx2/bnx2x cards the iscsiuio package must be installed.
+At the moment this is only supported when using automatic NIC
+configuration at boot time when using iscsi_auto on the kernel command
+line or ISCSI_AUTO=true in /etc/iscsi/iscsi.initramfs (see above).
+
+
+initramfs integration
+-----------------------------------
+
+open-iscsi binaries are added to the initramfs, regardless of whether
+/etc/iscsi/iscsi.initramfs exists, because kernel parameters could be used
+to specify iSCSI parameters regardless of its existence.
+
+If you don't have the root or /usr filesystem on iSCSI and want to keep the
+size of your initramfs small, create
+
+/etc/initramfs-tools/conf.d/open-iscsi
+
+with the following contents:
+
+NO_ISCSI_IN_INITRAMFS=yes
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/README.source b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/README.source
new file mode 100644 (file)
index 0000000..9bdfd74
--- /dev/null
@@ -0,0 +1,4 @@
+This package uses quilt to manage all modifications to the upstream
+source.  Changes are stored in the source package as diffs in
+debian/patches and applied during the build.
+See /usr/share/doc/quilt/README.source for a detailed explanation.
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/autoreconf b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/autoreconf
new file mode 100644 (file)
index 0000000..e1d98c3
--- /dev/null
@@ -0,0 +1 @@
+iscsiuio
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/buildconfig.build-deb b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/buildconfig.build-deb
new file mode 100644 (file)
index 0000000..1bb8bf6
--- /dev/null
@@ -0,0 +1 @@
+# empty
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/buildconfig.build-udeb b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/buildconfig.build-udeb
new file mode 100644 (file)
index 0000000..7e4d43c
--- /dev/null
@@ -0,0 +1,2 @@
+# disabled libsystemd in d-i
+NO_SYSTEMD=1
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/buildconfig.common b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/buildconfig.common
new file mode 100644 (file)
index 0000000..1bb8bf6
--- /dev/null
@@ -0,0 +1 @@
+# empty
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/changelog b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/changelog
new file mode 100644 (file)
index 0000000..f5c38cf
--- /dev/null
@@ -0,0 +1,991 @@
+open-iscsi (2.1.8-1) unstable; urgency=medium
+
+  [ Chris Hofstaedtler ]
+  * [be2751b] New upstream version 2.1.8 (Closes: #1021742)
+  * [6697df5] Remove upstream applied non-usrmerge-sed.patch
+
+  [ Eric Mackay ]
+  * [7dbf2c1] Man pages are no longer gzipped in upstream code
+  * [833e478] Drop upstream 341 and 354 patches, refresh remaining patches
+
+ -- Chris Hofstaedtler <zeha@debian.org>  Wed, 19 Oct 2022 15:59:32 +0000
+
+open-iscsi (2.1.7-2) unstable; urgency=medium
+
+  * [09dfaec] Enable hardening build flags
+  * [c0ce256] d/rules: remove unused DEB_HOST_MULTIARCH
+  * [70574d1] Run separate build for udeb to avoid libsystemd dependency
+    (Closes: #1003366)
+
+ -- Chris Hofstaedtler <zeha@debian.org>  Sat, 30 Jul 2022 14:23:25 +0000
+
+open-iscsi (2.1.7-1) unstable; urgency=medium
+
+  * [3050096] New upstream version 2.1.7 (Closes: #982307, #1016246)
+  * [46fd279] Refresh patches, drop upstream applied ftbfs patch
+  * [cac01da] Help upstream Makefile find sed in /bin
+  * [0202184] Add patches from upstream master to fix build
+  * [f61e6a0] Use dh_auto_install, better suits new upstream build system
+  * [2080bfb] Fix multiarch install location
+  * [4f57eb7] Move udeb files into correct places (like in 2.0.874-7.1)
+  * [75b86ce] Cleanup duplicate override_dh_installsystemd section
+    (Closes: #1004014)
+  * [24f9981] d/copyright: update
+  * [41970e3] Rely on dh_installinitramfs to install triggers
+
+ -- Chris Hofstaedtler <zeha@debian.org>  Fri, 29 Jul 2022 19:59:11 +0000
+
+open-iscsi (2.1.5-1) unstable; urgency=medium
+
+  * [150470c] New upstream version 2.1.5
+  * [7ca9f9e] Install the debian iscsid.service unit (Closes: #996708)
+  * [d660992] Add patch to fix build failure with gcc-11
+
+ -- Ritesh Raj Sarraf <rrs@debian.org>  Thu, 21 Oct 2021 21:36:50 +0530
+
+open-iscsi (2.1.4-2) unstable; urgency=low
+
+  [ Debian Janitor ]
+  * [66832cc] Trim trailing whitespace.
+  * [f68aaaf] debian/copyright: use spaces rather than tabs to start
+    continuation lines.
+  * [16eb556] Use secure URI in Homepage field.
+  * [c3f9946] Bump debhelper dependency to >= 10, since that's what
+    is used in debian/compat.
+  * [693da74] Bump debhelper from old 10 to 13.
+    + Use dh_installsystemd rather than deprecated dh_systemd_enable.
+    + Use dh_installsystemd rather than deprecated dh_systemd_start.
+    + debian/rules: Drop --fail-missing argument to dh_missing, which
+      is now the default.
+  * [107b3e4] Set debhelper-compat version in Build-Depends.
+  * [68b97c5] Remove unnecessary 'Testsuite: autopkgtest' header.
+  * [b80b61e] Set upstream metadata fields: Bug-Database, Bug-Submit,
+    Repository, Repository-Browse.
+  * [1096e5b] Update standards version to 4.5.1, no changes needed.
+
+ -- Ritesh Raj Sarraf <rrs@debian.org>  Thu, 09 Sep 2021 19:36:42 +0530
+
+open-iscsi (2.1.4-1) unstable; urgency=low
+
+  [ Ritesh Raj Sarraf ]
+  * [1a58d4e] Drop patches. Part of new upstream release
+  * [a264531] Rebase patch
+
+  [ Rafael David Tinoco ]
+  * d/iscsid.service: Let iscsid systemd job run in privileged
+    containers but not in unprivileged ones
+  * debian/extra/initramfs.local-top: handle iSCSI iBFT DHCP to
+    correctly run ipconfig to gather all DHCP config info, including
+    DNS search domain, which iBFT can't provide.
+  * Remove initramfs interfaces stamp in case no iscsi devs mounted
+  * add IPv6 support
+    - Source /run/net6-*.conf when needed.
+    - debian/extra/initramfs.local-top: handle IPv6 configs being
+      shipped in DEVICE6 or /run/net6-*.conf in the initramfs, so we
+      can fill in /run/initramfs/open-iscsi.interface
+  * d/rules, d/open-iscsi.finalrd, d/control: ship the finalrd iscsi
+    logout hook and recommend finalrd and busybox for the logout hook
+    to work.
+  * Make iscsid socket-activated to only activate it as needed:
+    - debian/open-iscsi.service: do not start or check iscsid.service
+    - debian/rules: install iscsid.socket
+    - debian/open-iscsi.postinst:
+    - upgrade: run restart logic only if service is running
+    - upgrade: disable iscsid.service and enable iscsid.socket
+    - iscsid.socket not started if the service is not running yet
+    - d/iscsi-disk.rules: Add a udev rule so that iscsid.service will be
+      run when udev disks are attached.
+    - d/iscsid.service: Remove ExecStop= directive.
+    - debian/tests/install: fix tests to work with socket activation
+    - debian/patches/lp1755858-default-iscsid_conf-to-iscsid_socket.patch
+  * debian/open-iscsi.service: Start open-iscsi systemd job when either
+    /etc/iscsi/nodes or /sys/class/iscsi_session have content.
+  * Prevent network interface that contains iscsi root from bouncing
+    during boot or going down during shutdown if the system is using
+    resolvconf or ifupdown:
+    - debian/iscsi-network-interface.rules
+    - debian/extra/net-interface-handler
+  * debian/extra/initramfs.hook: add ib_iser to the list of modules
+    included in the initramfs, so that we can in principle support
+    iscsi root on infiniband.
+  * debian/open-iscsi.kmod drop: (LP: #1833586) no static module
+    list is needed if we let iscsid load modules itself.
+  * d/extra/initramfs.local-{top,bottom}: move removal of
+    open-iscsi.interface file from local-top to local-bottom, and fix
+    shell quoting issue that would result in
+    /run/initramfs/open-iscsi.interface always being removed
+    (LP: #1872813)
+  * d/rules: Don't FTBFS due to warnings new in gcc10 regarding bounds
+    and initialization, because upstream's gcc10 support is incomplete.
+    This change can be dropped when upstream has completed their gcc
+    support.
+
+  [ Christian Ehrhardt ]
+  * [84e211f] New upstream version 2.1.4
+
+  [ Debian Janitor ]
+  * [03a860a] Remove constraints unnecessary since buster
+
+ -- Ritesh Raj Sarraf <rrs@debian.org>  Thu, 02 Sep 2021 18:07:51 +0530
+
+open-iscsi (2.1.3-5) unstable; urgency=medium
+
+  [ Cyril Brulebois ]
+  * [3b8b2d8] Revert "Set architecture for build to linux-any"
+  * [1297e50] Adjust dh_auto_install and dh_makeshlibs overrides for the conditional udeb.
+
+ -- Ritesh Raj Sarraf <rrs@debian.org>  Thu, 20 May 2021 19:52:30 +0530
+
+open-iscsi (2.1.3-4) unstable; urgency=medium
+
+  * [8142984] Set architecture for build to linux-any. This ensures that the
+    library is built on the right set of architectures and dh_makeshlibs is
+    invoked appropriately. (Closes: #987858)
+
+ -- Ritesh Raj Sarraf <rrs@debian.org>  Tue, 04 May 2021 21:45:56 +0530
+
+open-iscsi (2.1.3-3) unstable; urgency=medium
+
+  * [47645a5] Make open-iscsi-udeb compatible with d-i.
+    Thanks to Cyril Brulebois (Closes: #987568)
+
+ -- Ritesh Raj Sarraf <rrs@debian.org>  Thu, 29 Apr 2021 13:43:35 +0530
+
+open-iscsi (2.1.3-2) unstable; urgency=medium
+
+  * [c3b7109] Fix FTCBFS:
+    Let dh_auto_configure pass --host to iscsiuio/configure.
+    Thanks to Helmut Grohne <helmut@subdivi.de> (Closes: #898758)
+  * [efb5512] Add patches from upstream:
+    Fix memory leak in iscsiadm, Fix iscsiadm segfault when exiting, and
+    Fix iscsistart login issue when target is delayed. The last one should
+    fix #980085. (Closes: #980085)
+
+ -- Chris Hofstaedtler <zeha@debian.org>  Sun, 07 Feb 2021 19:23:13 +0000
+
+open-iscsi (2.1.3-1) unstable; urgency=medium
+
+  * [afee47d] New upstream version 2.1.3
+    - Fixes CVE-2020-13987, CVE-2020-17437, CVE-2020-13988.
+  * [236761e] Mark open-iscsi, iscsiuio M-A: foreign (Closes: #941099)
+  * [3e25b6a] d/README.source: remove obsolete get-orig-source note
+  * [296cd55] Explicitly set build date for docs.
+    Thanks to Chris Lamb <lamby@debian.org> (Closes: #975046)
+
+ -- Chris Hofstaedtler <zeha@debian.org>  Thu, 24 Dec 2020 00:09:46 +0000
+
+open-iscsi (2.1.2-2) unstable; urgency=medium
+
+  * Source-only upload to allow testing migration.
+  * Add myself to Uploaders.
+
+ -- Chris Hofstaedtler <zeha@debian.org>  Sun, 06 Dec 2020 23:25:11 +0000
+
+open-iscsi (2.1.2-1) unstable; urgency=medium
+
+  * [7f10701] New upstream version 2.1.2
+  * [51e4a23] Drop all patches
+  * [94b33e9] Fix Vcs-Browser link
+  * [36f52c9] Add a news entry about linkage with OpenSSL
+  * [8bee5c7] Update d/copyright with copyright and license information
+  * [02bacbf] Remove unused code to parse changelog
+  * [72bc9ac] Set libopensicsiusr-dev to arch:all as it has no
+    architecture dependent files
+
+ -- Ritesh Raj Sarraf <rrs@debian.org>  Sun, 15 Nov 2020 17:09:06 +0530
+
+open-iscsi (2.1.1-2) unstable; urgency=medium
+
+  * Upload to Unstable
+  * [71e9333] Set to master
+  * [dd49a5a] Add patches to fix compiler warnings
+
+ -- Ritesh Raj Sarraf <rrs@debian.org>  Fri, 14 Aug 2020 12:32:16 +0530
+
+open-iscsi (2.1.1-1) experimental; urgency=medium
+
+  [ Rafael David Tinoco ]
+  * New upstream version 2.1.1:
+    - [76d0a49] Remove OpenSSL dependency due to GPL license conflict
+    - [5f12ebf] Bump compatibility
+    - [44034fb] Updates to debian/rules:
+      - Update package description from upstream documentation
+      - Update Standards-Version
+      - Update Build-Depends and Depends
+      - Create new needed packages (open-iscsi userland library)
+    - [f4f0987] Update copyright and fix lintian complains
+    - [37cef72] status command defined to show active sessions
+    - [4b93bb8] Remove old post-installation workaround and update path
+    - [0a5ec77] Remove rest of unneeded old update path (abort-upgrade)
+    - [a4762f0] Remove rest of unneeded old update path (upgrade)
+    - [6915ce5] iscsid.service is needed whenever iscsi disks are added
+    - [1002212] Update tests dependencies
+    - [d3b6647] Workaround for Flex 2.5.35 is not needed anymore
+    - [396b15a] Use debian/rules for dh overrides (easier to manage)
+    - [3427d74] Remove old openssl patch to licensing issue:
+      - d/p/debian/dont-link-against-openssl.patch
+    - [dc3cfaf] Drop unneeded patches for v2.1.1:
+      - bugfixes/no-make-clean-kernel.patch (2.0.875-47-gb4a1cef)
+      - debian/var-run-lock.patch (2.0.877-27-g0f30033)
+      - debian/udeb-without-libmount.patch (libmount1-dbgsym:2.35.1-5)
+      - bugfixes/need_iscsiuio_for_hardware_offload.patch (2.0.873-214-gf780a82)
+      - bugfixes/move_offload_discovery_to_fw_get_targets.patch (2.0.873-215-g3ae35d3)
+      - bugfixes/fix_iscsiuio_long_options.patch (2.0.873-216-g0685179)
+      - security/Check-for-root-peer-user-for-iscsiuio-IPC.patch (2.0.875-14-ge313bd6)
+      - security/iscsiuio-should-ignore-bogus-iscsid-broadcast-packet.patch (2.0.875-15-gb9c3368)
+      - security/Ensure-all-fields-in-iscsiuio-IPC-response-are-set.patch (2.0.875-16-gbe58eed)
+      - security/Do-not-double-close-IPC-file-stream-to-iscsid.patch (2.0.875-17-g5504053)
+      - security/Ensure-strings-from-peer-are-copied-correctly.patch (2.0.875-18-g85f647c)
+      - security/Skip-useless-strcopy-and-validate-CIDR-length.patch (2.0.875-19-ga7a9613)
+      - security/Check-iscsiuio-ping-data-length-for-validity.patch (2.0.875-20-g59ede2c)
+      - include-sys-sysmacros.h-to-properly-define-minor.patch (2.0.875-10-g6d68ef5)
+
+  [ Ritesh Raj Sarraf ]
+  * [1078a22] Set debian branch to experimental
+  * [59b9ef1] Install docs for the new libopeniscsiusr package
+
+ -- Ritesh Raj Sarraf <rrs@debian.org>  Tue, 23 Jun 2020 20:38:47 +0530
+
+open-iscsi (2.0.874-7) unstable; urgency=medium
+
+  * [eeda27c] Enable back pristine-tar as we have now committed it
+    from the old upload
+
+ -- Ritesh Raj Sarraf <rrs@debian.org>  Sun, 07 Oct 2018 09:57:48 +0530
+
+open-iscsi (2.0.874-6) unstable; urgency=medium
+
+  * [645e13b] Switch packaging to Salsa (Closes: #899771)
+  * [9c86242] Add patch to fix FTBFS for missing macro.
+    Thanks to Scott Moser (Closes: #908160)
+
+ -- Ritesh Raj Sarraf <rrs@debian.org>  Fri, 05 Oct 2018 11:31:19 +0530
+
+open-iscsi (2.0.874-5) unstable; urgency=high
+
+  * [aeb86f7] Fix multiple security issues in iscsiuio. (CVE-2017-17840)
+    (Closes: #885021)
+
+ -- Christian Seiler <christian@iwakd.de>  Sat, 23 Dec 2017 11:30:44 +0100
+
+open-iscsi (2.0.874-4) unstable; urgency=medium
+
+  * [0347300] initramfs: populate PROTO= entry in /run/net-*.conf from iBFT
+    (Closes: #866213)
+
+ -- Christian Seiler <christian@iwakd.de>  Sun, 02 Jul 2017 18:01:09 +0200
+
+open-iscsi (2.0.874-3) unstable; urgency=medium
+
+  * [e506ea0] udeb: don't update initramfs when iSCSI is not used.
+    (Closes: #863435)
+
+ -- Christian Seiler <christian@iwakd.de>  Sun, 18 Jun 2017 22:01:22 +0200
+
+open-iscsi (2.0.874-2) unstable; urgency=medium
+
+  [ Christian Seiler ]
+  * Upload to sid.
+  * [dfc0d4a] Add some information about hardware offloading to README.Debian.
+  * [e5e3428] Properly dismantle dm-crypt devices on shutdown.
+    (Closes: #850211)
+
+  [ Andrew Patterson ]
+  * [dafd2de] Use /run/initramfs/iscsiuio.pid for pid file in initramfs
+  * [68f161f] Add iscsuio dependent libgcc_s library to debian initramfs
+    (Closes: #850060)
+  * [62f0717] Add Chelsio offload modules to initramfs
+  * [c1d67ee] Revert "Don't ignore offloading NICs in iscsistart."
+  * [b61d8ba] iscsiuio must be present to use hardware offload for bnx2x
+  * [fda3118] Move iscsistart offload discovery/setup to fw_get_targets()
+  * [397d886] Fix iscsiuio long options
+  * These changes make it possible to have the root filesystem on an iSCSI
+    volume and boot the system using hardware offloading.
+
+ -- Christian Seiler <christian@iwakd.de>  Wed, 25 Jan 2017 13:12:44 +0100
+
+open-iscsi (2.0.874-2~exp1) experimental; urgency=medium
+
+  * [c451bcf] debian/tests: drop specific sysvinit tests, assume testbed
+    setup for that instead.
+  * [f65cf91] debian/tests/find_free_ip.py: fix error when processing
+    empty lines in /etc/resolv.conf.
+  * [02c3051] Don't ignore offloading NICs in iscsistart. (Closes: #850057)
+  * [e47af5b] Add support for iscsiuio offloading to the initramfs.
+    (Closes: #850060)
+  * [9ab14bb] Build with -DOFFLOAD_BOOT_SUPPORTED for rootfs on offloaded
+    iSCSI.
+
+ -- Christian Seiler <christian@iwakd.de>  Wed, 04 Jan 2017 19:00:08 +0100
+
+open-iscsi (2.0.874-1) unstable; urgency=medium
+
+  [ Christian Seiler ]
+  * [cfea3bc] New upstream version 2.0.874
+  * [b0bf3f3] debian/patches: drop patches applied upstream
+  * [6699561] debian/control: add lsb-base dependency for init script
+  * [8ede6f7] debian/tests: use targetcli-fb for nested tests
+  * [b7ba04a] debian/tests: bump Depends of autopkgtest, due to use of new
+    features
+  * [6f37806] debian/rules: explicitly regenerate lexers/parsers during
+    build
+
+  [ Frank Fegert ]
+  * [6004a7e] umountiscsi.sh: properly detect iSCSI disks from offloaded
+    sessions
+
+ -- Christian Seiler <christian@iwakd.de>  Sat, 29 Oct 2016 17:44:00 +0200
+
+open-iscsi (2.0.873+git2.f951a06b-1) unstable; urgency=medium
+
+  * [ace9f2a] New upstream version 2.0.873+git2.f951a06b
+        * Fix locking issue in iscsiuio
+        * iscsiadm: fix parallel rescan handling of exit codes
+        * Better TCP connection error handling
+  * [6a4ba6a] debian/patches: rebase onto new upstream version
+  * [d05fe0e] Only deactivate LVM VGs we're supposed to. (Closes: #836135)
+  * [3b387b7] debian/patches/bugfixes/additional-spelling.patch:
+    fix some more typos
+
+ -- Christian Seiler <christian@iwakd.de>  Sun, 18 Sep 2016 12:06:11 +0200
+
+open-iscsi (2.0.873+git1.4c1f2d90-2) unstable; urgency=medium
+
+  * [5a7879c] remove debian/source/local-options
+  * [f5d5cbb] Temporarily build udeb without libmount (Closes: #834241)
+  * [520129b] open-iscsi-udeb: update initramfs after copying
+    configuration to target system
+
+ -- Christian Seiler <christian@iwakd.de>  Mon, 22 Aug 2016 08:31:02 +0200
+
+open-iscsi (2.0.873+git1.4c1f2d90-1) unstable; urgency=medium
+
+  * Upload to sid.
+  * [0f85c07] debian/copyright: add copyright information for debian/* and
+    debian/patches/* (accidentally dropped when converting to DEP-5)
+  * [fc39696] debian/control: tighten libisns-dev dependency to >= 0.96-4~
+    (open-isns renamed the library udeb, this ensures that the new name
+    will be picked up.)
+  * [60d3f4a] iscsiuio: fix reproducibility issues (build date)
+  * [328a368] debian/gbp.conf: don't specify experimental branch anymore
+  * [d44c9d4] debian/extra/activate-storage.sh: work around race condition
+    against the kernel scanning for partitions (Closes: #833917)
+
+ -- Christian Seiler <christian@iwakd.de>  Fri, 12 Aug 2016 22:57:55 +0200
+
+open-iscsi (2.0.873+git1.4c1f2d90-1~exp1) experimental; urgency=medium
+
+  * [16ff653] New Upstream version 2.0.873+git1.4c1f2d90
+    (Closes: #627908)
+  * [313215d] debian/watch, debian/control: new upstream URIs
+  * [0930362] debian/patches: rebase on current git master,
+    drop upstream-applied patches
+  * [466d970] Link against non-OpenSSL-variant of libisns
+    (GPL vs. OpenSSL license)
+  * [6cf412f] debian/control: add Build-Depends of new upstream version
+  * [147b55b] debian/control: use cgit instead of gitweb for Vcs-Browser
+  * [49dd8a2] debian/rules: simplify due to upstream build system
+    improvements
+  * [533a744] debian/rules: add dh_... --remaining-packages where
+    appropriate
+  * [9ae0be5] remove obsolete files (debian/*.modules{,.in})
+  * [7236298] debian/*: improve readability via wrap-and-sort
+  * [c68d51f] don't run make clean in kernel/ subdir
+  * [607f4d1] debian/gbp.conf: switch to experimental branch
+  * [a3b1a24] README.Debian: fix spelling error
+  * [d1cdd8e] cherry-pick upstream PR #17 (spelling fixes)
+  * [fd0f467] cherry-pick upstream PR #16 (man warnings)
+  * [c55b9c2] cherry-pick upstream PR #13 (typo)
+  * [4786175] cherry-pick upstream PR #2 (typo)
+  * [3e79826] additional spelling fixes (found by lintian)
+  * [ee0a6a5] Add iscsiuio binary package (Closes: #699240)
+  * [ad61aa0] debian/docs: install additional upstream docs
+  * [419e1b6] debian/copyright: move to DEP-5 style format
+  * [768632b] TODO.Debian: remove resolved issues
+  * [17767e9] Add autopkgtest functionality tests.
+
+ -- Christian Seiler <christian@iwakd.de>  Fri, 29 Jul 2016 19:32:25 +0200
+
+open-iscsi (2.0.873+git0.3b4b4500-15) unstable; urgency=medium
+
+  [ Christian Seiler ]
+  * [ec1cc4b] debian/control: Use Arch: linux-any instead of Arch: any
+  * [2f35aeb] open-iscsi-udeb: drop Depends: libnss-files-udeb
+    (Closes: #819685)
+  * [2af4f32] debian/control: Bump Standards-Version to 3.9.8.
+    (No changes.)
+
+  [ Adriano Rafael Gomes ]
+  * [8b8eb17] Add Brazilian Portuguese debconf translation.
+    (Closes: #824339)
+
+ -- Christian Seiler <christian@iwakd.de>  Fri, 20 May 2016 09:52:46 +0200
+
+open-iscsi (2.0.873+git0.3b4b4500-14) unstable; urgency=medium
+
+  [ Christian Seiler ]
+  * [7ec2450] debian/control: fix typo in Vcs-Git field
+  * [b98ca63] debian/control: bump Standards-Version to 3.9.7
+
+  [ Mathieu Trudel-Lapierre ]
+  * [f5b850a] udeb: don't generate initiator name if already present
+    (Closes: #816632)
+
+ -- Christian Seiler <christian@iwakd.de>  Thu, 03 Mar 2016 18:47:46 +0100
+
+open-iscsi (2.0.873+git0.3b4b4500-13) unstable; urgency=medium
+
+  [ Christian Seiler ]
+  * [d95ccde] initramfs: fix initramfs creation bug
+    (too many symbolic links)
+  * [f6246a8] Use triggers instead of update-initramfs
+  * [16283ac] Unconditionally add iSCSI to initramfs images
+  * [5cf584f] Support RFC 4173 root=iscsi:... format (Closes: #804162)
+  * [b12b4b9] Make sure initiatorname.iscsi isn't an obsolete conffile.
+  * [06ce1d3] Don't consider iscsiadm exit code 15 to be an error
+    (Partial-Fix-For: #809320)
+  * [481cedd] Support network autoconfiguration if iscsi_auto is used
+    (Closes: #804591)
+  * [3b3fa00] Record network device that was configured for iSCSI
+  * [508fcba] Handle the default route for iscsi_auto
+  * [64b0f31] Fix handling of multiple kept sessions on shutdown
+    (Closes: #809320)
+  * [df7259e] Fix FTBR on armhf (reproducible builds)
+
+  [ Marco d'Itri ]
+  * [d32c7c6] Create in postinst the /sbin/iscsi* compatibility symlinks.
+    (Closes: #810276)
+
+  [ Martin Pitt ]
+  * [db49787] Migrate from /var/run /run and from /var/lock to /run/lock.
+    (Closes: #810696)
+  * [1bca41d] Generate initiator name on install, not first boot.
+    (Closes: #810702) (LP: #1057635)
+
+ -- Christian Seiler <christian@iwakd.de>  Thu, 11 Feb 2016 16:35:07 +0530
+
+open-iscsi (2.0.873+git0.3b4b4500-12) unstable; urgency=low
+
+  [ Christian Perrier ]
+  * [7f5ce40] Debconf templates and debian/control reviewed by the
+    debian-l10n-english team as part of the Smith review project.
+    (Closes: #797860)
+
+  [ Debconf translation updates ]
+  * [bfd526f] Czeck (Michal Simunek). (Closes: #801127)
+  * [dbc83a6] French (Julien Patriarca). (Closes: #801181)
+  * [dcc7c4d] Russian (Yuri Kozlov). (Closes: #801625)
+  * [04acc7f] Spanish (Camaleón). (Closes: #801686)
+  * [dfd68ca] Dutch (Frans Spiesschaert). (Closes: #801706)
+  * [cd920e1] Portuguese (Américo Monteiro). (Closes: #801731)
+  * [ff0c87f] Italian (Beatrice Torracca). (Closes: #801875)
+  * [df6eb44] Danish (Joe Hansen). (Closes: #801888)
+  * [d51bf4a] German (Chris Leick). (Closes: #801903)
+
+  [ Christian Seiler ]
+  * [c030d08] Call startup-checks.sh as ExecStartPre= from
+    iscsid.service. (Fix regression in -10.)
+  * [3d41a1e] Use invoke-rc.d start and not restart upon initial
+    installation. (Fix regression in -10.)
+  * [1e94bfd] Add simple autopkgtests. (Closes: #710148)
+
+ -- Christian Seiler <christian@iwakd.de>  Mon, 19 Oct 2015 23:46:01 +0200
+
+open-iscsi (2.0.873+git0.3b4b4500-11) unstable; urgency=low
+
+  [ Christian Seiler ]
+  * [320f3d8] boot: wait long enough for multipath to create mappings
+  * [745f06e] Hook up native services to sysinit.target instead of
+    remote-fs.target. Thanks to Felipe Sateler for bringing this to our
+    attention
+
+ -- Christian Seiler <christian@iwakd.de>  Sat, 29 Aug 2015 13:39:52 +0530
+
+open-iscsi (2.0.873+git0.3b4b4500-10) unstable; urgency=low
+
+  [ Christian Seiler ]
+  * [553ee17] Move binaries from /usr to /.
+  * [b4da874] Add lintian overrides for iscsid.conf permissions
+    being 0600.
+  * [4f33a8d] Patch build system to fully respect Debian build flags.
+    (Closes: #764409)
+  * [295ee0b] Remove obsolete /var/lib/open-iscsi directory.
+  * [e86e5c1] postinst: Move startup of daemon after auto-generated
+    debhelper commands
+  * [4d05783] Move umountiscsi.sh to /lib/open-iscsi.
+  * [deb3533] Rewrite umountiscsi.sh, make it more robust
+    (Closes: #775838)
+  * [9ffbe41] Improve shutdown logic and auto-exclude vital sessions
+    from logout
+  * [592d3d1] Factor out startup logic from init script
+  * [6947cef] Explain old behavior of postinst in form of comments.
+  * [f84a986] Restart iscsid on upgrades, separate init scripts.
+    (Closes: #501321)
+  * [421400b] Prompt before removing if sessions are still active.
+  * [c703bad] debconf: use po-debconf to make warnings and notices
+    translateable.
+  * [3b03a6c] prerm: warn the user about downgrades that will
+    definitely break the system
+  * [62e90af] Add NEWS file to describe the most important changes
+    for administrators.
+  * [1d53892] postrm: remove /etc/iscsi database on purge
+  * [62c0cd2] Add native systemd service files
+  * [dafe2e3] Add TODO.Debian
+  * [13bd86a] Update changelog for release.
+
+  [ Ritesh Raj Sarraf ]
+  * [9bcebd0] Use standard pathfind from Debian policy manual
+    in postinst
+
+ -- Christian Seiler <christian@iwakd.de>  Thu, 20 Aug 2015 21:13:32 +0200
+
+open-iscsi (2.0.873+git0.3b4b4500-9) unstable; urgency=medium
+
+  [ Christian Seiler ]
+  * [38e441e] Re-add debian/gbp.conf to reflect packaging workflow.
+  * [3ea6875] Rework packaging to use dh(1). (Closes: #777602, #784092)
+  * [0ce99fa] Explain why the list of architectures for the udeb is restricted.
+
+  [ Ritesh Raj Sarraf ]
+  * [e6bc6a0] Drop previous (inactive) maintainers and add Christial Seiler
+    as a New Maintainer
+  * [b6bd4fe] Migrate from old style gbp config
+
+ -- Ritesh Raj Sarraf <rrs@debian.org>  Wed, 13 May 2015 15:35:04 +0530
+
+open-iscsi (2.0.873+git0.3b4b4500-8) unstable; urgency=medium
+
+  * [e707e75] Exclude iscsid.conf from dh_fixperms. (Closes: #735773)
+
+ -- Christian Seiler <christian@iwakd.de>  Tue, 10 Feb 2015 18:00:54 +0100
+
+open-iscsi (2.0.873+git0.3b4b4500-7) unstable; urgency=medium
+
+  [ Ritesh Raj Sarraf ]
+  * [8ed5fd2] Revert changes introduced in 2.0.873+git0.3b4b4500-5
+
+  [ Christian Seiler ]
+  * [cea864b] Clean up sysvinit ordering w.r.t. NFS.
+  * [9097d07] Remove debian/gbp.conf again (change doesn't fit release
+    criteria).
+
+ -- Christian Seiler <christian@iwakd.de>  Mon, 09 Feb 2015 16:32:52 +0100
+
+open-iscsi (2.0.873+git0.3b4b4500-6) unstable; urgency=medium
+
+  [ Christian Seiler ]
+  * Replace $remote_fs from Should-Start/Stop in init script with
+    $local_fs and mountnfs-bootclean. (Breaks ordering cycle on
+    systemd systems.)
+  * Create systemd drop-in to create Before-dependency on
+    remote-fs-pre.target and run umountiscsi.sh on stop.
+
+ -- Ritesh Raj Sarraf <rrs@debian.org>  Sat, 31 Jan 2015 11:47:18 +0530
+
+open-iscsi (2.0.873+git0.3b4b4500-5) unstable; urgency=medium
+
+  [ Christian Seiler ]
+  * Create systemd unit, make it order before remote-fs-pre.target to
+    fix hang at boot. Unit currently only starts init script.
+  * Manually start umountiscsi.sh in open-iscsi init script to make
+    the stop action on shutdown not be a noop. (systemd tracks service
+    state)
+  * Add dh-systemd to build-deps.
+  * Reorder #DEBHELPER# in postinst to not break upgrades (dh-systemd's
+    code has to be there before invoke-rc.d is called).
+
+  [ Ritesh Raj Sarraf ]
+  * [fa0ce1c] Install iscsid.conf with permission 600 (Closes: #735773)
+  * [eeb3e90] Don't wait in detecting disks when run under systemd.
+    Thanks to Christian Seiler (Closes: #775778)
+  * [641f3ee] Add gbp.conf
+  * [cff497b] Add iscsi.service as an Alias
+
+ -- Ritesh Raj Sarraf <rrs@debian.org>  Mon, 26 Jan 2015 13:04:33 +0530
+
+open-iscsi (2.0.873+git0.3b4b4500-4) unstable; urgency=medium
+
+  * [41c7eca] Introduce new architectures based on current build
+    status of the Debian Installer (Closes: #759817)
+
+ -- Ritesh Raj Sarraf <rrs@debian.org>  Mon, 01 Sep 2014 14:32:59 +0530
+
+open-iscsi (2.0.873+git0.3b4b4500-3) unstable; urgency=medium
+
+  * [56e20ac] Revert "Add patch to enable fsck, mount and swap
+    for network block devices"
+  * [517546c] Handle network swap devices (blocks) (Closes: #756843)
+
+ -- Ritesh Raj Sarraf <rrs@debian.org>  Wed, 20 Aug 2014 19:08:39 +0530
+
+open-iscsi (2.0.873+git0.3b4b4500-2) unstable; urgency=medium
+
+  [ Philipp Hug ]
+  * [b517ebb] Start open-iscsi after installation and make sure
+    initiatorname is generated.
+
+  [ Ritesh Raj Sarraf ]
+  * [7e1ae42] Add patch to enable fsck, mount and swap for network
+    block devices. Thanks to Turbo Fredriksson (Closes: #736349)
+  * [92ac387] Don't prematurely exit when encountering targets with
+    no block device. Thanks to Sammy Atmadja (Closes: #745708)
+  * [7363428] Add autotools-dev for updated config.{sub,guess}. Also add
+    dh-autoreconf in build-depends to support new architectures.
+    Thanks to Chen Baozi <baozich@gmail.com> and Wookey (Closes: 750610)
+
+ -- Ritesh Raj Sarraf <rrs@debian.org>  Thu, 26 Jun 2014 13:05:48 +0530
+
+open-iscsi (2.0.873+git0.3b4b4500-1) unstable; urgency=low
+
+  * [53a1224] Fix typo in README.
+    Thanks to Jim Paris (Closes: #693559)
+  * [1fcfdb8] Imported Upstream version 2.0.873+git0.3b4b4500
+    (Closes: #722562)
+  * [2280fc1] Refresh Patches
+  * [ca1c9b9] Enable standard hardening knobs
+  * [d73fe1e] Drop patch -03_hardened-build-flags.patch
+  * [4599ae0] Update Vcs links
+  * [728c154] Try harder to determine an iSCSI block device.
+    Thanks to Dennis Leeuw, Philip Freeman (Closes: #691732)
+  * [1b68764] Call udev to settle so that network device is available.
+    Thanks to Jim Paris (Closes: #693558)
+  * [2478ad6] Don't allow iscsid to get killed during shutodown.
+    Thanks to Wakko Warner (Closes: #700762)
+
+ -- Ritesh Raj Sarraf <rrs@debian.org>  Tue, 05 Nov 2013 21:45:47 +0530
+
+open-iscsi (2.0.873-3) unstable; urgency=low
+
+  * [4939401] Fix build to install udeb stuff only on supported architectures
+
+ -- Ritesh Raj Sarraf <rrs@debian.org>  Wed, 27 Jun 2012 22:36:05 +0530
+
+open-iscsi (2.0.873-2) unstable; urgency=low
+
+  * [0019fa9] Restrict architecture for the udeb package as its dependency,
+    scsi-modules, is not available on all the architecture paltforms
+
+ -- Ritesh Raj Sarraf <rrs@debian.org>  Tue, 26 Jun 2012 18:54:17 +0530
+
+open-iscsi (2.0.873-1) unstable; urgency=low
+
+  * [53943f2] Load iscsi_ibft module to allow target session over iBFT.
+    Thanks to JOORIS Emmanuel (Closes: #672122)
+  * [ca41744] Delete old obsolete patches
+  * [01a54bf] Drop old manpages already available upstream
+  * [caf884c] ship upstream manpages for iscsi-iname and iscsistart
+  * [a983848] Imported Upstream version 2.0.873
+
+ -- Ritesh Raj Sarraf <rrs@debian.org>  Mon, 21 May 2012 23:54:53 +0530
+
+open-iscsi (2.0.872+git0.6676a1cf-2) unstable; urgency=low
+
+  * Upload to unstable
+  * [cb80472] Fix default iscsid path in config file.
+    Thanks to Michal Suchanek (Closes: #650221)
+
+ -- Ritesh Raj Sarraf <rrs@debian.org>  Tue, 24 Apr 2012 09:41:08 +0530
+
+open-iscsi (2.0.872+git0.6676a1cf-1) experimental; urgency=low
+
+  [ Ritesh Raj Sarraf ]
+  * New Upstream git snapshot (Closes: #645752)
+  * [ce26f7c] Imported Upstream version 2.0.872+git0.6676a1cf
+  * [9ad08d7] also include iscsitart in the udeb
+  * [bc79ad2] refresh patch debian/patches/spelling-error-fixes.patch
+  * [0286328] refresh patch 004_make-iscsistart-a-dynamic-binary.patch
+  * [360a509] Drop patches:
+    + iscsi-dont-build-with-ssl.patch and
+    + disable-isns-security.patch
+  * [350db4d] rename and reorder patches
+  * [794fa4f] Package-Type is now an understood feild by dpkg
+  * [593f187] Add hardened build flags.
+    Thanks to Moritz Muehlenhoff (Closes: #659662)
+  * [cf4c6c3] Kill iscsid processes properly, on stop.
+    Thanks to Gwendal Grignou (Closes: #665966)
+  * [f1a9d2f] linitan fixes for spelling errors and manpage hyphen errors
+  * [a8560c8] add and fix lsb headers for init files
+
+  [ Colin Watson ]
+  * [156b745] open-iscsi: add a udeb (Closes: #635161)
+
+ -- Ritesh Raj Sarraf <rrs@debian.org>  Sat, 07 Apr 2012 21:02:37 +0530
+
+open-iscsi (2.0.872-2) unstable; urgency=low
+
+  * Upload to unstable
+
+ -- Ritesh Raj Sarraf <rrs@debian.org>  Wed, 14 Sep 2011 14:26:00 +0530
+
+open-iscsi (2.0.872-1) experimental; urgency=low
+
+  * New Upstream Release
+  * [cccd5a9] Use udevadm to check for existense of udev.
+    Thanks to Marco d'Itri (Closes: #622209)
+  * [ddb81e4] Drop patches, merged upstream
+  * [25aa1d9] disable security and slp support
+  * [89b2a6a] Add patch to disable ssl.
+    Thanks to Mike Christie
+  * [d70e88a] Refresh patch
+  * [b501aec] delete debian/patches/disable-isns.patch
+  * [2cc67f7] spelling-error and hyphentation fixes
+  * [b886116] Bump Standards Version to 3.9.2
+  * [405ecfd] add autotools-dev to build-dep to ensure we have no stale
+    configure scripts
+
+ -- Ritesh Raj Sarraf <rrs@debian.org>  Fri, 26 Aug 2011 16:21:38 +0530
+
+open-iscsi (2.0.871.3-6) unstable; urgency=low
+
+  * [87c440c] fix gcc 4.6 build failure (Closes: #625152)
+
+ -- Ritesh Raj Sarraf <rrs@debian.org>  Tue, 03 May 2011 00:22:07 +0530
+
+open-iscsi (2.0.871.3-5) unstable; urgency=low
+
+  * Last upload was incorrect. Really upload to unstable
+
+ -- Ritesh Raj Sarraf <rrs@debian.org>  Sat, 12 Feb 2011 02:00:34 +0530
+
+open-iscsi (2.0.871.3-4) unstable; urgency=low
+
+  * Reupload to unstable
+
+ -- Ritesh Raj Sarraf <rrs@debian.org>  Thu, 10 Feb 2011 20:17:07 +0530
+
+open-iscsi (2.0.871.3-3) experimental; urgency=low
+
+  * Install iscsid.conf with 0600 permission as it can contain passwords
+    (Closes: #472965)
+  * Provide an example for iSCSI root installation (Closes: #492358)
+  * Add support to enable multiple session to the iSCSI Target in the
+    initramfs. Thanks to Norbert Tretkowski for the patch.
+    (Closes: #598773)
+  * Add patch to support NICs that have native iSCSI support. Thanks to
+    Bjoern Metzdorf for the patch. (Closes: #514924)
+  * cherry pick commit f0b670c0 from upstrem (Closes: #603990)
+  * Bump Standards Version (No changes required)
+
+ -- Ritesh Raj Sarraf <rrs@debian.org>  Wed, 05 Jan 2011 13:43:42 +0545
+
+open-iscsi (2.0.871.3-2) unstable; urgency=low
+
+  * Break down and add quilt patches
+    + 003_Fix-CVE-2009-1297.patch
+    + 004_make-iscsistart-a-dynamic-binary.patch
+  * Add some explanation about initiatorname.iscsi into README.Debian
+    (Closes: #507003)
+  * Fix double variable assignment in initramfs.local-top. Thanks to Aurelien
+    Jarno (Closes: #576786)
+  * Document the odd hang behavior during iSCSI login phase when using 32 bit
+    open-iscsi with 64 bit kernel
+  * Change address to my official Debian address and remove the DMUA flag
+  * Handle iSCSI LVM devices and devices marked _netdev (Closes: #498616)
+  * Switch to 3.0 (quilt) source format
+
+ -- Ritesh Raj Sarraf <rrs@debian.org>  Fri, 11 Jun 2010 12:33:02 +0530
+
+open-iscsi (2.0.871.3-1) unstable; urgency=low
+
+  * New upstream release (Closes: #564012, #566511)
+  * When open-iscsi service is asked to stop, attempt to umount all iSCSI
+    devices. On failure, bail out (Closes: #501580, #499126)
+  * Add debian/source/format specifying the current source format
+
+ -- Ritesh Raj Sarraf <rrs@researchut.com>  Wed, 24 Mar 2010 21:44:38 +0530
+
+open-iscsi (2.0.871-1) unstable; urgency=low
+
+  [ Guido Günther ]
+  * Imported Upstream version 2.0.871
+
+  [ Ritesh Raj Sarraf ]
+  * New Upstream Release - 2.0.871
+    (Closes: #424642)
+  * Fix credential passing in local-top/initramfs.local-top
+    (Closes: #550012, #525053)
+  * Fix settling of devices in initramfs (Closes: #501582, #488999)
+  * Update Standards-Version to 3.8.4
+  * Change to team maintenance
+  * Add git-orig-source target
+  * Add debian/watch file
+  * Add README.source file
+  * Add quilt patches
+  * Add Vcs headers
+  * Update debhelper to v7
+  * Update copyright information
+  * Improve description (Closes: #504707)
+  * Stop umountiscsi and open-iscsi in runlevel 1
+  * Remove already obsolete disabled-install-indep target
+  * Replace deprecated dh_clean -k with dh_prep
+  * Refresh 001_manpages_fixes.patch
+  * Fix copyright and explain packaging licensing
+  * Fix "undefined reference to strl* when building iscsid"
+  * Proper sanity check in the init script for empty strings
+    (Closes: #501319)
+  * Provide init script service with the same name
+  * Build iscsistart as a dynamic binary
+
+ -- Ritesh Raj Sarraf <rrs@researchut.com>  Sat, 06 Feb 2010 20:28:23 +0530
+
+open-iscsi (2.0.870~rc3-0.6) unstable; urgency=low
+
+  * Non-maintainer upload.
+  * [4bfddee] Fix CVE-2009-1297 (Closes: #547011) - thanks to Colin Watson for
+    the patch
+
+ -- Guido Günther <agx@sigxcpu.org>  Sat, 23 Jan 2010 17:56:18 +0100
+
+open-iscsi (2.0.870~rc3-0.5) unstable; urgency=low
+
+  * Non-maintainer upload to fix release goal.
+  * Fix incorrect provides and dependencies in init.d script (Closes:
+    #541390).
+  * Add missing package dependency on udev.  Rewrite init.d script to use
+    'udevadm settle' instead of obsolete 'udevsettle' (Closes: #517225).
+  * No longer ignore errors in the postinst.  Tip from lintian.
+  * Do not start open-iscsi init.d script during package installation,
+    to avoid installation problem (Closes: #529280).
+
+ -- Petter Reinholdtsen <pere@debian.org>  Sun, 13 Sep 2009 20:25:49 +0200
+
+open-iscsi (2.0.870~rc3-0.4) unstable; urgency=medium
+
+  * Clean up diff.gz, it downgraded the package to 2.0.869.2.
+    (closes: #507496)
+
+ -- Norbert Tretkowski <nobse@debian.org>  Thu,  8 Jan 2009 11:19:23 +0100
+
+open-iscsi (2.0.870~rc3-0.3) unstable; urgency=low
+
+  * Non-maintainer upload.
+  * Do not exit with return code 1 in init script, because it breaks
+    upgrades and is a policy violation (Closes: #503070)
+
+ -- Patrick Schoenfeld <schoenfeld@debian.org>  Mon, 27 Oct 2008 10:21:17 +0100
+
+open-iscsi (2.0.870~rc3-0.2) unstable; urgency=low
+
+  * Non-maintainer upload.
+  * Drop patch from iscsistart.c which breaks booting from iscsi.
+    (closes: #499508)
+  * Drop patch from version.h which adds an outdated upstream version
+    number.
+
+ -- Norbert Tretkowski <nobse@debian.org>  Fri, 10 Oct 2008 10:46:56 +0200
+
+open-iscsi (2.0.870~rc3-0.1) unstable; urgency=low
+
+  * Non-maintainer upload.
+  * New upstream release
+    - Adds support for Linux 2.6.26 (Closes: #499508)
+  * Fix ">&" redirection bashism in open-iscsi initscript.
+
+ -- Chris Lamb <lamby@debian.org>  Tue, 30 Sep 2008 21:40:27 +0100
+
+open-iscsi (2.0.869.2-2.1) unstable; urgency=medium
+
+  * Non-maintainer upload.
+  * Fix bashism in debian/rules (Closes: #484427)
+    - Move upstream URL to Homepage field.
+    - Bump Standards-Version to 3.8.0.
+
+ -- Chris Lamb <chris@chris-lamb.co.uk>  Fri, 11 Jul 2008 23:20:18 +0100
+
+open-iscsi (2.0.869.2-2) unstable; urgency=low
+
+  * Revert if-up.d approach for logging into automatic targets; just
+    start open-iscsi at rcS.d/S45, and mount _netdev filesystems when
+    open-iscsi is started.
+  * Call udevsettle before mounting
+
+ -- Philipp Hug <debian@hug.cx>  Mon, 12 May 2008 12:48:49 +0200
+
+open-iscsi (2.0.869.2-1) unstable; urgency=low
+
+  * New upstream release
+
+ -- Philipp Hug <debian@hug.cx>  Mon, 12 May 2008 11:56:30 +0200
+
+open-iscsi (2.0.869~rc4-1) experimental; urgency=low
+
+  * init script: If /sys is not mounted return without error
+    (Closes: #470434, #423368)
+  * Merged changes by Andrew Moise <chops@demiurgestudios.com>
+  * Adding Andrew as Co-Maintainer
+  * New upstream release (Closes: #474167)
+  * Added flex and bison build-depends
+  * Fixed up init scripts to attempt to handle automatic mounting and
+    unmounting properly (Closes: #423851, #438542)
+  * Added /etc/network/if-up.d/000open-iscsi to start automatic targets
+  * Parameterized /etc/iscsi/initiatorname.iscsi in init script,
+    correcting one place where it still said /etc/initiatorname.iscsi
+  * Updated README.Debian
+  * Include iscsistart for use in initramfs (Closes: #419408)
+  * Add initramfs scripts to make iSCSI root easy
+  * Based on patch by Guido Guenther <agx@sigxcpu.org>
+
+ -- Philipp Hug <debian@hug.cx>  Sat, 12 Apr 2008 15:53:12 +0200
+
+open-iscsi (2.0.865-1) unstable; urgency=low
+
+  * New upstream release
+  * Removed iscsi-iname patch as it's now included in upstream
+  * Moved initiatorname.iscsi to /etc/iscsi/initiatorname.iscsi
+
+ -- Philipp Hug <debian@hug.cx>  Sat, 16 Jun 2007 12:31:05 +0200
+
+open-iscsi (2.0.730-1) unstable; urgency=low
+
+  * Reverted to upstream init script + patches (Closes: #397363 #401579)
+  * Removed libdb dependency
+  * Create /etc/iscsi
+  * Integrated NMU changes from Martin Zobel-Helas
+     + New Upstream Release (Closes: #397636)
+     + Made /var/lib/open-iscsi 0700 (Closes: #398733)
+     + change #define INITIATOR_NAME_FILE to /etc/initiatorname.iscsi
+       in usr/initiator.h
+     + Fix package description (Closes: #380162)
+
+ -- Philipp Hug <debian@hug.cx>  Wed,  6 Dec 2006 20:22:30 +0100
+
+open-iscsi (1.0.485-4) unstable; urgency=low
+
+  * Removed bash-ism from init script
+  * Added hint about autostart to README.Debian
+  * Improved description a bit (Closes: #380162)
+
+ -- Philipp Hug <debian@hug.cx>  Mon, 21 Aug 2006 19:55:40 +0200
+
+open-iscsi (1.0.485-3) unstable; urgency=low
+
+  * Added description to man page
+
+ -- Philipp Hug <debian@hug.cx>  Sun, 23 Jul 2006 19:08:48 +0200
+
+open-iscsi (1.0.485-2) unstable; urgency=low
+
+  * Moved package to unstable
+  * Removed unused section in control
+  * Updated Standards-Version to 3.7.2.1
+  * Added INIT INFO section to init script to make it lsb compliant
+  * Removed unusued lines in rules
+  * Added man page for iscsi-iname
+
+ -- Philipp Hug <debian@hug.cx>  Sat, 22 Jul 2006 19:45:35 +0200
+
+open-iscsi (1.0.485-1) experimental; urgency=low
+
+  * Install iscsid.conf in /etc/iscsid.conf instead of /etc/iscsid.conf-example
+
+ -- Philipp Hug <debian@hug.cx>  Tue, 27 Jun 2006 14:42:20 +0200
+
+open-iscsi (1.0.485-0unreleased) dapper; urgency=low
+
+  * Initial Release (closes: Bug#333695)
+  * Updated init script
+  * Automatically generate iscsi initiator name
+  * Use Debian specific initator name prefix
+  * Put database into /var/lib/open-iscsi
+
+ -- Philipp Hug <debian@hug.cx>  Mon,  6 Mar 2006 19:20:17 +0000
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/control b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/control
new file mode 100644 (file)
index 0000000..45debe4
--- /dev/null
@@ -0,0 +1,152 @@
+Source: open-iscsi
+Section: net
+Priority: optional
+Maintainer: Debian iSCSI Maintainers <open-iscsi@packages.debian.org>
+Uploaders: Ritesh Raj Sarraf <rrs@debian.org>,
+           Christian Seiler <christian@iwakd.de>,
+           Chris Hofstaedtler <zeha@debian.org>
+Build-Depends: bison,
+               bzip2,
+               debhelper-compat (= 13),
+               dh-exec,
+               dpkg-dev (>= 1.19),
+               flex,
+               libisns-dev,
+               libmount-dev,
+               pkg-config,
+               libkmod-dev,
+               libsystemd-dev,
+               libssl-dev
+Standards-Version: 4.5.1
+Vcs-Git: https://salsa.debian.org/linux-blocks-team/open-iscsi.git
+Vcs-Browser: https://salsa.debian.org/linux-blocks-team/open-iscsi
+Homepage: https://www.open-iscsi.com/
+Rules-Requires-Root: no
+
+Package: open-iscsi
+Architecture: linux-any
+Multi-Arch: foreign
+Depends: ${misc:Depends},
+         ${shlibs:Depends},
+         libopeniscsiusr,
+         udev
+Recommends: ${busybox:Recommends}, finalrd (>= 3)
+Pre-Depends: debconf | debconf-2.0
+Description: iSCSI initiator tools
+ The Open-iSCSI project is a high-performance, transport independent,
+ multi-platform implementation of RFC3720 iSCSI.
+ .
+ Open-iSCSI is partitioned into user and kernel parts.
+ .
+ The kernel portion of Open-iSCSI is a from-scratch code
+ licensed under GPL. The kernel part implements iSCSI data path
+ (that is, iSCSI Read and iSCSI Write), and consists of three
+ loadable modules: scsi_transport_iscsi.ko, libiscsi.ko and iscsi_tcp.ko.
+ .
+ User space contains the entire control plane: configuration
+ manager, iSCSI Discovery, Login and Logout processing,
+ connection-level error processing, Nop-In and Nop-Out handling,
+ and (in the future:) Text processing, iSNS, SLP, Radius, etc.
+ .
+ The user space Open-iSCSI consists of a daemon process called
+ iscsid, and a management utility iscsiadm.
+ .
+ This package includes a daemon, iscsid, and a management utility,
+ iscsiadm.
+
+Package: libopeniscsiusr
+Architecture: linux-any
+Depends: ${misc:Depends},
+         ${shlibs:Depends}
+Enhances: open-iscsi
+Description: iSCSI userspace library
+ The Open-iSCSI project is a high-performance, transport independent,
+ multi-platform implementation of RFC3720 iSCSI.
+ .
+ Open-iSCSI is partitioned into user and kernel parts.
+ .
+ The kernel portion of Open-iSCSI is a from-scratch code
+ licensed under GPL. The kernel part implements iSCSI data path
+ (that is, iSCSI Read and iSCSI Write), and consists of three
+ loadable modules: scsi_transport_iscsi.ko, libiscsi.ko and iscsi_tcp.ko.
+ .
+ User space contains the entire control plane: configuration
+ manager, iSCSI Discovery, Login and Logout processing,
+ connection-level error processing, Nop-In and Nop-Out handling,
+ and (in the future:) Text processing, iSNS, SLP, Radius, etc.
+ .
+ The user space Open-iSCSI consists of a daemon process called
+ iscsid, and a management utility iscsiadm.
+ .
+ This package contains the iSCSI userspace library.
+
+Package: libopeniscsiusr-dev
+Architecture: all
+Depends: ${misc:Depends},
+         libopeniscsiusr
+Enhances: open-iscsi
+Description: iSCSI userspace library headers
+ The Open-iSCSI project is a high-performance, transport independent,
+ multi-platform implementation of RFC3720 iSCSI.
+ .
+ Open-iSCSI is partitioned into user and kernel parts.
+ .
+ The kernel portion of Open-iSCSI is a from-scratch code
+ licensed under GPL. The kernel part implements iSCSI data path
+ (that is, iSCSI Read and iSCSI Write), and consists of three
+ loadable modules: scsi_transport_iscsi.ko, libiscsi.ko and iscsi_tcp.ko.
+ .
+ User space contains the entire control plane: configuration
+ manager, iSCSI Discovery, Login and Logout processing,
+ connection-level error processing, Nop-In and Nop-Out handling,
+ and (in the future:) Text processing, iSNS, SLP, Radius, etc.
+ .
+ The user space Open-iSCSI consists of a daemon process called
+ iscsid, and a management utility iscsiadm.
+ .
+ This package contains the iSCSI userspace library headers.
+
+Package: iscsiuio
+Architecture: linux-any
+Multi-Arch: foreign
+Depends: ${misc:Depends},
+         ${shlibs:Depends},
+         libopeniscsiusr,
+         udev
+Enhances: open-iscsi
+Description: iSCSI offloading daemon for QLogic devices
+ The Open-iSCSI project is a high-performance, transport independent,
+ multi-platform implementation of RFC3720 iSCSI.
+ .
+ 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').
+ .
+ This package is required to offload iSCSI onto these devices.
+
+Package: open-iscsi-udeb
+# Note: the (virtual) udeb package scsi-modules (provided by different
+#       linux kernel udebs) must exist for these architectures - so
+#       check that before adding them to this list; the other
+#       scsi-(core|common|...)-modules are NOT sufficient!
+Architecture: amd64 arm64 armhf i386 ia64 mips mipsel powerpc ppc64 ppc64el s390x
+Section: debian-installer
+Package-Type: udeb
+Depends: ${misc:Depends},
+         ${shlibs:Depends},
+         scsi-modules
+Description: Configure iSCSI
+ The Open-iSCSI project is a high-performance, transport independent,
+ multi-platform implementation of RFC3720 iSCSI.
+ .
+ This is the minimal package (udeb) used by debian-installer.
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/copyright b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/copyright
new file mode 100644 (file)
index 0000000..1f20662
--- /dev/null
@@ -0,0 +1,355 @@
+Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+
+Files: *
+Copyright: 2011, Aastha Mehta
+           2005, Alex Aizman
+           2002-2003, Ardis Technolgies <roman@ardistech.com>
+           2014-2015, Chris Leech
+           2001-2002, Cisco Systems, Inc
+           2011, Dell Inc
+           2004-2005, Dmitry Yusupov
+           2004-2005, Dmitry Yusupov, Alex Aizman
+           2004, FUJITA Tomonori <tomof@acm.org>
+           1989-1991, Free Software Foundation, Inc
+           2006-2007, IBM Corporation
+           2006-2011, Mike Christie
+           2013, QLogic Corporation
+           2014, Red Hat Inc
+           2006-2015, Red Hat, Inc
+           2006, Voltaire Ltd
+License: GPL-2+
+
+Files: Changelog
+       Makefile
+       README
+       THANKS
+       TODO
+       doc/*
+       etc/*
+       include/iscsi_err.h
+       include/iscsi_net_util.h
+       include/list.h
+       libopeniscsiusr/*
+       sysfs-documentation
+       test/README
+       test/TODO
+       test/harness/*
+       test/regression.dat
+       test/test-open-iscsi.py
+       usr/Makefile
+       usr/be2iscsi.h
+       usr/cxgbi.h
+       usr/discoveryd.h
+       usr/ethtool-copy.h
+       usr/host.h
+       usr/idbm_fields.h
+       usr/iscsi_settings.h
+       usr/iscsi_util.h
+       usr/iser.h
+       usr/log.c
+       usr/scsi.c
+       usr/scsi.h
+       usr/session_info.c
+       usr/session_info.h
+       usr/session_mgmt.h
+       usr/statics.c
+       usr/types.h
+       usr/version.h
+       utils/50-iscsi-firmware-login.rules.template
+       utils/Makefile
+       utils/iscsi_fw_login.sh.template
+       utils/sysdeps/*
+Copyright: 2000, 1 Tim Waugh <twaugh@redhat.com>
+           2002-2003, Ardis Technolgies <roman@ardistech.com>
+           2012, Dan Luedtke
+           1998, David S. Miller <davem@redhat.com>
+           1997, Eric Youngdale
+           2002, Intel <eli.kupermann@intel.com>
+           2001, Jeff Garzik <jgarzik@pobox.com>
+           2015, Lee Duncan <lduncan@suse.com>
+           1998, Michael Zucchi
+           2000, MontaVista Software, Inc
+           2005-2012, Randy Dunlap
+           2017, Red Hat, Inc
+           2001, Simon Huggins
+           2008, Sun Microsystems
+           2001, Sun Microsystems <thockin@sun.com>
+           2006, Voltaire Ltd
+License: GPL-2+
+Comment: No explicit license found, using license(s) from:
+ COPYING
+
+Files: iscsiuio/*
+Copyright: 2001, Adam Dunkels
+           2009-2011, Broadcom Corporation
+           2016, Cavium Inc
+           2014-2015, QLogic Corporation
+License: BSD-4-clause
+
+Files: libopeniscsiusr/context.c
+       libopeniscsiusr/context.h
+       libopeniscsiusr/default.c
+       libopeniscsiusr/default.h
+       libopeniscsiusr/docs/doc-preclean.pl
+       libopeniscsiusr/docs/libopeniscsiusr.h.3
+       libopeniscsiusr/idbm.c
+       libopeniscsiusr/idbm.h
+       libopeniscsiusr/idbm_fields.h
+       libopeniscsiusr/iface.c
+       libopeniscsiusr/iface.h
+       libopeniscsiusr/libopeniscsiusr/*
+       libopeniscsiusr/misc.c
+       libopeniscsiusr/misc.h
+       libopeniscsiusr/node.c
+       libopeniscsiusr/node.h
+       libopeniscsiusr/rfc.h
+       libopeniscsiusr/session.c
+       libopeniscsiusr/sysfs.c
+       libopeniscsiusr/sysfs.h
+       libopeniscsiusr/tests/test_context.c
+       libopeniscsiusr/tests/test_iface.c
+       libopeniscsiusr/tests/test_node.c
+       libopeniscsiusr/tests/test_session.c
+       libopeniscsiusr/version.h
+Copyright: 2004, Dmitry Yusupov, Alex Aizman
+           2006, Mike Christie
+           2006-2018, Red Hat, Inc
+License: GPL-3+
+
+Files: iscsiuio/AUTHORS
+       iscsiuio/ChangeLog
+       iscsiuio/Makefile.am
+       iscsiuio/NEWS
+       iscsiuio/README
+       iscsiuio/RELEASE.TXT
+       iscsiuio/iscsiuiolog
+       iscsiuio/src/Makefile.am
+       iscsiuio/src/README
+       iscsiuio/src/apps/Makefile.am
+       iscsiuio/src/apps/README
+       iscsiuio/src/apps/brcm-iscsi/Makefile.am
+       iscsiuio/src/apps/brcm-iscsi/Makefile.brcm-iscsi
+       iscsiuio/src/apps/dhcpc/Makefile.am
+       iscsiuio/src/apps/dhcpc/Makefile.dhcpc
+       iscsiuio/src/uip-1.0-changelog.txt
+       iscsiuio/src/uip/Makefile.am
+       iscsiuio/src/uip/Makefile.include
+       iscsiuio/src/uip/debug.h
+       iscsiuio/src/uip/uip_eth.h
+       iscsiuio/src/unix/Makefile.am
+       iscsiuio/src/unix/libs/Makefile.am
+Copyright: 2004-2013, Broadcom Corporation
+           2014, QLogic Corporation
+License: GPL-3+
+Comment: No explicit license found, using license(s) from:
+ iscsiuio/COPYING
+
+Files: iscsiuio/src/apps/dhcpc/dhcpc.c
+       iscsiuio/src/apps/dhcpc/dhcpc.h
+       iscsiuio/src/uip/clock.h
+       iscsiuio/src/uip/lc-addrlabels.h
+       iscsiuio/src/uip/lc-switch.h
+       iscsiuio/src/uip/lc.h
+       iscsiuio/src/uip/psock.c
+       iscsiuio/src/uip/psock.h
+       iscsiuio/src/uip/pt.h
+       iscsiuio/src/uip/timer.c
+       iscsiuio/src/uip/timer.h
+       iscsiuio/src/uip/uip-neighbor.c
+       iscsiuio/src/uip/uip-neighbor.h
+       iscsiuio/src/uip/uip.c
+       iscsiuio/src/uip/uip.h
+       iscsiuio/src/uip/uip_arch.h
+       iscsiuio/src/uip/uip_arp.c
+       iscsiuio/src/uip/uip_arp.h
+       iscsiuio/src/uip/uipopt.h
+       iscsiuio/src/unix/clock-arch.c
+       iscsiuio/src/unix/clock-arch.h
+       iscsiuio/src/unix/uip-conf.h
+Copyright: 2001-2003, Adam Dunkels
+           2004-2006, Swedish Institute of Computer Science
+License: BSD-3-clause
+
+Files: include/sysdeps.h
+       usr/sysfs.c
+       usr/sysfs.h
+       utils/sysdeps/sysdeps.c
+Copyright: 2003, Greg Kroah-Hartman <greg@kroah.com>
+           2003-2006, Kay Sievers <kay.sievers@vrfy.org>
+License: GPL-2
+
+Files: iscsiuio/configure.ac
+       iscsiuio/docs/*
+Copyright: 2004-2013, Broadcom Corporation
+           2014, QLogic Corporation
+License: GPL
+Comment: No explicit GPL version specified, using license(s) from:
+ GPL-2
+
+Files: usr/fwparam_ibft/prom_parse.tab.c
+       usr/fwparam_ibft/prom_parse.tab.h
+Copyright: 1984-2015, Free Software Foundation, Inc
+License: GPL-3+ with Bison exception
+
+Files: utils/iscsi-gen-initiatorname.sh.template
+       utils/iscsi_offload.sh
+Copyright: 2011, Hannes Reinecke, SUSE Labs
+License: GPL
+Comment: No explicit GPL version specified, using license(s) from:
+ GPL-2
+
+Files: utils/md5.c
+       utils/md5.h
+Copyright: Colin Plumb
+           Ian Jackson
+License: public-domain
+
+Files: debian/*
+License: GPL-2+
+Copyright: Debian iSCSI Maintainers
+
+License: BSD-3-clause
+ 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.
+
+License: BSD-4-clause
+ 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.
+
+License: GPL-2
+ This program is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public
+ License version 2 as published by the Free Software Foundation
+ .
+ This program is distributed in the hope that it will be
+ useful, but WITHOUT ANY WARRANTY; without even the implied
+ warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ PURPOSE.  See the GNU General Public License for more
+ details.
+ .
+ You should have received a copy of the GNU General Public
+ License along with this package; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ Boston, MA  02110-1301 USA
+ .
+ On Debian systems, the full text of the GNU General Public
+ License version 2 can be found in the file
+ `/usr/share/common-licenses/GPL-2'.
+
+License: GPL-2+
+ 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.
+ .
+ You should have received a copy of the GNU General Public
+ License along with this package; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ Boston, MA  02110-1301 USA
+ .
+ On Debian systems, the full text of the GNU General Public
+ License version 2 can be found in the file
+ `/usr/share/common-licenses/GPL-2'.
+
+License: GPL-3+
+ 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 3 of the License, or (at your option) any later
+ version.
+ .
+ This program is distributed in the hope that it will be
+ useful, but WITHOUT ANY WARRANTY; without even the implied
+ warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ PURPOSE.  See the GNU General Public License for more
+ details.
+ .
+ You should have received a copy of the GNU General Public
+ License along with this package; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ Boston, MA  02110-1301 USA
+ .
+ On Debian systems, the full text of the GNU General Public
+ License version 3 can be found in the file
+ `/usr/share/common-licenses/GPL-3'.
+
+License: GPL
+ 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 3 of the License, or
+ (at your option) any later version.
+ .
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+ .
+ You should have received a copy of the GNU General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ .
+ On Debian systems, the full text of the GNU General Public
+ License version 3 can be found in the file
+ `/usr/share/common-licenses/GPL-3'.
+
+License: GPL-3+ with Bison exception
+ As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton.  Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+ .
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison.
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/extra/activate-storage.sh b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/extra/activate-storage.sh
new file mode 100755 (executable)
index 0000000..410944f
--- /dev/null
@@ -0,0 +1,80 @@
+#!/bin/sh
+#
+# This script activates storage at boot after the iSCSI login. It can
+# be called from both the init script as well as the native systemd
+# service.
+#
+
+PATH=/sbin:/bin
+
+MULTIPATH=/sbin/multipath
+VGCHANGE=/sbin/vgchange
+
+if [ -f /etc/default/open-iscsi ]; then
+       . /etc/default/open-iscsi
+fi
+
+# See if we need to handle LVM
+if [ ! -x $VGCHANGE ] && [ -n "$LVMGROUPS" ]; then
+       echo "Warning: LVM2 tools are not installed, not honouring LVMGROUPS." >&2
+       LVMGROUPS=""
+fi
+
+# If we don't have to activate any VGs and are running systemd, we
+# don't have to activate anything, so doing udevadm settle here and
+# potentially sleeping (if multipath is used) will not be productive,
+# because after waiting for both of these things, we will do nothing.
+# Therefore just drop out early if that is the case.
+if [ -d /run/systemd/system ] && [ -z "$LVMGROUPS" ] ; then
+       exit 0
+fi
+
+# Make sure we pick up all devices
+udevadm settle || true
+
+# Work around race condition here: after udevadm settle it is
+# guaranteed that all iSCSI disks have now properly appeared, but
+# other dependent devices may not have. This can include multipath
+# mappings of iSCSI devices (multipathd will race against udev for
+# locking the underlying source block devices when it comes to
+# creating the mappings, and it will retry the lock only once per
+# second, and typically succeed only on second try), but also
+# partitions on the given disks (which the kernel scans
+# asyncronously).
+#
+# The proper way of handling this is to have LVM activation and/or
+# mounting of file systems be handled in a completely event-driven
+# manner, but that requires configuration by the sysadmin in the
+# case of LVM, and for mounting it only works with systemd at the
+# moment. For compatibility with how the package handled this
+# previously, we will work around this race for a while longer.
+
+if [ -x $MULTIPATH ] ; then
+       # 1 second is too short for multipath devices to appear,
+       # because multipathd takes more than 1s to activate them
+       # after udevadm settle is done.
+       sleep 3
+else
+       sleep 1
+fi
+udevadm settle || true
+
+# Handle LVM
+if [ -n "$LVMGROUPS" ] ; then
+       if ! $VGCHANGE -ay $LVMGROUPS ; then
+               echo "Warning: could not activate all LVM groups." >&2
+       fi
+       # Make sure we pick up all LVM devices
+       udevadm settle || true
+fi
+
+# Mount all network filesystems
+# (systemd takes care of it directly, so don't do it there)
+if ! [ -d /run/systemd/system ] ; then
+       if [ $HANDLE_NETDEV -eq 1 ] ; then
+               mount -a -O _netdev >/dev/null 2>&1 || true
+               # FIXME: should we really support swap on iSCSI?
+               #        If so, we should update umountiscsi.sh!
+               swapon -a -e >/dev/null 2>&1 || true
+       fi
+fi
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/extra/initramfs/hooks/iscsi b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/extra/initramfs/hooks/iscsi
new file mode 100755 (executable)
index 0000000..7458571
--- /dev/null
@@ -0,0 +1,41 @@
+#!/bin/sh
+
+PREREQ="udev"
+
+prereqs()
+{
+       echo "$PREREQ"
+}
+
+case $1 in
+# get pre-requisites
+prereqs)
+       prereqs
+       exit 0
+       ;;
+esac
+
+if [ -r /etc/initramfs-tools/conf.d/open-iscsi ] ; then
+       . /etc/initramfs-tools/conf.d/open-iscsi
+fi
+
+if [ x"$NO_ISCSI_IN_INITRAMFS" = x"yes" ] ; then
+       exit 0
+fi
+
+# Hooks for loading iscsi bits into the initramfs
+. /usr/share/initramfs-tools/hook-functions
+
+copy_exec /sbin/iscsistart /sbin
+cp /etc/iscsi/initiatorname.iscsi $DESTDIR/etc
+if [ -r /etc/iscsi/iscsi.initramfs ] ; then
+       cp /etc/iscsi/iscsi.initramfs $DESTDIR/etc
+fi
+
+for x in crc32c libcrc32c ib_iser iscsi_tcp libiscsi scsi_transport_iscsi iscsi_ibft; do
+       manual_add_modules ${x}
+done
+for x in cxgb3i cxgb4i; do
+       manual_add_modules ${x}
+done
+
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/extra/initramfs/hooks/iscsiuio b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/extra/initramfs/hooks/iscsiuio
new file mode 100755 (executable)
index 0000000..41df3b5
--- /dev/null
@@ -0,0 +1,35 @@
+#!/bin/sh
+
+PREREQ="udev iscsi"
+
+prereqs()
+{
+       echo "$PREREQ"
+}
+
+case $1 in
+# get pre-requisites
+prereqs)
+       prereqs
+       exit 0
+       ;;
+esac
+
+if [ -r /etc/initramfs-tools/conf.d/open-iscsi ] ; then
+       . /etc/initramfs-tools/conf.d/open-iscsi
+fi
+
+if [ x"$NO_ISCSI_IN_INITRAMFS" = x"yes" ] ; then
+       exit 0
+fi
+
+# Hooks for loading iscsi bits into the initramfs
+. /usr/share/initramfs-tools/hook-functions
+
+copy_exec /sbin/iscsiuio
+# iscsiuio needs libgcc_s library, so add it and its dependencies.
+LIBC_DIR=$(ldd /sbin/iscsiuio | sed -nr 's#.* => (/lib.*)/libc\.so\.[0-9.-]+ \(0x[[:xdigit:]]+\)$#\1#p')
+find -L "$LIBC_DIR" -maxdepth 1 -name 'libgcc_s.*' -type f | while read so; do
+       copy_exec "$so"
+done
+manual_add_modules bnx2i
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/extra/initramfs/local-bottom/iscsi b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/extra/initramfs/local-bottom/iscsi
new file mode 100755 (executable)
index 0000000..06ddc56
--- /dev/null
@@ -0,0 +1,30 @@
+#!/bin/sh
+# If iscsiuio is present in the initramfs, and it was started by us,
+# stop it again so the system iscsiuio can take over later.
+if [ -x /sbin/iscsiuio ] && [ -e /run/initramfs/iscsiuio.pid ] ; then
+       start-stop-daemon --stop --quiet --retry=TERM/10/KILL/5 \
+               --pidfile /run/initramfs/iscsiuio.pid \
+               --name iscsiuio --exec /sbin/iscsiuio || :
+fi
+
+# Remove the interface file if no disks are present
+if [ -f /run/initramfs/open-iscsi.interface ] ; then
+       found=0
+       for disk in /dev/disk/by-path/*-iscsi-*; do
+               if [ ! -e "$disk" ] ; then
+                       # If we have no matches, we stil go through the for loop once with
+                       # the pattern as a string
+                       continue
+               fi
+               if ! readlink -f "$disk" > /dev/null ; then
+                       continue
+               fi
+               found=1
+               break;
+       done
+       if [ $found = 0 ] ; then
+               rm /run/initramfs/open-iscsi.interface
+       fi
+fi
+
+exit 0
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/extra/initramfs/local-top/iscsi b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/extra/initramfs/local-top/iscsi
new file mode 100755 (executable)
index 0000000..9f3af32
--- /dev/null
@@ -0,0 +1,384 @@
+#!/bin/sh
+
+PREREQ=""
+
+prereqs()
+{
+       echo "$PREREQ"
+}
+
+case $1 in
+# get pre-requisites
+prereqs)
+       prereqs
+       exit 0
+       ;;
+esac
+
+parse_root_param ()
+{
+       target="$1"
+       auth="$2"
+       OLDIFS="$IFS"
+       IFS=":"
+       set -- $target
+       IFS="$OLDIFS"
+
+       tmp_ISCSI_TARGET_IP="$1"
+       if [ -n "$2" ] ; then
+               if [ x"$2" != x"6" ] ; then
+                       echo "Warning: unsupported protocol specified for iSCSI root parameter, assuming 6 (TCP)" >&2
+               fi
+       fi
+       tmp_ISCSI_TARGET_PORT="$3"
+       tmp_ISCSI_ROOT_LUN="$4"
+       tmp_ISCSI_TARGET_NAME="$5"
+       shift 5
+       while [ -n "$1" ] ; do
+               tmp_ISCSI_TARGET_NAME="${tmp_ISCSI_TARGET_NAME}:$1"
+               shift
+       done
+
+       if [ -z "$tmp_ISCSI_TARGET_IP" ] || [ -z "$tmp_ISCSI_TARGET_NAME" ] ; then
+               echo "Warning: empty iSCSI IP / target name currently not supported for root=iscsi:, ignoring parameter" >&2
+               return
+       fi
+
+       OLDIFS="$IFS"
+       IFS=":"
+       set -- $auth
+       IFS="$OLDIFS"
+
+       tmp_ISCSI_USERNAME=""
+       tmp_ISCSI_PASSWORD=""
+       tmp_ISCSI_IN_USERNAME=""
+       tmp_ISCSI_IN_PASSWORD=""
+
+       if [ $# -gt 4 ] ; then
+               echo "Warning: invalid authentication for root=iscsi:, ignoring" >&2
+               return
+       fi
+
+       if [ $# -gt 0 ] ; then
+               tmp_ISCSI_USERNAME="$1"
+               tmp_ISCSI_PASSWORD="$2"
+               if [ $# -gt 2 ] ; then
+                       tmp_ISCSI_IN_USERNAME="$3"
+                       tmp_ISCSI_IN_PASSWORD="$4"
+               fi
+       fi
+
+       ISCSI_TARGET_IP="$tmp_ISCSI_TARGET_IP"
+       ISCSI_TARGET_PORT="$tmp_ISCSI_TARGET_PORT"
+       ISCSI_TARGET_NAME="$tmp_ISCSI_TARGET_NAME"
+       ISCSI_ROOT_LUN="$tmp_ISCSI_ROOT_LUN"
+       if [ -n "$tmp_ISCSI_USERNAME" ] ; then
+               ISCSI_USERNAME="$tmp_ISCSI_USERNAME"
+               ISCSI_PASSWORD="$tmp_ISCSI_PASSWORD"
+       fi
+       if [ -n "$tmp_ISCSI_IN_USERNAME" ] ; then
+               ISCSI_IN_USERNAME="$tmp_ISCSI_IN_USERNAME"
+               ISCSI_IN_PASSWORD="$tmp_ISCSI_IN_PASSWORD"
+       fi
+       ISCSI_HAD_ROOT=yes
+}
+
+do_iscsi_login ()
+{
+       # Bring in the main config
+       . /conf/initramfs.conf
+       for conf in conf/conf.d/*; do
+               [ -f ${conf} ] && . ${conf}
+       done
+       . /scripts/functions
+
+       udevadm settle
+       IBFT_DHCP_DEVICE=""
+
+       if [ -n "$ISCSI_AUTO" ] ; then
+               # try to auto-configure network interface based
+               # on firmware values
+               modprobe iscsi_ibft
+               iscsistart -N
+
+               # write out /run/net-$IFACE.conf based on what
+               # was in the firmware
+               iscsistart -f | while read k eq v; do
+                       case "${k} ${eq} ${v}" in
+                       ("# BEGIN RECORD"*)
+                               DEVICE=""
+                               PROTO="none"
+                               IPV4ADDR=""
+                               IPV4NETMASK=""
+                               IPV4GATEWAY=""
+                               IPV4DNS0=""
+                               IPV4DNS1=""
+                               UPTIME="0"
+                               DHCPLEASETIME="0"
+                               DOMAINSEARCH=""
+                               continue
+                               ;;
+                       ("# END RECORD"*)
+                               if [ -n "$DEVICE" ] ; then
+                               {
+                                       echo "DEVICE='${DEVICE}'"
+                                       echo "PROTO='${PROTO}'"
+                                       echo "IPV4ADDR='${IPV4ADDR}'"
+                                       echo "IPV4BROADCAST=''"
+                                       echo "IPV4NETMASK='${IPV4NETMASK}'"
+                                       echo "IPV4GATEWAY='${IPV4GATEWAY}'"
+                                       echo "IPV4DNS0='${IPV4DNS0}'"
+                                       echo "IPV4DNS1='${IPV4DNS1}'"
+                                       echo "HOSTNAME=''"
+                                       echo "DNSDOMAIN=''"
+                                       echo "NISDOMAIN=''"
+                                       echo "ROOTSERVER=''"
+                                       echo "ROOTPATH=''"
+                                       echo "UPTIME='${UPTIME}'"
+                                       echo "DHCPLEASETIME='${DHCPLEASETIME}'"
+                                       echo "DOMAINSEARCH=''"
+                               } > "/run/net-${DEVICE}.conf.ibft"
+                               if [ "$PROTO" != "dhcp" -a "$DHCPLEASETIME" = "0" ]; then
+                                       # this is static ibft configuration.
+                                       mv "/run/net-${DEVICE}.conf.ibft" "/run/net-${DEVICE}.conf"
+                               else
+                                       IBFT_DHCP_DEVICE="$DEVICE"
+                               fi
+                               echo "${DEVICE}" > /run/initramfs/open-iscsi.interface
+                               # iscsistart -N doesn't set the default gateway. Therefore,
+                               # we need to add it ourselves. However, the ip command is
+                               # only available if we use busybox in the initramfs (it's
+                               # in open-iscsi's Recommends), so check for that.
+                               if [ -n "${IPV4GATEWAY}" ] && which ip >/dev/null 2>&1 ; then
+                                       ip route add default via "${IPV4GATEWAY}"
+                               fi
+                               fi
+                               continue
+                               ;;
+                       esac
+                       if [ "${eq}" != "=" ] ; then
+                               continue
+                       fi
+                       case "${k}" in
+                               iface.ipaddress)     IPV4ADDR="${v}" ;;
+                               iface.subnet_mask)   IPV4NETMASK="${v}" ;;
+                               iface.gateway)       IPV4GATEWAY="${v}" ;;
+                               iface.primary_dns)   IPV4DNS0="${v}" ;;
+                               iface.secondary_dns) IPV4DNS1="${v}" ;;
+                               iface.net_ifacename) DEVICE="${v}" ;;
+                               iface.bootproto)
+                                       case "${v}" in
+                                               DHCP)   PROTO="dhcp"   ;;
+                                               STATIC) PROTO="static" ;;
+                                               *)      PROTO="${v}"   ;;
+                                       esac
+                                       ;;
+                       esac
+               done
+       fi
+
+       # run configure_networking even if we have iscsi_auto, because there
+       # could be other network interfaces that need to be configured
+       # also, if we set up DHCP iBFT, we need ipconfig to run so it creates
+       # a proper /run/net-${DEVICE}.conf file that includes the DNS search
+       # domain, which we don't get in our iBFT data (see LP: #1806777)
+       configure_networking
+
+       if [ -n "$IBFT_DHCP_DEVICE" ]; then
+               if ! [ -e "/run/net-${DEVICE}.conf" ] ; then
+                       echo "WARN: ipconfig dhcp failed, using iSCSI iBFT config - DNS search domain may be missing at runtime" >&2
+                       # We have DHCP iBFT, but ipconfig DHCP failed;
+                       # so we should fallback to just using the iBFT config,
+                       # though that will not include the DNS search domain
+                       mv "/run/net-${DEVICE}.conf.ibft" "/run/net-${DEVICE}.conf"
+                       # need to re-run configure_networking to process conf file
+                       configure_networking
+               fi
+       fi
+
+       # Save network device we configured via configure_networking, but only
+       # if we didn't already get one from autoconfiguration (then we always
+       # prefer that).
+       if ! [ -e /run/initramfs/open-iscsi.interface ] ; then
+               if [ -z "${DEVICE}" ] || ! [ -e "/run/net-${DEVICE}.conf" ] ; then
+                       for i in /run/net-*.conf ; do
+                               [ -e "${i}" ] && { . "${i}" ; break ; }
+                       done
+               fi
+               if [ -n "${DEVICE}" ] ; then
+                       echo "${DEVICE}" > /run/initramfs/open-iscsi.interface
+                else
+                       for i in /run/net6-*.conf; do
+                               [ -e "${i}" ] && { . "${i}" ; break ; }
+                       done
+               fi
+               if [ -z "${DEVICE}" ] && [ -n "${DEVICE6}" ] ; then
+                       echo "${DEVICE6}" > /run/initramfs/open-iscsi.interface
+               fi
+       fi
+
+       modprobe iscsi_tcp
+       modprobe crc32c
+
+       # If iscsiuio is present in the initramfs, start it, in case UIO
+       # offloading is required.
+       if [ -x /sbin/iscsiuio ] ; then
+               start-stop-daemon --start --quiet --pidfile /run/initramfs/iscsiuio.pid \
+                                 --startas /sbin/iscsiuio --name iscsiuio \
+                                 --exec /sbin/iscsiuio -- --pid=/run/initramfs/iscsiuio.pid || :
+       fi
+
+       if [ -z $ISCSI_AUTO ]; then
+               if [ -z $ISCSI_INITIATOR ]; then
+                       . /etc/initiatorname.iscsi
+                       ISCSI_INITIATOR=$InitiatorName
+               fi
+
+               if [ -z $ISCSI_TARGET_PORT ]; then
+                       ISCSI_TARGET_PORT=3260
+               fi
+
+               if [ -z $ISCSI_TARGET_GROUP ]; then
+                       ISCSI_TARGET_GROUP=1
+               fi
+
+               iscsistart -i $ISCSI_INITIATOR -t $ISCSI_TARGET_NAME    \
+                          -g $ISCSI_TARGET_GROUP -a $ISCSI_TARGET_IP   \
+                          -p $ISCSI_TARGET_PORT \
+                          ${ISCSI_USERNAME:+-u "$ISCSI_USERNAME"}      \
+                          ${ISCSI_PASSWORD:+-w "$ISCSI_PASSWORD"}      \
+                          ${ISCSI_IN_USERNAME:+-U "$ISCSI_IN_USERNAME"}\
+                          ${ISCSI_IN_PASSWORD:+-W "$ISCSI_IN_PASSWORD"}
+       else
+               modprobe iscsi_ibft
+               iscsistart -b
+       fi
+
+       if [ -z $ISCSI_TARGET_PORT ]; then
+               ISCSI_TARGET_PORT=3260
+       fi
+
+       if [ -z $ISCSI_TARGET_GROUP ]; then
+               ISCSI_TARGET_GROUP=1
+       fi
+
+       for i in $ISCSI_TARGET_IP; do
+       iscsistart -i $ISCSI_INITIATOR -t $ISCSI_TARGET_NAME    \
+                  -g $ISCSI_TARGET_GROUP -a $i \
+                  -p $ISCSI_TARGET_PORT \
+                  ${ISCSI_USERNAME:+-u "$ISCSI_USERNAME"}      \
+                  ${ISCSI_PASSWORD:+-w "$ISCSI_PASSWORD"}      \
+                  ${ISCSI_IN_USERNAME:+-U "$ISCSI_IN_USERNAME"}\
+                  ${ISCSI_IN_PASSWORD:+-W "$ISCSI_IN_PASSWORD"}
+       done
+}
+
+parse_iscsi_ops ()
+{
+       [ -r /etc/iscsi.initramfs ] && . /etc/iscsi.initramfs
+
+       for x in $(cat /proc/cmdline); do
+               case ${x} in
+               iscsi_auto)
+                       ISCSI_AUTO=true
+                       ;;
+               iscsi_initiator=*)
+                       ISCSI_INITIATOR="${x#iscsi_initiator=}"
+                       ;;
+               iscsi_target_name=*)
+                       ISCSI_TARGET_NAME="${x#iscsi_target_name=}"
+                       ;;
+               iscsi_target_ip=*)
+                       ISCSI_TARGET_IP="${x#iscsi_target_ip=}"
+                       ;;
+               iscsi_target_port=*)
+                       ISCSI_TARGET_PORT="${x#iscsi_target_port=}"
+                       ;;
+               iscsi_target_group=*)
+                       ISCSI_TARGET_GROUP="${x#iscsi_target_group=}"
+                       ;;
+               iscsi_username=*)
+                       ISCSI_USERNAME="${x#iscsi_username=}"
+                       ;;
+               iscsi_password=*)
+                       ISCSI_PASSWORD="${x#iscsi_password=}"
+                       ;;
+               iscsi_in_username=*)
+                       ISCSI_IN_USERNAME="${x#iscsi_in_username=}"
+                       ;;
+               iscsi_in_password=*)
+                       ISCSI_IN_PASSWORD="${x#iscsi_in_password=}"
+                       ;;
+               root=iscsi:*@*)
+                       x="${x##root=iscsi:}"
+                       parse_root_param "${x#*@}" "${x%%@*}"
+                       ;;
+               root=iscsi:*)
+                       parse_root_param "${x##root=iscsi:}" ""
+                       ;;
+               esac
+       done
+}
+
+if [ ! -x /sbin/iscsistart ]; then
+       exit 0
+fi
+
+parse_iscsi_ops
+
+if ( [ -z $ISCSI_TARGET_NAME ] || [ -z $ISCSI_TARGET_IP ] ) && [ -z $ISCSI_AUTO ]; then
+       exit 0
+fi
+
+do_iscsi_login
+
+udevadm settle
+
+# The second check is to allow us to use multiple root= parameters. That way
+# one may specify root=iscsi:... root=UUID=... to mount partitions on an iSCSI
+# disk. (The latter value will overwrite the former for purposes of the main
+# initramfs scripts, but our loop that scans /proc/cmdline will still detect
+# the former and set proper parameters.
+if [ -n "$ISCSI_HAD_ROOT" ] && [ x"${ROOT##iscsi:}" != x"${ROOT}" ] ; then
+       if [ -z "$ISCSI_ROOT_LUN" ] ; then
+               ISCSI_ROOT_LUN=0
+       fi
+       found=0
+       # FIXME: RFC 4173 defines the LUN field to be more complicated and that
+       #        the same LUN may have multiple representations.
+       for disk in /dev/disk/by-path/*-iscsi-*-"${ISCSI_ROOT_LUN}" ; do
+               # Resolve device name, as the colons in the by-path name will
+               # cause mount to think that this is a NFS share, which we don't
+               # want.
+               if ! disk="$(readlink -f "$disk")" ; then
+                       continue
+               fi
+
+               # Try to load file system type module (ignore errors), otherwise
+               # this won't succeed.
+               if fstype=$(get_fstype "$disk") ; then
+                       modprobe "$fstype" || :
+                       ROOTFSTYPE="$fstype"
+               fi
+
+               # Try to mount read-only and see if it's the right filesystem.
+               # If so, record the device name but umount again, because we
+               # want to be able to do an fsck on it.
+               if mount -r -t "${ROOTFSTYPE:-auto}" ${ROOTFLAGS} "${disk}" ${rootmnt} ; then
+                       if [ -d ${rootmnt}/proc ] ; then
+                               # This will be sourced by init after this hook has run.
+                               echo "export ROOT=$disk" >> /conf/param.conf
+                               if [ -n "$ROOTFSTYPE" ] && [ x"$ROOTFSTYPE" != x"auto" ] ; then
+                                       echo "export ROOTFSTYPE=$ROOTFSTYPE" >> /conf/param.conf
+                               fi
+                               found=1
+                       fi
+                       umount ${rootmnt}
+                       if [ $found -eq 1 ] ; then
+                               break
+                       fi
+               fi
+       done
+fi
+
+exit 0
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/extra/logout-all.sh b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/extra/logout-all.sh
new file mode 100755 (executable)
index 0000000..061e1a7
--- /dev/null
@@ -0,0 +1,68 @@
+#!/bin/sh
+#
+# This script logs out from all active iSCSI sessions, excluding those
+# listed in /run/open-iscsi/shutdown-keep-sessions. That file is
+# generated by umountiscsi.sh and determines which sessions should not
+# be terminated.
+#
+
+ISCSIADM=/sbin/iscsiadm
+PIDFILE=/run/iscsid.pid
+
+ISCSI_ROOT_KEEP_ALL_SESSIONS_AT_SHUTDOWN=0
+if [ -f /etc/default/open-iscsi ]; then
+       . /etc/default/open-iscsi
+fi
+
+if [ -f /etc/iscsi/iscsi.initramfs ] && [ $ISCSI_ROOT_KEEP_ALL_SESSIONS_AT_SHUTDOWN -eq 1 ]; then
+       # Don't logout from any sessions if root is on initramfs and the
+       # administrator wanted it that way.
+       exit 0
+fi
+
+if [ ! -s $PIDFILE ] || ! kill -0 `sed -n 1p $PIDFILE` >/dev/null 2>/dev/null ; then
+       # Don't logout from iSCSI sessions if daemon isn't running
+       echo "iSCSI initiator daemon not running, not logging out from targets." >&2
+       exit 1
+fi
+
+EXCLUDED_SESSIONS=""
+if [ -f /run/open-iscsi/shutdown-keep-sessions ] ; then
+       _EXCLUDED_SESSIONS=$(cat /run/open-iscsi/shutdown-keep-sessions)
+       for s in ${_EXCLUDED_SESSIONS} ; do
+               EXCLUDED_SESSIONS="${EXCLUDED_SESSIONS:+$EXCLUDED_SESSIONS }${s}"
+       done
+fi
+
+# trivial case
+if [ -z "$EXCLUDED_SESSIONS" ] ; then
+       $ISCSIADM -m node --logoutall=all
+       exit $?
+fi
+
+in_set() {
+       eval _set=\$$1
+       case "${_set}" in
+               ("$2"|*" $2"|"$2 "*|*" $2 "*) return 0 ;;
+               (*)                           return 1 ;;
+       esac
+}
+
+# go through all iSCSI sessions, but exclude those where we don't want
+# to logout from
+RC=0
+for host_dir in /sys/devices/platform/host* ; do
+       [ -d "$host_dir"/iscsi_host* ] || continue
+       for session_dir in "$host_dir"/session* ; do
+               if in_set EXCLUDED_SESSIONS "$session_dir" ; then
+                       continue
+               fi
+               $ISCSIADM -m session -r "$session_dir" --logout
+               rc=$?
+               if [ $rc -ne 0 ] ; then
+                       RC=1
+               fi
+       done
+done
+
+exit $RC
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/extra/net-interface-handler b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/extra/net-interface-handler
new file mode 100755 (executable)
index 0000000..9cd6e1e
--- /dev/null
@@ -0,0 +1,80 @@
+#!/bin/sh -e
+# suppress configuration of network interface used
+# by iSCSI root device
+#
+# If the root filesystem is on iSCSI, then we must take care to avoid
+# changing the state of its network interface. To this end, the initramfs
+# leaves a note for us which interface was used, and we mangle
+# /run/network/ifstate manually to stop it being brought up or down
+# automatically. This is a slight layering violation, but, unfortunately,
+# ifupdown appears to have no way to do this without also running
+# /etc/network/*.d/ scripts.
+
+assert_interface() {
+    # udev sets INTERFACE to the name of the currently-processed nic.
+    [ -n "$INTERFACE" ] && return 0
+    echo "environment variable INTERFACE not set." 1>&2;
+    return 1
+}
+
+start() {
+    CR="
+"
+    assert_interface || return
+    ifile=/run/initramfs/open-iscsi.interface
+
+    [ -f "$ifile" ] && read iface < "$ifile" || return 0
+    [ "$INTERFACE" = "$iface" ] || return
+
+    if ! grep -qs "^$iface=" /run/network/ifstate; then
+        mkdir -p /run/network
+        echo "$iface=$iface" >>/run/network/ifstate
+
+        if [ -f /run/net-$iface.conf ]; then
+            conf=/run/net-$iface.conf
+        elif [ -f /run/net6-$iface.conf ]; then
+            conf=/run/net6-$iface.conf
+        else
+            conf=""
+        fi
+        if command -v resolvconf >/dev/null &&
+           [ -n "$conf" ]; then
+            . "$conf"
+            R=""
+            [ -n "$DOMAINSEARCH" ] && R="$R${CR}search $DOMAINSEARCH"
+            [ -n "$IPV6DOMAINSEARCH" ] && R="$R${CR}search $IPV6DOMAINSEARCH"
+            for ns in "$IPV4DNS0" "$IPV4DNS1" "$IPV6DNS0" "$IPV6DNS1"; do
+                [ -n "$ns" -a "$ns" != "0.0.0.0" ] && R="$R${CR}nameserver $ns"
+            done
+            if [ -n "$R" ]; then
+                # create the dir in case resolvconf did not start yet
+                mkdir -p /run/resolvconf/interface
+                resolvconf -a $iface.iscsi-network <<EOF
+${R#${CR}}
+EOF
+            fi
+        fi
+    fi
+}
+
+stop() {
+    assert_interface || return
+    ifile=/run/initramfs/open-iscsi.interface
+    [ -f "$ifile" ] && read iface < "$ifile" || return 0
+    [ "$INTERFACE" = "$iface" ] || return
+
+    if grep -qs "^$iface=" /run/network/ifstate; then
+        grep -v "^$iface=" /run/network/ifstate >/run/network/.ifstate.tmp || true
+        mv /run/network/.ifstate.tmp /run/network/ifstate
+
+        if command -v resolvconf >/dev/null; then
+            resolvconf -d $iface.iscsi-network
+        fi
+    fi
+}
+
+case "$1" in
+    start) start ;;
+    stop) stop ;;
+    *) echo "ERROR: must be called with 'start' or 'stop'" >&2; exit 1 ;;
+esac
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/extra/startup-checks.sh b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/extra/startup-checks.sh
new file mode 100755 (executable)
index 0000000..a369785
--- /dev/null
@@ -0,0 +1,59 @@
+#!/bin/sh
+#
+# This script does the required startup checks before the iSCSI
+# daemon should be started. It also generates a name if that
+# hadn't been done before.
+#
+
+PATH=/sbin:/bin
+
+NAMEFILE=/etc/iscsi/initiatorname.iscsi
+CONFIGFILE=/etc/iscsi/iscsid.conf
+
+if [ ! -e "$CONFIGFILE" ]; then
+       echo >&2
+       echo "Error: configuration file $CONFIGFILE is missing!" >&2
+       echo "The iSCSI driver has not been correctly installed and cannot start." >&2
+       echo >&2
+       exit 1
+fi
+
+if [ ! -f $NAMEFILE ]; then
+       echo >&2
+       echo "Error: InitiatorName file $NAMEFILE is missing!" >&2
+       echo "The iSCSI driver has not been correctly installed and cannot start." >&2
+       echo >&2
+       exit 1
+fi
+
+# see if we need to generate a unique iSCSI InitiatorName
+if grep -q "^GenerateName=yes" $NAMEFILE ; then
+       if [ ! -x /sbin/iscsi-iname ] ; then
+               echo "Error: /sbin/iscsi-iname does not exist, driver was not successfully installed" >&2
+               exit 1
+       fi
+       # Generate a unique InitiatorName and save it
+       INAME=`/sbin/iscsi-iname -p iqn.1993-08.org.debian:01`
+       if [ "$INAME" != "" ] ; then
+               echo "## DO NOT EDIT OR REMOVE THIS FILE!" > $NAMEFILE
+               echo "## If you remove this file, the iSCSI daemon will not start." >> $NAMEFILE
+               echo "## If you change the InitiatorName, existing access control lists" >> $NAMEFILE
+               echo "## may reject this initiator.  The InitiatorName must be unique">> $NAMEFILE
+               echo "## for each iSCSI initiator.  Do NOT duplicate iSCSI InitiatorNames." >> $NAMEFILE
+               printf "InitiatorName=$INAME\n"  >> $NAMEFILE
+               chmod 600 $NAMEFILE
+       else
+               echo "Error: failed to generate an iSCSI InitiatorName, driver cannot start." >&2
+               echo >&2
+               exit 1
+       fi
+fi
+
+# make sure there is a valid InitiatorName for the driver
+if ! grep -q "^InitiatorName=[^ \t\n]" $NAMEFILE ; then
+       echo >&2
+       echo "Error: $NAMEFILE does not contain a valid InitiatorName." >&2
+       echo "The iSCSI driver has not been correctly installed and cannot start." >&2
+       echo >&2
+       exit 1
+fi
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/extra/udeb/finish-install.d/10open-iscsi b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/extra/udeb/finish-install.d/10open-iscsi
new file mode 100755 (executable)
index 0000000..3080d59
--- /dev/null
@@ -0,0 +1,24 @@
+#! /bin/sh
+
+set -e
+
+got_iscsi=
+for f in /etc/iscsi/*; do
+       # Ignore iscsid.conf, as that will always be present, even if
+       # iSCSI is not used. (See Debian bug #863435.)
+       if [ x"$f" = x"/etc/iscsi/iscsid.conf" ] ; then
+               continue
+       fi
+       [ -e "$f" ] || continue
+       got_iscsi=1
+       break
+done
+
+if [ "$got_iscsi" ]; then
+       # Copy the configuration to the target...
+       cp -a /etc/iscsi /target/etc/
+       if [ -x /target/usr/sbin/update-initramfs ] ; then
+               echo "iSCSI detected, refreshing initramfs"
+               /bin/in-target update-initramfs -k all -u
+       fi
+fi
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/extra/udeb/iscsi-start b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/extra/udeb/iscsi-start
new file mode 100644 (file)
index 0000000..beea0ae
--- /dev/null
@@ -0,0 +1,20 @@
+#! /bin/sh
+
+# This is basically a version of the init script without dependencies on lsb
+# and without all the sanity checks. The installer is a clean environment, so
+# we don't need all of that.
+
+if ! [ -f /etc/iscsi/initiatorname.iscsi ]; then
+       # Generate a unique InitiatorName and save it
+       INAME=`iscsi-iname -p iqn.1993-08.org.debian:01`
+       echo "## DO NOT EDIT OR REMOVE THIS FILE!" > /etc/iscsi/initiatorname.iscsi
+       echo "## If you remove this file, the iSCSI daemon will not start." >> /etc/iscsi/initiatorname.iscsi
+       echo "## If you change the InitiatorName, existing access control lists" >> /etc/iscsi/initiatorname.iscsi
+       echo "## may reject this initiator.  The InitiatorName must be unique">> /etc/iscsi/initiatorname.iscsi
+       echo "## for each iSCSI initiator.  Do NOT duplicate iSCSI InitiatorNames." >> /etc/iscsi/initiatorname.iscsi
+       printf "InitiatorName=$INAME\n"  >> /etc/iscsi/initiatorname.iscsi
+       chmod 600 /etc/iscsi/initiatorname.iscsi
+fi
+
+modprobe -q iscsi_tcp 2>/dev/null >&2
+/sbin/iscsid
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/extra/udev/70-iscsi-network-interface.rules b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/extra/udev/70-iscsi-network-interface.rules
new file mode 100644 (file)
index 0000000..e0408d7
--- /dev/null
@@ -0,0 +1,3 @@
+# run before 80-networking.rules to run before ifupdown
+SUBSYSTEM=="net", ACTION=="add", RUN+="/lib/open-iscsi/net-interface-handler start"
+SUBSYSTEM=="net", ACTION=="remove", RUN+="/lib/open-iscsi/net-interface-handler stop"
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/extra/udev/70-open-iscsi.rules b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/extra/udev/70-open-iscsi.rules
new file mode 100644 (file)
index 0000000..784072b
--- /dev/null
@@ -0,0 +1,3 @@
+# When iscsi disks are present, iscsid.service should be running. LP: #1802354
+# ID_PATH looks like ip-<ipv4-dotted-quad>:<port>-iscsi-<target>-lun-<lun>
+SUBSYSTEM=="block", ACTION=="add", ENV{ID_PATH}=="*-iscsi-*", ENV{SYSTEMD_WANTS}+="iscsid.service"
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/extra/umountiscsi.sh b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/extra/umountiscsi.sh
new file mode 100755 (executable)
index 0000000..5632e05
--- /dev/null
@@ -0,0 +1,683 @@
+#!/bin/sh
+#
+# This script umounts mounted iSCSI devices on shutdown, if possible.
+# It is supposed to catch most use cases but is not designed to work
+# for every corner-case. It handles LVM and multipath, but only if
+# one of the following stackings is used:
+#   LVM -> multipath -> iSCSI
+#   multipath -> iSCSI
+#   LVM -> iSCSI
+#   LVM -> LUKS -> multipath -> iSCSI
+#   LVM -> LUKS -> iSCSI
+#   LUKS -> LVM -> multipath -> iSCSI
+#   LUKS -> multipath -> iSCSI
+#   LUKS -> LVM -> iSCSI
+#   LUKS -> iSCSI
+# It does not try to umount anything belonging to any device that is
+# also used as a backing store for the root filesystem. Any iSCSI
+# device part of the backing store of the root filesystem will be noted
+# in /run/open-iscsi/shutdown-keep-sessions, so that the session not be
+# closed on shutdown.
+#
+# KNOWN ISSUES:
+#    - It doesn't handle submounts properly in all corner cases.
+#      Specifically, it doesn't handle a non-iSCSI mount below an
+#      iSCSI mount if it isn't also marked _netdev in /etc/fstab.
+#    - It does not handle other things device mapper can do, such as
+#      RAID, crypto, manual mappings of parts of disks, etc.
+#    - It doesn't try to kill programs still accessing those mounts,
+#      umount will just fail then.
+#    - It doesn't handle more complicated stackings such as overlayfs,
+#      FUSE filesystems, loop devices, etc.
+#    - It doesn't handle swap.
+#
+# LONG TERM GOAL:
+#    - In the long term, there should be a solution where for each part
+#      of the stacking (device mapper, LVM, overlayfs, etc.) explicit
+#      depdendencies are declared with the init system such that it can
+#      be automatically dismantled. That would make this script
+#      superfluous and also not be a layering violation, as it
+#      currently is.
+#
+# CODING CHOICES:
+#    - On systems running sysvinit, this script might be called without
+#      /usr being mounted, so a lot of very useful commands are not
+#      available: head, tail, stat, awk, etc. This makes the script
+#      quite ugly at places, but that can't be avoided.
+#
+# Author: Christian Seiler <christian@iwakd.de>
+#
+
+# Make sure we don't include /usr in our path, else future modifications
+# to this script might accidentally use something from there and cause
+# failure on separate-/usr sysvinit systems that isn't immediately
+# noticed.
+PATH=/sbin:/bin
+
+EXCLUDE_MOUNTS_AT_SHUTDOWN=""
+if [ -f /etc/default/open-iscsi ]; then
+       . /etc/default/open-iscsi
+fi
+
+MULTIPATH=/sbin/multipath
+PVS=/sbin/pvs
+LVS=/sbin/lvs
+VGS=/sbin/vgs
+VGCHANGE=/sbin/vgchange
+CRYPTSETUP=/sbin/cryptsetup
+DMSETUP=/sbin/dmsetup
+
+if [ -x $PVS ] && [ -x $LVS ] && [ -x $VGCHANGE ] ; then
+       HAVE_LVM=1
+else
+       HAVE_LVM=0
+fi
+if [ -x $CRYPTSETUP ] && [ -x $DMSETUP ] ; then
+       HAVE_LUKS=1
+else
+       HAVE_LUKS=0
+fi
+
+DRY_RUN=0
+
+# We need to make sure that we don't try to umount the root device
+# and for systemd systems, also /usr (which is pre-mounted in initrd
+# there).
+EXCLUDE_MOUNTS="/"
+if [ -d /run/systemd/system ] ; then
+        EXCLUDE_MOUNTS="$EXCLUDE_MOUNTS /usr"
+fi
+EXCLUDE_MOUNTS="${EXCLUDE_MOUNTS}${EXCLUDE_MOUNTS_AT_SHUTDOWN+ $EXCLUDE_MOUNTS_AT_SHUTDOWN}"
+unset _EXCLUDE_MOUNTS
+
+error_usage() {
+       echo "Usage: $0 [--dry-run | --timeout secs]" >&2
+       exit 1
+}
+
+timeout=0
+
+if [ $# -gt 2 ] ; then
+       error_usage
+fi
+
+if [ $# -eq 2 ] ; then
+       if [ x"$1"x != x"--timeout"x ] ; then
+               error_usage
+       fi
+       case "$2" in
+               (-1)            timeout="$2" ;;
+               (*[!0-9]*|"")   error_usage ;;
+               (*)             timeout="$2" ;;
+       esac
+elif [ $# -eq 1 ] ; then
+       if [ x"$1"x != x"--dry-run"x ] ; then
+               error_usage
+       fi
+       DRY_RUN=1
+fi
+
+# poor man's hash implementation using shell variables
+hash_keys() {
+       _hash_keys_hash_key_prefix="${1}_"
+       (
+               IFS='='
+               set | while read var value ; do
+                       if [ x"${var#$_hash_keys_hash_key_prefix}"x != x"${var}"x ] ; then
+                               printf '%s\n' "${var#$_hash_keys_hash_key_prefix}"
+                       fi
+               done
+       )
+}
+
+
+hash_clear() {
+       for k in $(hash_keys "$1") ; do
+               unset "${1}_${k}"
+       done
+}
+
+hash_get() {
+       _hash_get_var="$2_$(printf '%s' "$3" | sed 's%[^A-Za-z0-9_]%_%g')"
+       eval _hash_get_value=\$${_hash_get_var}
+       eval $1=\${_hash_get_value}
+}
+
+hash_set() {
+       _hash_set_var="$1_$(printf '%s' "$2" | sed 's%[^A-Za-z0-9_]%_%g')"
+       eval ${_hash_set_var}=\${3}
+}
+
+hash_unset() {
+       _hash_set_var="$1_$(printf '%s' "$2" | sed 's%[^A-Za-z0-9_]%_%g')"
+       unset ${_hash_set_var}
+}
+
+in_set() {
+       eval _set=\$$1
+       case "${_set}" in
+               ("$2"|*" $2"|"$2 "*|*" $2 "*) return 0 ;;
+               (*)                           return 1 ;;
+       esac
+}
+
+_add_to_set() {
+       eval _set=\$$1
+       case "${_set}" in
+               ("$2"|*" $2"|"$2 "*|*" $2 "*) ;;
+               ("")    _set="$2" ;;
+               (*)     _set="${_set} $2" ;;
+       esac
+       eval $1=\${_set}
+}
+
+add_to_set() {
+       _add_to_set_set="$1"
+       shift
+       for _add_to_set_val in "$@" ; do
+               _add_to_set "${_add_to_set_set}" "${_add_to_set_val}"
+       done
+}
+
+hash_add_to_set() {
+       _hash_add_to_set_var="$1_$(printf '%s' "$2" | sed 's%[^A-Za-z0-9_]%_%g')"
+       shift
+       shift
+       add_to_set "${_hash_add_to_set_var}" "$@"
+}
+
+device_majmin() {
+       eval $1=\"\"
+       _majmin_dec=$(LC_ALL=C ls -lnd /dev/"$2" | while read _perms _links _uid _gid _majcomma _min _rest ; do
+               if [ x"${_majcomma%,}"x != x"${_majcomma}"x ] ; then
+                       printf '%s' ${_majcomma%,}:${_min}
+               fi
+               break
+       done)
+       [ -n "${_majmin_dec}" ] || return
+       eval $1=\${_majmin_dec}
+}
+
+get_lvm_vgs() {
+       # handle the case where we didn't get passed any PVs
+       # at all
+       [ $# -gt 0 ] || return 0
+       # subshell for pwd change
+       (
+               cd /dev
+               $PVS --noheadings -o vg_name "$@" 2>/dev/null
+       )
+}
+
+enumerate_luks() {
+       hash_clear LUKS_DEVICES_REVERSE_MAP
+
+       _all_crypt_devices=$($DMSETUP info --noheadings -o name -c -S subsystem=CRYPT 2>/dev/null || :)
+       for _crypt_device in ${_all_crypt_devices} ; do
+               [ -b "/dev/mapper/${_crypt_device}" ] || continue
+               _crypt_device="$(readlink -fe "/dev/mapper/${_crypt_device}" 2>/dev/null || :)"
+               _crypt_device="${_crypt_device#/dev/}"
+               [ -b "/dev/${_crypt_device}" ] || continue
+               # dmsetup deps is weird, it outputs the following:
+               # 1 dependencies : (XYZ)
+               _dep=$($DMSETUP deps -o blkdevname "/dev/${_crypt_device}" | sed -n '1s%.*: (\(.*\)).*%\1%p')
+               if [ -n "$_dep" ] && [ -b "/dev/${_dep}" ] ; then
+                       _dep="$(readlink -fe "/dev/$_dep" 2>/dev/null || :)"
+                       _dep="${_dep#/dev/}"
+               fi
+               if [ -n "$_dep" ] && [ -b "/dev/${_dep}" ] ; then
+                       hash_set LUKS_DEVICES_REVERSE_MAP "${_dep}" "${_crypt_device}"
+               fi
+       done
+}
+
+enumerate_iscsi_devices() {
+       # Empty arrays
+       iscsi_disks=""
+       iscsi_partitions=""
+       iscsi_multipath_disks=""
+       iscsi_multipath_disk_aliases=""
+       iscsi_multipath_partitions=""
+       iscsi_lvm_vgs=""
+       iscsi_lvm_lvs=""
+       iscsi_potential_mount_sources=""
+       iscsi_luks_pass1=""
+       iscsi_luks_pass2=""
+
+       hash_clear ISCSI_DEVICE_SESSIONS
+       hash_clear ISCSI_MPALIAS_SESSIONS
+       hash_clear ISCSI_LVMVG_SESSIONS
+       hash_clear ISCSI_NUMDEVICE_SESSIONS
+       ISCSI_EXCLUDED_SESSIONS=""
+
+       # We first need to generate a global reverse mapping of all
+       # cryptsetup (e.g. LUKS) devices, because there's no easy way
+       # to query "is this the encrypted backing of an active crypto
+       # mapping?
+       enumerate_luks
+
+       # Look for all iscsi disks
+       for _host_dir in /sys/devices/platform/host* /sys/devices/pci*/*/*/host* ; do
+               if ! [ -d "$_host_dir"/iscsi_host* ] || ! [ -d "$_host_dir"/iscsi_host/host* ] ; then
+                       continue
+               fi
+               for _session_dir in "$_host_dir"/session* ; do
+                       [ -d "$_session_dir"/target* ] || continue
+                       for _block_dev_dir in "$_session_dir"/target*/*\:*/block/* ; do
+                               _block_dev=${_block_dev_dir##*/}
+                               [ x"${_block_dev}"x != x"*"x ] || continue
+                               add_to_set iscsi_disks "${_block_dev}"
+                               hash_add_to_set ISCSI_DEVICE_SESSIONS "${_block_dev}" ${_session_dir}
+                       done
+               done
+       done
+
+       # Look for all partitions on those disks
+       for _disk in $iscsi_disks ; do
+               hash_get _disk_sessions ISCSI_DEVICE_SESSIONS "${_disk}"
+               for _part_dir in /sys/class/block/"${_disk}"/"${_disk}"?* ; do
+                       _part="${_part_dir##*/}"
+                       [ x"${_part}"x != x"${_disk}?*"x ] || continue
+                       add_to_set iscsi_partitions "${_part}"
+                       hash_set ISCSI_DEVICE_SESSIONS "${_part}" "${_disk_sessions}"
+               done
+       done
+
+       if [ -x $MULTIPATH ] ; then
+               # Look for all multipath disks
+               for _disk in $iscsi_disks ; do
+                       hash_get _disk_sessions ISCSI_DEVICE_SESSIONS "${_disk}"
+                       for _alias in $($MULTIPATH -v1 -l /dev/"$_disk") ; do
+                               _mp_dev="$(readlink -fe "/dev/mapper/${_alias}" || :)"
+                               [ -n "${_mp_dev}" ] || continue
+                               add_to_set iscsi_multipath_disks "${_mp_dev#/dev/}"
+                               add_to_set iscsi_multipath_disk_aliases "${_alias}"
+                               hash_add_to_set ISCSI_DEVICE_SESSIONS "${_mp_dev#/dev/}" ${_disk_sessions}
+                               hash_add_to_set ISCSI_MPALIAS_SESSIONS "${_alias}" ${_disk_sessions}
+                       done
+               done
+
+               # Look for partitions on these multipath disks
+               for _alias in $iscsi_multipath_disk_aliases ; do
+                       hash_get _mp_sessions ISCSI_MPALIAS_SESSIONS "${_alias}"
+                       for _part_name in /dev/mapper/"${_alias}"-part* ; do
+                               _part="$(readlink -fe "$_part_name" 2>/dev/null || :)"
+                               [ -n "${_part}" ] || continue
+                               add_to_set iscsi_multipath_partitions "${_part#/dev/}"
+                               hash_set ISCSI_DEVICE_SESSIONS "${_part#/dev/}" "${_mp_sessions}"
+                       done
+               done
+       fi
+
+       if [ $HAVE_LUKS -eq 1 ] ; then
+               # Look for all LUKS devices.
+               for _dev in $iscsi_disks $iscsi_partitions $iscsi_multipath_disks $iscsi_multipath_partitions ; do
+                       hash_get _luksDev LUKS_DEVICES_REVERSE_MAP "${_dev}"
+                       [ -n "${_luksDev}" ] || continue
+                       add_to_set iscsi_luks_pass1 "${_luksDev}"
+                       hash_get _currentSession ISCSI_DEVICE_SESSIONS "${_dev}"
+                       if [ -n "${_currentSession}" ] ; then
+                               hash_set ISCSI_DEVICE_SESSIONS "${_luksDev}" "${_currentSession}"
+                       fi
+               done
+       fi
+
+       if [ $HAVE_LVM -eq 1 ] ; then
+               # Look for all LVM volume groups that have a backing store
+               # on any iSCSI device we found. Also, add $LVMGROUPS set in
+               # /etc/default/open-iscsi (for more complicated stacking
+               # configurations we don't automatically detect).
+               for _vg in $(get_lvm_vgs $iscsi_disks $iscsi_partitions $iscsi_multipath_disks $iscsi_multipath_partitions $iscsi_luks_pass1) $LVMGROUPS ; do
+                       add_to_set iscsi_lvm_vgs "$_vg"
+               done
+
+               # $iscsi_lvm_vgs is now unique list
+               for _vg in $iscsi_lvm_vgs ; do
+                       # get PVs to track iSCSI sessions
+                       for _pv in $($VGS --noheadings -o pv_name "$_vg" 2>/dev/null) ; do
+                               _pv_dev="$(readlink -fe "$_pv" 2>/dev/null || :)"
+                               [ -n "${_pv_dev}" ] || continue
+                               hash_get _pv_sessions ISCSI_DEVICE_SESSIONS "${_pv_dev#/dev/}"
+                               hash_add_to_set ISCSI_LVMVG_SESSIONS "${_vg}" ${_pv_sessions}
+                       done
+
+                       # now we collected all sessions belonging to this VG
+                       hash_get _vg_sessions ISCSI_LVMVG_SESSIONS "${_vg}"
+
+                       # find all LVs
+                       for _lv in $($VGS --noheadings -o lv_name "$_vg" 2>/dev/null) ; do
+                               _dev="$(readlink -fe "/dev/${_vg}/${_lv}" 2>/dev/null || :)"
+                               [ -n "${_dev}" ] || continue
+                               iscsi_lvm_lvs="$iscsi_lvm_lvs ${_dev#/dev/}"
+                               hash_set ISCSI_DEVICE_SESSIONS "${_dev#/dev/}" "${_vg_sessions}"
+                       done
+               done
+       fi
+
+       if [ $HAVE_LUKS -eq 1 ] ; then
+               # Look for all LUKS devices.
+               for _dev in $iscsi_lvm_lvs ; do
+                       hash_get _luksDev LUKS_DEVICES_REVERSE_MAP "${_dev}"
+                       [ -n "${_luksDev}" ] || continue
+                       add_to_set iscsi_luks_pass2 "${_luksDev}"
+                       hash_get _currentSession ISCSI_DEVICE_SESSIONS "${_dev}"
+                       if [ -n "${_currentSession}" ] ; then
+                               hash_set ISCSI_DEVICE_SESSIONS "${_luksDev}" "${_currentSession}"
+                       fi
+               done
+       fi
+
+       # Gather together all mount sources
+       iscsi_potential_mount_sources="$iscsi_potential_mount_sources $iscsi_disks $iscsi_partitions"
+       iscsi_potential_mount_sources="$iscsi_potential_mount_sources $iscsi_multipath_disks $iscsi_multipath_partitions"
+       iscsi_potential_mount_sources="$iscsi_potential_mount_sources $iscsi_lvm_lvs"
+       iscsi_potential_mount_sources="$iscsi_potential_mount_sources $iscsi_luks_pass1 $iscsi_luks_pass2"
+
+       # Convert them to numerical representation
+       iscsi_potential_mount_sources_majmin=""
+       for _src in $iscsi_potential_mount_sources ; do
+               device_majmin _src_majmin "$_src"
+               [ -n "$_src_majmin" ] || continue
+               iscsi_potential_mount_sources_majmin="${iscsi_potential_mount_sources_majmin} ${_src_majmin}"
+               hash_get _dev_sessions ISCSI_DEVICE_SESSIONS "${_src}"
+               hash_set ISCSI_NUMDEVICE_SESSIONS "${_src_majmin}" "${_dev_sessions}"
+       done
+
+       # Enumerate mount points
+       iscsi_mount_points=""
+       iscsi_mount_point_ids=""
+       while read _mpid _mppid _mpdev _mpdevpath _mppath _mpopts _other ; do
+               if in_set iscsi_potential_mount_sources_majmin "$_mpdev" ; then
+                       if in_set EXCLUDE_MOUNTS "${_mppath}" ; then
+                               hash_get _dev_sessions ISCSI_NUMDEVICE_SESSIONS "${_mpdev}"
+                               add_to_set ISCSI_EXCLUDED_SESSIONS $_dev_sessions
+                               continue
+                       fi
+                       # list mountpoints in reverse order (in case
+                       # some are stacked) mount --move may cause the
+                       # order of /proc/self/mountinfo to not always
+                       # reflect the stacking order, so this is not
+                       # fool-proof, but it's better than nothing
+                       iscsi_mount_points="$_mppath $iscsi_mount_points"
+                       iscsi_mount_point_ids="$_mpid $iscsi_mount_points"
+               fi
+       done < /proc/self/mountinfo
+}
+
+try_umount() {
+       # in order to handle stacking try twice; together with the fact
+       # that the list of mount points is in reverse order of the
+       # contents /proc/self/mountinfo this should catch most cases
+       for retry in 1 2 ; do
+               for path in $iscsi_mount_points ; do
+                       # first try to see if it really is a mountpoint
+                       # still (might be the second round this is done
+                       # and the mount is already gone, or something
+                       # else umounted it first)
+                       if ! fstab-decode mountpoint -q "$path" ; then
+                               continue
+                       fi
+
+                       # try to umount it
+                       if ! fstab-decode umount "$path" ; then
+                               # unfortunately, umount's exit code
+                               # may be a false negative, i.e. it
+                               # might give a failure exit code, even
+                               # though it succeeded, so check again
+                               if fstab-decode mountpoint -q "$path" ; then
+                                       echo "Could not unmount $path" >&2
+                                       any_umount_failed=1
+                               fi
+                       fi
+               done
+       done
+}
+
+try_deactivate_lvm() {
+       [ $HAVE_LVM -eq 1 ] || return
+
+       for vg in $iscsi_lvm_vgs ; do
+               vg_excluded=0
+               hash_get vg_sessions ISCSI_LVMVG_SESSIONS "$vg"
+               for vg_session in $vg_sessions ; do
+                       if in_set ISCSI_EXCLUDED_SESSIONS "$vg_session" ; then
+                               vg_excluded=1
+                       fi
+               done
+               if [ $vg_excluded -eq 1 ] ; then
+                       # volume group on same iSCSI session as excluded
+                       # mount, don't disable it
+                       # (FIXME: we should only exclude VGs that contain
+                       # those mounts, not also those that happen to be
+                       # in the same iSCSI session)
+                       continue
+               fi
+               if ! $VGCHANGE --available=n $vg ; then
+                       # Make sure the volume group (still) exists. If
+                       # it doesn't we count that as deactivated, so
+                       # don't fail then.
+                       _vg_test=$(vgs -o vg_name --noheadings $vg 2>/dev/null || :)
+                       if [ -n "${_vg_test}" ] ; then
+                               echo "Cannot deactivate Volume Group $vg" >&2
+                               any_umount_failed=1
+                       fi
+               fi
+       done
+}
+
+try_dismantle_multipath() {
+       [ -x $MULTIPATH ] || return
+
+       for mpalias in $iscsi_multipath_disk_aliases ; do
+               mp_excluded=0
+               hash_get mp_sessions ISCSI_MPALIAS_SESSIONS "$mpalias"
+               for mp_session in $mp_sessions ; do
+                       if in_set ISCSI_EXCLUDED_SESSIONS "$mp_session" ; then
+                               mp_excluded=1
+                       fi
+               done
+               if [ $mp_excluded -eq 1 ] ; then
+                       # multipath device on same iSCSI session as
+                       # excluded mount, don't disable it
+                       # (FIXME: we should only exclude multipath mounts
+                       # that contain those mounts, not also those that
+                       # happen to be in the same iSCSI session)
+                       continue
+               fi
+               if ! $MULTIPATH -f $mpalias ; then
+                       echo "Cannot dismantle Multipath Device $mpalias" >&2
+                       any_umount_failed=1
+               fi
+       done
+}
+
+try_dismantle_luks() {
+       [ $HAVE_LUKS -eq 1 ] || return
+       case "$1" in
+       1)      iscsi_luks_current_pass="$iscsi_luks_pass1" ;;
+       2|*)    iscsi_luks_current_pass="$iscsi_luks_pass2" ;;
+       esac
+
+       for luksDev in $iscsi_luks_current_pass ; do
+               luks_excluded=0
+               hash_get device_sessions ISCSI_DEVICE_SESSIONS "$luksDev"
+               for device_session in $device_sessions ; do
+                       if in_set ISCSI_EXCLUDED_SESSIONS "$device_session" ; then
+                               luks_excluded=1
+                       fi
+               done
+               if [ $luks_excluded -eq 1 ] ; then
+                       continue
+               fi
+               _luksName="$($DMSETUP info -c --noheadings -o name /dev/"$luksDev" 2>/dev/null || :)"
+               [ -n "${_luksName}" ] || continue
+               if ! $CRYPTSETUP close "${_luksName}" ; then
+                       echo "Cannot dismantle cryptsetup device ${_luksName}" >&2
+                       any_umount_failed=1
+               fi
+       done
+}
+
+# Don't do this if we are using systemd as init system, since systemd
+# takes care of network filesystems (including those marked _netdev) by
+# itself.
+if ! [ -d /run/systemd/system ] && [ $HANDLE_NETDEV -eq 1 ] && [ $DRY_RUN -eq 0 ]; then
+       echo "Unmounting all devices marked _netdev";
+       umount -a -O _netdev >/dev/null 2>&1
+fi
+
+enumerate_iscsi_devices
+
+# Dry run? Just print what we want to do (useful for administrator to check).
+if [ $DRY_RUN -eq 1 ] ; then
+       echo "$0: would umount the following mount points:"
+       had_mount=0
+       if [ -n "$iscsi_mount_points" ] ; then
+               for v in $iscsi_mount_points ; do
+                       echo "  $v"
+                       had_mount=1
+               done
+       fi
+       [ $had_mount -eq 1 ] || echo "  (none)"
+
+       echo "$0: would disable the following LUKS devices (second pass):"
+       had_luks=0
+       if [ -n "$iscsi_luks_pass2" ] ; then
+               for v in ${iscsi_luks_pass2} ; do
+                       luks_excluded=0
+                       hash_get device_sessions ISCSI_DEVICE_SESSIONS "$v"
+                       for device_session in $device_sessions ; do
+                               if in_set ISCSI_EXCLUDED_SESSIONS "$device_session" ; then
+                                       luks_excluded=1
+                               fi
+                       done
+                       if [ $luks_excluded -eq 1 ] ; then
+                               continue
+                       fi
+                       _luksName="$($DMSETUP info -c --noheadings -o name /dev/"$v" 2>/dev/null || :)"
+                       [ -n "${_luksName}" ] || continue
+                       echo "  ${_luksName}"
+                       had_luks=1
+               done
+       fi
+       [ $had_luks -eq 1 ] || echo "  (none)"
+
+       echo "$0: would deactivate the following LVM Volume Groups:"
+       had_vg=0
+       if [ -n "$iscsi_lvm_vgs" ] ; then
+               for v in $iscsi_lvm_vgs ; do
+                       # sync this exclusion logic with try_deactivate_lvm
+                       vg_excluded=0
+                       hash_get vg_sessions ISCSI_LVMVG_SESSIONS "$v"
+                       for vg_session in $vg_sessions ; do
+                               if in_set ISCSI_EXCLUDED_SESSIONS "$vg_session" ; then
+                                       vg_excluded=1
+                               fi
+                       done
+                       if [ $vg_excluded -eq 1 ] ; then
+                               continue
+                       fi
+                       echo "  $v"
+                       had_vg=1
+               done
+       fi
+       [ $had_vg -eq 1 ] || echo "  (none)"
+
+       echo "$0: would disable the following LUKS devices (first pass):"
+       had_luks=0
+       if [ -n "$iscsi_luks_pass1" ] ; then
+               for v in ${iscsi_luks_pass1} ; do
+                       luks_excluded=0
+                       hash_get device_sessions ISCSI_DEVICE_SESSIONS "$v"
+                       for device_session in $device_sessions ; do
+                               if in_set ISCSI_EXCLUDED_SESSIONS "$device_session" ; then
+                                       luks_excluded=1
+                               fi
+                       done
+                       if [ $luks_excluded -eq 1 ] ; then
+                               continue
+                       fi
+                       _luksName="$($DMSETUP info -c --noheadings -o name /dev/"$v" 2>/dev/null || :)"
+                       [ -n "${_luksName}" ] || continue
+                       echo "  ${_luksName}"
+                       had_luks=1
+               done
+       fi
+       [ $had_luks -eq 1 ] || echo "  (none)"
+
+       echo "$0: would deactivate the following multipath volumes:"
+       had_mp=0
+       if [ -n "$iscsi_multipath_disk_aliases" ] ; then
+               for v in $iscsi_multipath_disk_aliases ; do
+                       # sync this exclusion logic with try_dismantle_multipath
+                       mp_excluded=0
+                       hash_get mp_sessions ISCSI_MPALIAS_SESSIONS "$v"
+                       for mp_session in $mp_sessions ; do
+                               if in_set ISCSI_EXCLUDED_SESSIONS "$mp_session" ; then
+                                       mp_excluded=1
+                               fi
+                       done
+                       if [ $mp_excluded -eq 1 ] ; then
+                               continue
+                       fi
+                       echo "  $v"
+                       had_mp=1
+               done
+       fi
+       [ $had_mp -eq 1 ] || echo "  (none)"
+
+       if [ -n "$ISCSI_EXCLUDED_SESSIONS" ] ; then
+               echo "$0: the following sessions are excluded from disconnection (because / or another excluded mount is on them):"
+               for v in $ISCSI_EXCLUDED_SESSIONS ; do
+                       echo "  $v"
+               done
+       fi
+
+       exit 0
+fi
+
+# after our first enumeration, write out a list of sessions that
+# shouldn't be terminated because excluded mounts are on those
+# sessions
+if [ -n "$ISCSI_EXCLUDED_SESSIONS" ] ; then
+       mkdir -p -m 0700 /run/open-iscsi
+       for session in $ISCSI_EXCLUDED_SESSIONS ; do
+               printf '%s\n' $session
+       done > /run/open-iscsi/shutdown-keep-sessions
+else
+       # make sure there's no leftover from a previous call
+       rm -f /run/open-iscsi/shutdown-keep-sessions
+fi
+
+any_umount_failed=0
+try_umount
+try_dismantle_luks 2
+try_deactivate_lvm
+try_dismantle_luks 1
+try_dismantle_multipath
+
+while [ $any_umount_failed -ne 0 ] && ( [ $timeout -gt 0 ] || [ $timeout -eq -1 ] ) ; do
+       # wait a bit, perhaps there was still a program that
+       # was terminating
+       sleep 1
+
+       # try again and decrease timeout
+       enumerate_iscsi_devices
+       any_umount_failed=0
+       try_umount
+       try_dismantle_luks 2
+       try_deactivate_lvm
+       try_dismantle_luks 1
+       try_dismantle_multipath
+       if [ $timeout -gt 0 ] ; then
+               timeout=$((timeout - 1))
+       fi
+done
+
+# Create signaling file (might be useful)
+if [ $any_umount_failed -eq 1 ] ; then
+       touch /run/open-iscsi/some_umount_failed
+else
+       rm -f /run/open-iscsi/some_umount_failed
+fi
+exit $any_umount_failed
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/gbp.conf b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/gbp.conf
new file mode 100644 (file)
index 0000000..04b497a
--- /dev/null
@@ -0,0 +1,12 @@
+[DEFAULT]
+pristine-tar = True
+color = auto
+debian-branch = master
+
+[import-orig]
+dch = True
+
+[dch]
+id-length = 7
+meta = True
+multimaint-merge = True
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/iscsid.init b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/iscsid.init
new file mode 100644 (file)
index 0000000..18b1856
--- /dev/null
@@ -0,0 +1,48 @@
+#!/bin/sh
+# kFreeBSD do not accept scripts as interpreters, using #!/bin/sh and sourcing.
+if [ true != "$INIT_D_SCRIPT_SOURCED" ] ; then
+    set "$0" "$@"; INIT_D_SCRIPT_SOURCED=true . /lib/init/init-d-script
+fi
+### BEGIN INIT INFO
+# Provides:          iscsid
+# Required-Start:    $network $local_fs
+# Required-Stop:     $network $local_fs sendsigs
+# Default-Start:     S
+# Default-Stop:      0 1 6
+# Short-Description: iSCSI initiator daemon (iscsid)
+# Description:       The iSCSI initiator daemon takes care of
+#                    monitoring iSCSI connections to targets. It is
+#                    also the daemon providing the interface for the
+#                    iscisadm tool to talk to when administering iSCSI
+#                    connections.
+### END INIT INFO
+
+# Author: Christian Seiler <christian@iwakd.de>
+
+DESC="iSCSI initiator daemon"
+DAEMON=/sbin/iscsid
+PIDFILE=/run/iscsid.pid
+OMITDIR=/run/sendsigs.omit.d
+
+do_start_prepare() {
+       if ! /lib/open-iscsi/startup-checks.sh ; then
+               exit 1
+       fi
+}
+
+do_start_cleanup() {
+       ln -sf $PIDFILE $OMITDIR
+}
+
+do_stop_override() {
+       # Don't stop iscsid if we're on initramfs or we had some
+       # excluded sessions. We could actually stop it, it's not
+       # required for the kernel to continue working with active
+       # sessions, but it also doesn't hurt to leave it running.
+       if [ -f /etc/iscsi/iscsi.initramfs ] ||
+               ( [ -f /run/open-iscsi/shutdown-keep-sessions ] && [ -n "$(cat /run/open-iscsi/shutdown-keep-sessions)" ] )
+       then
+               return
+       fi
+       do_stop "$@"
+}
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/iscsid.service b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/iscsid.service
new file mode 100644 (file)
index 0000000..c98fd7e
--- /dev/null
@@ -0,0 +1,19 @@
+[Unit]
+Description=iSCSI initiator daemon (iscsid)
+Documentation=man:iscsid(8)
+Wants=network-online.target remote-fs-pre.target
+Before=remote-fs-pre.target
+After=network.target network-online.target
+DefaultDependencies=no
+Conflicts=shutdown.target
+Before=shutdown.target
+ConditionVirtualization=!private-users
+
+[Service]
+Type=forking
+PIDFile=/run/iscsid.pid
+ExecStartPre=/lib/open-iscsi/startup-checks.sh
+ExecStart=/sbin/iscsid
+
+[Install]
+WantedBy=sysinit.target
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/iscsiuio.init b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/iscsiuio.init
new file mode 100644 (file)
index 0000000..5c7a298
--- /dev/null
@@ -0,0 +1,24 @@
+#!/bin/sh
+# kFreeBSD do not accept scripts as interpreters, using #!/bin/sh and sourcing.
+if [ true != "$INIT_D_SCRIPT_SOURCED" ] ; then
+    set "$0" "$@"; INIT_D_SCRIPT_SOURCED=true . /lib/init/init-d-script
+fi
+### BEGIN INIT INFO
+# Provides:          iscsiuio
+# Required-Start:    $network $local_fs
+# Required-Stop:     $network $local_fs sendsigs
+# X-Start-Before:    iscsid
+# X-Stop-After:      iscsid
+# Default-Start:     S
+# Default-Stop:      0 1 6
+# Short-Description: iSCSI userspace offloading daemon (iscsiuio)
+# Description:       Userspace daemon required for the hardware iSCSI
+#                    offloading functionality of QLogic (formerly
+#                    Broadcom) NetXtreme II cards.
+### END INIT INFO
+
+# Author: Christian Seiler <christian@iwakd.de>
+
+DESC="iSCSI userspace offloading daemon (iscsiuio)"
+DAEMON=/sbin/iscsiuio
+PIDFILE=/run/iscsiuio.pid
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/iscsiuio.install b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/iscsiuio.install
new file mode 100644 (file)
index 0000000..0e4f1ba
--- /dev/null
@@ -0,0 +1,2 @@
+debian/extra/initramfs/hooks/iscsiuio usr/share/initramfs-tools/hooks/
+usr/sbin/iscsiuio sbin/
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/iscsiuio.manpages b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/iscsiuio.manpages
new file mode 100644 (file)
index 0000000..635cb26
--- /dev/null
@@ -0,0 +1 @@
+usr/share/man/man8/iscsiuio.8
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/iscsiuio.service b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/iscsiuio.service
new file mode 100644 (file)
index 0000000..2bbe9b0
--- /dev/null
@@ -0,0 +1,18 @@
+[Unit]
+Description=iSCSI userspace offloading daemon (iscsiuio)
+Documentation=man:iscsiuio(8)
+Documentation=file:///usr/share/doc/iscsiuio/README.gz
+Wants=network.target
+Before=iscsid.service
+After=network.target
+DefaultDependencies=no
+Conflicts=shutdown.target
+Before=shutdown.target
+
+[Service]
+Type=forking
+PIDFile=/run/iscsiuio.pid
+ExecStart=/sbin/iscsiuio
+
+[Install]
+WantedBy=sysinit.target
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/libopeniscsiusr-dev.install b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/libopeniscsiusr-dev.install
new file mode 100644 (file)
index 0000000..e43b95c
--- /dev/null
@@ -0,0 +1 @@
+usr/include
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/libopeniscsiusr-dev.manpages b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/libopeniscsiusr-dev.manpages
new file mode 100644 (file)
index 0000000..d1ba8ca
--- /dev/null
@@ -0,0 +1,57 @@
+usr/share/man/man3/iscsi_iface_name_get.3
+usr/share/man/man3/iscsi_ifaces_get.3
+usr/share/man/man3/iscsi_session_username_in_get.3
+usr/share/man/man3/iscsi_is_default_iface.3
+usr/share/man/man3/iscsi_session_lu_reset_tmo_get.3
+usr/share/man/man3/iscsi_iface_dump_config.3
+usr/share/man/man3/iscsi_iface_port_speed_get.3
+usr/share/man/man3/iscsi_iface_free.3
+usr/share/man/man3/libopeniscsiusr.h.3
+usr/share/man/man3/iscsi_session_persistent_address_get.3
+usr/share/man/man3/iscsi_iface_transport_name_get.3
+usr/share/man/man3/iscsi_iface_netdev_get.3
+usr/share/man/man3/iscsi_node_tpgt_get.3
+usr/share/man/man3/iscsi_session_recovery_tmo_get.3
+usr/share/man/man3/iscsi_node_conn_port_get.3
+usr/share/man/man3/iscsi_context_log_func_set.3
+usr/share/man/man3/iscsi_iface_hwaddress_get.3
+usr/share/man/man3/iscsi_node_iface_name_get.3
+usr/share/man/man3/iscsi_node_dump_config.3
+usr/share/man/man3/iscsi_sessions_free.3
+usr/share/man/man3/iscsi_session_port_get.3
+usr/share/man/man3/iscsi_default_iface_setup.3
+usr/share/man/man3/iscsi_session_tpgt_get.3
+usr/share/man/man3/iscsi_session_sid_get.3
+usr/share/man/man3/iscsi_context_free.3
+usr/share/man/man3/iscsi_context_userdata_get.3
+usr/share/man/man3/iscsi_sessions_get.3
+usr/share/man/man3/iscsi_iface_ipaddress_get.3
+usr/share/man/man3/iscsi_session_free.3
+usr/share/man/man3/iscsi_node_conn_is_ipv6.3
+usr/share/man/man3/iscsi_iface_iname_get.3
+usr/share/man/man3/iscsi_context_log_priority_get.3
+usr/share/man/man3/iscsi_node_conn_address_get.3
+usr/share/man/man3/iscsi_session_tgt_reset_tmo_get.3
+usr/share/man/man3/iscsi_log_priority_str.3
+usr/share/man/man3/iscsi_strerror.3
+usr/share/man/man3/iscsi_context_new.3
+usr/share/man/man3/iscsi_ifaces_free.3
+usr/share/man/man3/iscsi_session_target_name_get.3
+usr/share/man/man3/iscsi_node_portal_get.3
+usr/share/man/man3/iscsi_session_get.3
+usr/share/man/man3/iscsi_session_username_get.3
+usr/share/man/man3/iscsi_nodes_get.3
+usr/share/man/man3/iscsi_session_password_get.3
+usr/share/man/man3/iscsi_node_print_config.3
+usr/share/man/man3/iscsi_session_persistent_port_get.3
+usr/share/man/man3/iscsi_context_userdata_set.3
+usr/share/man/man3/iscsi_session_iface_get.3
+usr/share/man/man3/iscsi_nodes_free.3
+usr/share/man/man3/iscsi_session_abort_tmo_get.3
+usr/share/man/man3/iscsi_context_log_priority_set.3
+usr/share/man/man3/iscsi_node_target_name_get.3
+usr/share/man/man3/iscsi_iface_print_config.3
+usr/share/man/man3/iscsi_iface_port_state_get.3
+usr/share/man/man3/iscsi_session_password_in_get.3
+usr/share/man/man3/iscsi_iface_get.3
+usr/share/man/man3/iscsi_session_address_get.3
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/libopeniscsiusr.install b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/libopeniscsiusr.install
new file mode 100644 (file)
index 0000000..a408b93
--- /dev/null
@@ -0,0 +1 @@
+usr/lib/${DEB_HOST_MULTIARCH}/libopeniscsiusr*.so.*
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/not-installed b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/not-installed
new file mode 100644 (file)
index 0000000..b2a4673
--- /dev/null
@@ -0,0 +1,17 @@
+etc/iscsi/ifaces/iface.example
+etc/iscsi/initiatorname.iscsi
+etc/logrotate.d/iscsiuiolog
+etc/udev/rules.d/50-iscsi-firmware-login.rules
+sbin/iscsi-gen-initiatorname
+sbin/iscsi_fw_login
+sbin/iscsi_offload
+usr/lib/systemd/system-generators/ibft-rule-generator
+usr/lib/systemd/system/iscsi-init.service
+usr/lib/systemd/system/iscsi.service
+usr/lib/systemd/system/iscsid.service
+usr/lib/systemd/system/iscsiuio.service
+usr/lib/systemd/system/iscsiuio.socket
+usr/lib/${DEB_HOST_MULTIARCH}/libopeniscsiusr.so
+usr/lib/${DEB_HOST_MULTIARCH}/pkgconfig/libopeniscsiusr.pc
+usr/sbin/brcm_iscsiuio
+usr/share/man/man8/iscsi_fw_login.8
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/open-iscsi-udeb.install b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/open-iscsi-udeb.install
new file mode 100644 (file)
index 0000000..50d7e64
--- /dev/null
@@ -0,0 +1,10 @@
+debian/tmp-udeb/etc/iscsi/iscsid.conf etc/iscsi/
+debian/tmp-udeb/sbin/iscsiadm sbin/
+debian/tmp-udeb/sbin/iscsid sbin/
+debian/tmp-udeb/sbin/iscsi_discovery sbin/
+debian/tmp-udeb/sbin/iscsi-iname sbin/
+debian/tmp-udeb/sbin/iscsistart sbin/
+debian/extra/udeb/iscsi-start sbin/
+debian/extra/udeb/finish-install.d/10open-iscsi usr/lib/finish-install.d/
+# Ship shared libraries along with the executable in a single udeb
+debian/tmp-udeb/usr/lib/${DEB_HOST_MULTIARCH}/libopeniscsiusr*.so.* usr/lib/${DEB_HOST_MULTIARCH}/
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/open-iscsi.default b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/open-iscsi.default
new file mode 100644 (file)
index 0000000..8cb4e2f
--- /dev/null
@@ -0,0 +1,67 @@
+# List of LVMed iSCSI Volume Groups.
+# Multiple Volume Groups can be specified with spaces
+#
+# This list defines the Volume Groups that should be activated at boot
+# after iSCSI has been activated. If you use dynamic activation of LVM
+# volumes (lvmetad), you can (and should) leave this empty.
+#
+# On shutdown, this setting typically has no effect, since open-iscsi
+# tries to determine all active VGs on iSCSI and deactivate them.
+# However, if you have a really complicated stacking setup that isn't
+# automatically detected, volume groups defined here will also be
+# deactivated.
+#
+# To see whether open-iscsi is able to properly detect your setup for
+# shutdown, execute the following on a running system:
+#    /lib/open-iscsi/umountiscsi.sh --dry-run
+# This will tell you what steps will betaken at shutdown before logging
+# out of the iSCSI session.
+LVMGROUPS=""
+
+
+# Handle _netdev devices
+# You can specify your iSCSI (LVMed or Multipathed or DM Encrypted)
+# devices with the _netdev mount option and open-iscsi will treat them
+# accordingly.
+#
+# Note: however, handling _netdev devices comes with the caveat that
+# other _netdev mounts, like an NFS share, also get pulled in with it.
+#
+# If this option is set to 0, no iSCSI mounts in /etc/fstab will be
+# automatically mounted on systems running sysvinit. This setting is
+# not necessary when using systemd as init system (Debian's default).
+HANDLE_NETDEV=1
+
+
+# Additional mounts to exclude at shutdown.
+#
+# If you have additional mounts on iSCSI that shouldn't be umounted at
+# shutdown by open-iscsi (by default, open-iscsi excludes / and on
+# systemd systems als /usr), place them here. iSCSI sessions that carry
+# these mounts will also be kept open.
+#
+# If any of these mountpoints contain spaces, please use the same
+# escaping as in /etc/fstab, i.e. replace the spaces with \040.
+EXCLUDE_MOUNTS_AT_SHUTDOWN=""
+
+
+
+# Don't logout from ANY iSCSI session on shutdown
+#
+# When shutting down, if the root filesystem is on iSCSI, open-iscsi
+# tries to determine which sessions are still required for the root
+# filesystem. By default, the host will still logout from all other
+# sessions.
+#
+# If you are running a very complicated setup of your root filesystem
+# (multiple mapping levels stacked on top of each other), it may be the
+# case that the autodetection logic doesn't work propery. You may then
+# enable this setting to keep around all iSCSI sessions.
+#
+# Note that /etc/iscsi/iscsi.initramfs must exist for this option to
+# have any effect at all.
+#
+# This was the default behavior in previous versions of this package
+# up to the version that shipped with Debian 8 (Jessie).
+#
+ISCSI_ROOT_KEEP_ALL_SESSIONS_AT_SHUTDOWN=0
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/open-iscsi.finalrd b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/open-iscsi.finalrd
new file mode 100755 (executable)
index 0000000..d0f4352
--- /dev/null
@@ -0,0 +1,47 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-3.0-only
+
+set -e
+
+if [ "$1" = "setup" ]
+then
+    . /usr/share/initramfs-tools/hook-functions
+    copy_exec /bin/grep
+    copy_exec /bin/sleep
+    copy_exec /sbin/iscsiadm
+    copy_exec /sbin/iscsid
+    # hm, not sure why expr is copied
+    copy_exec /usr/bin/expr
+    copy_file config /etc/iscsi/iscsid.conf
+    copy_file config /etc/iscsi/initiatorname.iscsi
+    # needed to resolve UIDs (LP: #1922976)
+    copy_exec /usr/lib/*/libnss_files.so.*
+    exit 0
+fi
+
+# if not present in the environment, then fake a trivial passwd file (LP: #1922976)
+if [ ! -e /etc/passwd ] ; then
+    echo "root:x:0:0:root:/:/bin/sh" > /etc/passwd
+fi
+
+# re-establish connection and logout during shutdown
+# if initramfs did bring up open-iscsi on boot
+[ -f /open-iscsi.interface ] || exit 0
+
+iscsid
+
+# After restarting iscsid, wait for an active connection.
+# Limit the wait time in case of unexpected failure of iscsid.
+MAX_RETRIES=30
+RETRY=0
+while ! iscsiadm -m session -P 1 | grep -q "iSCSI Connection State: LOGGED IN"; do
+    RETRY=$(($RETRY + 1))
+    if [ $RETRY -gt $MAX_RETRIES ]; then
+        echo "Unexpected iSCSI Connection State, forcing iSCSI logout."
+        break
+    fi
+    sleep 1
+done
+
+# Issue an iSCSI logout.
+iscsiadm -m node -u
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/open-iscsi.init b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/open-iscsi.init
new file mode 100644 (file)
index 0000000..f443e1e
--- /dev/null
@@ -0,0 +1,113 @@
+#! /bin/sh
+### BEGIN INIT INFO
+# Provides:          open-iscsi iscsi
+# Required-Start:    $network $local_fs iscsid
+# Required-Stop:     $network $local_fs iscsid sendsigs
+# Default-Start:     S
+# Default-Stop:      0 1 6
+# Short-Description: Login to default iSCSI targets
+# Description:       Login to default iSCSI targets at boot and log out
+#                    of all iSCSI targets at shutdown.
+### END INIT INFO
+
+PATH=/sbin:/bin
+DAEMON=/sbin/iscsid
+ADM=/sbin/iscsiadm
+PIDFILE=/run/iscsid.pid
+NAMEFILE=/etc/iscsi/initiatorname.iscsi
+CONFIGFILE=/etc/iscsi/iscsid.conf
+OMITDIR=/run/sendsigs.omit.d
+
+[ -x "$DAEMON" ] || exit 0
+
+. /lib/lsb/init-functions
+
+# Include defaults if available
+if [ -f /etc/default/open-iscsi ]; then
+       . /etc/default/open-iscsi
+fi
+
+
+if [ ! -d /sys/class/ ]; then
+  log_failure_msg "iSCSI requires a mounted sysfs, not started."
+  exit 0
+fi
+
+RETVAL=0
+
+start() {
+       if ! [ -s $PIDFILE ] || ! kill -0 `sed -n 1p $PIDFILE` >/dev/null ; then
+               log_failure_msg "iSCSI initiator daemon not started: not logging in to default targets"
+               exit 1
+       fi
+
+       starttargets
+
+       # activate LVM, mount filesystems, etc.
+       /lib/open-iscsi/activate-storage.sh
+}
+
+starttargets() {
+       log_daemon_msg "Setting up iSCSI targets"
+       echo
+       $ADM -m node --loginall=automatic
+       log_end_msg 0
+}
+
+stoptargets() {
+       log_daemon_msg "Disconnecting iSCSI targets"
+       sync
+       # only logout if daemon is running, iscsiadm hangs otherwise
+        if [ -s $PIDFILE ] && kill -0 `sed -n 1p $PIDFILE` >/dev/null ; then
+               /lib/open-iscsi/logout-all.sh
+        fi
+
+       log_end_msg 0
+}
+
+stop() {
+       # Call umountiscsi.sh to unmount iSCSI devices first (always do
+       # that, regardless of whether root is on iSCSI, umountiscsi.sh
+       # will exclude it - and even if that shouldn't work, the mount
+       # point will be busy)
+       log_daemon_msg "Umounting iSCSI filesystems"
+       /lib/open-iscsi/umountiscsi.sh
+       umount_exit_status=$?
+       log_end_msg $umount_exit_status
+
+       if [ $umount_exit_status -ne 0 ]; then
+               log_failure_msg "Couldn't unmount all iSCSI devices. not logging out from any target."
+               exit 1
+       fi
+
+       stoptargets
+}
+
+restart() {
+       stop
+       start
+}
+
+restarttargets() {
+       stoptargets
+       starttargets
+}
+
+status() {
+       echo Current active iSCSI sessions:
+       $ADM -m session
+}
+
+case "$1" in
+       start|starttargets|stop|stoptargets|restart|restarttargets|status)
+               $1
+               ;;
+       force-reload)
+               restart
+               ;;
+       *)
+               echo "Usage: $0 {start|stop|restart|force-reload|status}"
+               exit 1
+               ;;
+esac
+exit $RETVAL
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/open-iscsi.install b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/open-iscsi.install
new file mode 100644 (file)
index 0000000..419c2af
--- /dev/null
@@ -0,0 +1,18 @@
+etc/iscsi/iscsid.conf
+debian/extra/umountiscsi.sh lib/open-iscsi/
+debian/extra/logout-all.sh lib/open-iscsi/
+debian/extra/startup-checks.sh lib/open-iscsi/
+debian/extra/activate-storage.sh lib/open-iscsi/
+debian/extra/net-interface-handler lib/open-iscsi/
+debian/iscsid.service lib/systemd/system/
+usr/lib/systemd/system/iscsid.socket lib/systemd/system/
+debian/extra/udev/* lib/udev/rules.d/
+debian/open-iscsi.finalrd usr/share/finalrd/
+debian/extra/initramfs/hooks/iscsi usr/share/initramfs-tools/hooks/
+debian/extra/initramfs/local-top/iscsi usr/share/initramfs-tools/scripts/local-top/
+debian/extra/initramfs/local-bottom/iscsi usr/share/initramfs-tools/scripts/local-bottom/
+sbin/iscsiadm
+sbin/iscsid
+sbin/iscsi_discovery
+sbin/iscsi-iname
+sbin/iscsistart
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/open-iscsi.links b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/open-iscsi.links
new file mode 100644 (file)
index 0000000..96e050d
--- /dev/null
@@ -0,0 +1 @@
+sbin/iscsiadm usr/bin/iscsiadm
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/open-iscsi.manpages b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/open-iscsi.manpages
new file mode 100644 (file)
index 0000000..eaa6e74
--- /dev/null
@@ -0,0 +1,6 @@
+usr/share/man/man8/iscsid.8
+usr/share/man/man8/iscsistart.8
+usr/share/man/man8/iscsi-gen-initiatorname.8
+usr/share/man/man8/iscsiadm.8
+usr/share/man/man8/iscsi_discovery.8
+usr/share/man/man8/iscsi-iname.8
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/open-iscsi.postinst b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/open-iscsi.postinst
new file mode 100644 (file)
index 0000000..505f7c1
--- /dev/null
@@ -0,0 +1,150 @@
+#!/bin/sh
+
+. /usr/share/debconf/confmodule
+
+set -e
+
+restore_old_timeouts()
+{
+    if [ -s /run/open-iscsi/upgrade/restore_old_timeouts ] ; then
+        sh /run/open-iscsi/upgrade/restore_old_timeouts || :
+    fi
+    rm -f /run/open-iscsi/upgrade/restore_old_timeouts
+    [ ! -d /run/open-iscsi/upgrade ] || rmdir --ignore-fail-on-non-empty /run/open-iscsi/upgrade
+    [ ! -d /run/open-iscsi ] || rmdir --ignore-fail-on-non-empty /run/open-iscsi
+}
+
+case "$1" in
+    configure)
+
+        # Compatibility symlinks
+        for file in iscsid iscsi_discovery iscsi-iname iscsistart; do
+            if [ ! -e /usr/sbin/$file ]; then
+                ln -s /sbin/$file /usr/sbin/$file
+            fi
+        done
+
+        # Generate a unique iSCSI InitiatorName
+        NAMEFILE=/etc/iscsi/initiatorname.iscsi
+        if [ ! -e $NAMEFILE ] && [ -z "$2" ] ; then
+            INAME=$(iscsi-iname -p iqn.1993-08.org.debian:01)
+            if [ -n "$INAME" ] ; then
+                echo "## DO NOT EDIT OR REMOVE THIS FILE!" > $NAMEFILE
+                echo "## If you remove this file, the iSCSI daemon will not start." >> $NAMEFILE
+                echo "## If you change the InitiatorName, existing access control lists" >> $NAMEFILE
+                echo "## may reject this initiator.  The InitiatorName must be unique">> $NAMEFILE
+                echo "## for each iSCSI initiator.  Do NOT duplicate iSCSI InitiatorNames." >> $NAMEFILE
+                printf "InitiatorName=%s\n" "$INAME" >> $NAMEFILE
+                chmod 600 $NAMEFILE
+            else
+                echo "Error: failed to generate an iSCSI InitiatorName, driver cannot start."
+                echo
+                exit 1;
+            fi
+        fi
+    ;;
+
+    abort-upgrade|abort-remove|abort-deconfigure)
+    ;;
+
+    *)
+        echo "postinst called with unknown argument \`$1'" >&2
+        exit 1
+    ;;
+esac
+
+#DEBHELPER#
+
+if [ "$1" = configure ] && [ -n "$2" ] && [ -d /run/systemd/system ] &&
+    systemctl is-active iscsid.service > /dev/null
+then
+    # There already is a check in preinst with a debconf prompt that
+    # allows the administrator to abort. Don't abort here, because
+    # leaving the package in a half-configured state is probably worse.
+    # Just make sure to wait a while to see if recovery happens. If
+    # not, proceed anyway.
+    RETRIES=0
+    while cat /sys/class/iscsi_session/session*/state 2>/dev/null | grep -qv LOGGED_IN ; do
+        if [ $RETRIES -eq 0 ] ; then
+            echo "open-iscsi postinst: since the check in preinst some iSCSI sessions have" >&2
+            echo "                     failed. -> will wait 30s for automatic recovery" >&2
+        fi
+        if [ $RETRIES -gt 30 ]; then
+            echo "open-iscsi postinst: some sessions are still in failed state -> iscsid" >&2
+            echo "                     will be restarted regardless, since that may" >&2
+            echo "                     actually help with the session recovery." >&2
+            break
+        fi
+        RETRIES=$((RETRIES + 1))
+        sleep 1
+    done
+
+    # Before we restart iscsid, we should increase the recovery timeout
+    # significantly. Thanks to Mike Christie (open-iscsi upstream) for
+    # the suggestion. But store the old timeouts and restore them
+    # later.
+    new_timeout=120
+    mkdir -m 0700 -p /run/open-iscsi/upgrade
+    rm -f /run/open-iscsi/upgrade/restore_old_timeouts
+    trap restore_old_timeouts EXIT
+    for settingfile in /sys/class/iscsi_session/session*/recovery_tmo ; do
+        [ -f "${settingfile}" ] || continue
+        setting="$(cat "$settingfile" 2>/dev/null || :)"
+        if [ -n "$setting" ] ; then
+            echo "echo "'"'"${setting}"'"'" > "'"'"${settingfile}"'" 2>/dev/null' >> /run/open-iscsi/upgrade/restore_old_timeouts
+        fi
+        if [ ${new_timeout} -gt ${setting} ] ; then
+            echo ${new_timeout} > "${settingfile}" 2>/dev/null
+        fi
+    done
+
+    # Just in case something goes wrong:
+    sync
+
+    # we want to be able to be explicit to start .service, but follow policy.d
+    # therefore use deb-systemd-invoke
+    deb-systemd-invoke restart iscsid.service || true
+
+    RETRIES=0
+    while cat /sys/class/iscsi_session/session*/state 2>/dev/null | grep -qv LOGGED_IN ; do
+        if [ $RETRIES -eq 0 ]; then
+            echo "open-iscsi postinst: after iscsid restart, waiting for iSCSI sessions" >&2
+            echo "                     to recover. This may take a couple of seconds." >&2
+        fi
+
+        if [ $RETRIES -gt ${new_timeout} ]; then
+            db_reset open-iscsi/upgrade_recovery_error || true
+            db_input critical open-iscsi/upgrade_recovery_error || true
+            db_go
+            break
+        fi
+
+        RETRIES=$((RETRIES + 1))
+        sleep 1
+    done
+
+    restore_old_timeouts
+    trap - EXIT
+fi
+
+if [ "$1" = configure ]; then
+    # With socket based activation one wants iscsid.socket to be active
+    # But on upgrades the iscsid.service might already be active
+    # Due to that directly starting iscsid.socket might fail:
+    #   systemd[1]: iscsid.socket: Socket service iscsid.service already active, refusing.
+    # Therefore check if iscsid.service is:
+    # - active:
+    #    - ok for now, do not start iscsid.socket as it would conflict
+    #    - on a reboot .socket will be started as it is enabled
+    # - inactive:
+    #    - start iscsid.socket - to be ready
+    # In both cases:
+    #    - disable iscsid.service so it only starts by the socket after reboot
+    if [ -d /run/systemd/system ]; then
+        if ! systemctl is-active iscsid.service > /dev/null; then
+            deb-systemd-invoke start iscsid.socket || true
+        fi
+    fi
+fi
+
+exit 0
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/open-iscsi.postrm b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/open-iscsi.postrm
new file mode 100644 (file)
index 0000000..6d816c1
--- /dev/null
@@ -0,0 +1,35 @@
+#!/bin/sh
+# postrm script for open-iscsi
+
+set -e
+
+case "$1" in
+    purge)
+        if [ -d /etc/iscsi ]
+        then
+            rm -rf /etc/iscsi
+        fi
+    ;;
+
+    remove)
+        for _ in iscsi-iname iscsid iscsi_discovery iscsistart
+        do
+            if [ -L /usr/sbin/$_ ]
+            then
+                rm /usr/sbin/$_
+            fi
+        done
+    ;;
+
+    abort-upgrade|upgrade|failed-upgrade|abort-install|disappear)
+    ;;
+
+    *)
+        echo "postrm called with unknown argument \`$1'" >&2
+        exit 1
+    ;;
+esac
+
+#DEBHELPER#
+
+exit 0
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/open-iscsi.preinst b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/open-iscsi.preinst
new file mode 100644 (file)
index 0000000..1e5016a
--- /dev/null
@@ -0,0 +1,56 @@
+#!/bin/sh
+# preinst script for open-iscsi
+
+. /usr/share/debconf/confmodule
+set -e
+
+case "$1" in
+    install|upgrade)
+        # Determine if we have any iSCSI sessions that are in a failed
+        # state. If so, upgrading iSCSI is dangerous, so ask the user
+        # if they really want to do it. But before prompting, retry a
+        # few times, just in case we hit a bad moment where a TCP
+        # connection was being reestablished.
+        RETRIES=0
+        while cat /sys/class/iscsi_session/session*/state 2>/dev/null | grep -qv LOGGED_IN ; do
+            if [ $RETRIES -gt 5 ]; then
+                db_reset open-iscsi/upgrade_even_with_failed_sessions || true
+                db_input critical open-iscsi/upgrade_even_with_failed_sessions || true
+                db_go
+                db_get open-iscsi/upgrade_even_with_failed_sessions
+                if [ "$RET" = "false" ] ; then
+                    echo "Aborting preinst due to user request." >&2
+                    exit 1
+                fi
+                break
+            fi
+
+            RETRIES=$((RETRIES + 1))
+            sleep 1
+        done
+    ;;
+
+    abort-upgrade)
+    ;;
+
+    *)
+        echo "preinst called with unknown argument \`$1'" >&2
+        exit 1
+    ;;
+esac
+
+if [ "$1" = "upgrade" ] && dpkg --compare-versions "$2" le-nl "2.0.873+git0.3b4b4500-12" ; then
+    # /etc/iscsi/initiatorname.iscsi is no longer a conffile, so we rename it
+    # to .dpkg-backup so that dpkg will not mark it as an obsolete conffile
+    # on upgrading (which could cause some administrators to accidentally
+    # remove the file even though they need it while removing obsolete
+    # conffiles) - and then in postinst we will rename it back to
+    # initiatorname.iscsi.
+    if [ -f /etc/iscsi/initiatorname.iscsi ] ; then
+        mv -f /etc/iscsi/initiatorname.iscsi /etc/iscsi/initiatorname.iscsi.dpkg-backup
+    fi
+fi
+
+#DEBHELPER#
+
+exit 0
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/open-iscsi.prerm b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/open-iscsi.prerm
new file mode 100644 (file)
index 0000000..64eb19c
--- /dev/null
@@ -0,0 +1,40 @@
+#!/bin/sh
+# prerm script for open-iscsi
+
+. /usr/share/debconf/confmodule
+set -e
+
+case "$1" in
+    remove)
+        if ls -d /sys/class/iscsi_session/session* >/dev/null 2>&1 ; then
+            # There are still active iSCSI sessions. Ask the user
+            # if they know what they are doing.
+            db_reset open-iscsi/remove_even_with_active_sessions || true
+            db_input critical open-iscsi/remove_even_with_active_sessions || true
+            db_go
+            db_get open-iscsi/remove_even_with_active_sessions
+            if [ "$RET" = "false" ] ; then
+                echo "Aborting prerm due to user request." >&2
+                exit 1
+            fi
+        fi
+
+        sync
+        # If there are still active and mounted iSCSI sessions,
+        # open-iscsi stop may fail. But we did warn the user...
+        invoke-rc.d open-iscsi stop || true
+        invoke-rc.d iscsid stop || exit $?
+    ;;
+
+    upgrade|deconfigure|failed-upgrade)
+    ;;
+
+    *)
+        echo "prerm called with unknown argument \`$1'" >&2
+        exit 1
+    ;;
+esac
+
+#DEBHELPER#
+
+exit 0
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/open-iscsi.service b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/open-iscsi.service
new file mode 100644 (file)
index 0000000..06f83fe
--- /dev/null
@@ -0,0 +1,31 @@
+[Unit]
+Description=Login to default iSCSI targets
+Documentation=man:iscsiadm(8) man:iscsid(8)
+Wants=network-online.target remote-fs-pre.target
+After=network-online.target iscsid.service
+Before=remote-fs-pre.target
+DefaultDependencies=no
+Conflicts=shutdown.target
+Before=shutdown.target
+# Must have some pre-defined targets to login to
+ConditionDirectoryNotEmpty=|/etc/iscsi/nodes
+# or have a session to use via iscsid
+ConditionDirectoryNotEmpty=|/sys/class/iscsi_session
+
+[Service]
+Type=oneshot
+RemainAfterExit=true
+# iscsiadm --login will return 21 if no nodes are configured,
+# and 15 if a session is alread logged in (which we do not
+# consider an error)
+SuccessExitStatus=15 21
+# Note: iscsid will be socket activated by iscsiadm
+ExecStart=/sbin/iscsiadm -m node --loginall=automatic
+ExecStart=/lib/open-iscsi/activate-storage.sh
+ExecStop=/lib/open-iscsi/umountiscsi.sh
+ExecStop=/bin/sync
+ExecStop=/lib/open-iscsi/logout-all.sh
+
+[Install]
+WantedBy=sysinit.target
+Alias=iscsi.service
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/open-iscsi.templates b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/open-iscsi.templates
new file mode 100644 (file)
index 0000000..5b09fa1
--- /dev/null
@@ -0,0 +1,71 @@
+# These templates have been reviewed by the debian-l10n-english
+# team
+#
+# If modifications/additions/rewording are needed, please ask
+# debian-l10n-english@lists.debian.org for advice.
+#
+# Even minor modifications require translation updates and such
+# changes should be coordinated with translators and reviewers.
+
+Template: open-iscsi/remove_even_with_active_sessions
+Type: boolean
+#flag:translate!:6,8
+_Description: Proceed with removing open-iscsi?
+ There are currently active iSCSI sessions. If you remove open-iscsi
+ now this may lead to data loss and/or hang the system at shutdown.
+ .
+ Do not do this if this system's root filesystem is on iSCSI.
+ .
+ If you do proceed, open-iscsi will try to unmount all filesystems on
+ iSCSI and log out from current sessions. If that fails (because a
+ filesystem is still in use), the kernel will keep the current
+ iSCSI sessions open, but will not perform any recovery if there is an
+ interruption of the network connection (or if the target is rebooted).
+ .
+ If you really intend to remove open-iscsi, you should abort here and
+ then stop open-iscsi:
+ .
+   service open-iscsi stop
+ .
+ If that did not clean up everything, manually umount all filesystems
+ that are on iSCSI, manually dismantle the storage stack, and only then
+ log out from all iSCSI sessions:
+ .
+   iscsiadm -m node --logoutall=all
+ .
+ At that point, it should be safe to remove this package.
+
+Template: open-iscsi/upgrade_even_with_failed_sessions
+Type: boolean
+_Description: Proceed with upgrading open-iscsi?
+ There are currently failed iSCSI sessions. Upgrading open-iscsi may
+ cause data loss.
+ .
+ If you do not proceed, the preinstallation script will be aborted and
+ you will have the option to manually recover the iSCSI sessions. (Note
+ that aborting an upgrade is problematic if you are dist-upgrading your
+ entire system.) You may also recover the iSCSI sessions manually while
+ keeping this prompt open and then choose to proceed. Or you may choose
+ to proceed directly, after which iscsid will be restarted and session
+ recovery will be attempted once more.
+
+Template: open-iscsi/upgrade_recovery_error
+Type: error
+_Description: iSCSI recovery error on upgrade
+ The iscsid daemon was restarted, but couldn't recover all iSCSI sessions.
+ This is bad and could lead to data loss. Please check the system and kernel
+ logs to determine the cause of the issue.
+ .
+ Please do not acknowledge this note until you have fixed the problem
+ from a separate login shell.
+
+Template: open-iscsi/downgrade_and_break_system
+Type: boolean
+_Description: Proceed with downgrading open-iscsi?
+ You are trying to downgrade open-iscsi. Because of changes between the
+ version you are downgrading to and the version currently installed,
+ this downgrade will break the system.
+ .
+ If you really intend to downgrade, please follow the following procedure
+ instead: umount all iSCSI file systems, log out of all iSCSI sessions,
+ back up /etc/iscsi, purge open-iscsi, and reinstall the older version.
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/patches/lp1755858-default-iscsid_conf-to-iscsid_socket.patch b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/patches/lp1755858-default-iscsid_conf-to-iscsid_socket.patch
new file mode 100644 (file)
index 0000000..5c82cd3
--- /dev/null
@@ -0,0 +1,27 @@
+Description: default in iscid.conf to use iscsid.socket
+
+People do not want iscsid to run if not needed.
+To do so it is configured to be socket activated.
+Internally iscsid code has a fallback if the service is missing to run the
+command specified in iscsid.conf as "iscsid.startup".
+Set this to ensure the socket is active instead of calling the binary, which
+would not be what we want anyway as it would not be from the .service context.
+
+Author: Christian Ehrhardt <christian.ehrhardt@canonical.com>
+Bug-Ubuntu: https://bugs.launchpad.net/bugs/1755858
+Reviewed-by: Rafael David Tinoco <rafaeldtinoco@ubuntu.com>
+Last-Update: 2020-08-13
+
+Index: open-iscsi/etc/iscsid.conf
+===================================================================
+--- open-iscsi.orig/etc/iscsid.conf
++++ open-iscsi/etc/iscsid.conf
+@@ -22,7 +22,7 @@
+ # iscsid.startup = /bin/systemctl start iscsid.socket iscsiuio.socket
+ #
+ # Default for Debian and Ubuntu. Uncomment to activate.
+-# iscsid.startup = /bin/systemctl start iscsid.socket
++iscsid.startup = /bin/systemctl start iscsid.socket
+ #
+ # Default if you are not using systemd. Uncomment to activate.
+ # iscsid.startup = /usr/bin/service start iscsid
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/patches/multiarch-path.patch b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/patches/multiarch-path.patch
new file mode 100644 (file)
index 0000000..a5f947a
--- /dev/null
@@ -0,0 +1,18 @@
+Index: open-iscsi/libopeniscsiusr/Makefile
+===================================================================
+--- open-iscsi.orig/libopeniscsiusr/Makefile
++++ open-iscsi/libopeniscsiusr/Makefile
+@@ -17,11 +17,8 @@ SBINDIR ?= $(exec_prefix)/sbin
+ DBROOT ?= $(etcdir)/iscsi
+ ifndef LIB_DIR
+-      ifeq ($(shell test -d /lib64 && echo 1),1)
+-              LIB_DIR=$(prefix)/lib64
+-      else
+-              LIB_DIR=$(prefix)/lib
+-      endif
++      DEB_HOST_MULTIARCH  ?= $(shell dpkg-architecture -qDEB_HOST_MULTIARCH)
++      LIB_DIR=$(prefix)/lib/$(DEB_HOST_MULTIARCH)
+ endif
+ INCLUDE_DIR ?= $(prefix)/include
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/patches/series b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/patches/series
new file mode 100644 (file)
index 0000000..e9127b3
--- /dev/null
@@ -0,0 +1,2 @@
+lp1755858-default-iscsid_conf-to-iscsid_socket.patch
+multiarch-path.patch
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/po/POTFILES.in b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/po/POTFILES.in
new file mode 100644 (file)
index 0000000..4f691d5
--- /dev/null
@@ -0,0 +1 @@
+[type: gettext/rfc822deb] open-iscsi.templates
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/po/cs.po b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/po/cs.po
new file mode 100644 (file)
index 0000000..c87ca0e
--- /dev/null
@@ -0,0 +1,179 @@
+# Czech PO debconf template translation of open-iscsi.
+# Copyright (C) 2015 Michal Simunek <michal.simunek@gmail.com>
+# This file is distributed under the same license as the open-iscsi package.
+# Michal Simunek <michal.simunek@gmail.com>, 2015.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: open-iscsi 2.0.873+git0.3b4b4500-12\n"
+"Report-Msgid-Bugs-To: open-iscsi@packages.debian.org\n"
+"POT-Creation-Date: 2015-09-30 06:58+0200\n"
+"PO-Revision-Date: 2015-10-06 11:15+0200\n"
+"Last-Translator: Michal Simunek <michal.simunek@gmail.com>\n"
+"Language-Team: Czech <debian-l10n-czech@lists.debian.org>\n"
+"Language: cs\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid "Proceed with removing open-iscsi?"
+msgstr "Pokračovat v odstraňování open-iscsi?"
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid ""
+"There are currently active iSCSI sessions. If you remove open-iscsi now this "
+"may lead to data loss and/or hang the system at shutdown."
+msgstr ""
+"V současné době existují aktivní relace iSCSI. Pokud nyní open-iscsi "
+"odstraníte, může dojít ke ztrátě dat anebo to způsobit, že při vypínání "
+"přestane systém reagovat."
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid "Do not do this if this system's root filesystem is on iSCSI."
+msgstr "Tuto akci neprovádějte, pokud je kořenový souborový systém na iSCSI."
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid ""
+"If you do proceed, open-iscsi will try to unmount all filesystems on iSCSI "
+"and log out from current sessions. If that fails (because a filesystem is "
+"still in use), the kernel will keep the current iSCSI sessions open, but "
+"will not perform any recovery if there is an interruption of the network "
+"connection (or if the target is rebooted)."
+msgstr ""
+"Budete-li pokračovat, open-iscsi se pokusí odpojit všechny souborové systémy "
+"na iSCSI a odhlásit se z aktuálních relací. Pokud se toto nezdaří (protože "
+"se souborový systém stále používá), jádro ponechá současné relace iSCSI "
+"otevřené, ale v případě, že dojde k přerušení síťového připojení, nebude "
+"provádět žádnou obnovu (nebo v případě, že se cílové zařízení restartuje)."
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid ""
+"If you really intend to remove open-iscsi, you should abort here and then "
+"stop open-iscsi:"
+msgstr ""
+"Pokud skutečně máte v úmyslu open-iscsi odstranit, měli byste tuto operaci "
+"přerušit a následně open-iscsi zastavit:"
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid ""
+"If that did not clean up everything, manually umount all filesystems that "
+"are on iSCSI, manually dismantle the storage stack, and only then log out "
+"from all iSCSI sessions:"
+msgstr ""
+"Pokud toto vše neodstraní, ručně odpojte všechny souborové systémy, které "
+"jsou na iSCSI, ručně odeberte zásobník úložiště a teprve potom odhlaste "
+"všechny relace iSCSI."
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid "At that point, it should be safe to remove this package."
+msgstr "V tomto okamžiku by mělo být bezpečné tento balíček odstranit."
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:3001
+msgid "Proceed with upgrading open-iscsi?"
+msgstr "Pokračovat v aktualizaci open-iscsi?"
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:3001
+msgid ""
+"There are currently failed iSCSI sessions. Upgrading open-iscsi may cause "
+"data loss."
+msgstr ""
+"V současné době existují přerušené relace iSCSI. Aktualizace open-iscsi může "
+"způsobit ztrátu dat."
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:3001
+msgid ""
+"If you do not proceed, the preinstallation script will be aborted and you "
+"will have the option to manually recover the iSCSI sessions. (Note that "
+"aborting an upgrade is problematic if you are dist-upgrading your entire "
+"system.) You may also recover the iSCSI sessions manually while keeping this "
+"prompt open and then choose to proceed. Or you may choose to proceed "
+"directly, after which iscsid will be restarted and session recovery will be "
+"attempted once more."
+msgstr ""
+"Pokud nebudete pokračovat, předinstalační skript se přeruší a budete mít "
+"možnost relace iSCSI obnovit ručně. (Berte prosím na vědomí, že přerušení "
+"aktualizace je v případě, že aktualizujete celý systém, problematická.) "
+"iSCSI relace můžete také ručně obnovit a zároveň ponechat tuto výzvu "
+"otevřenou a následně zvolit pokračování. Nebo můžete zvolit přímo "
+"pokračovat, načež se restartuje iscsid a ještě jednou se provede pokus o "
+"obnovení relace."
+
+#. Type: error
+#. Description
+#: ../open-iscsi.templates:4001
+msgid "iSCSI recovery error on upgrade"
+msgstr "Chyba obnovení iSCSI při aktualizaci"
+
+#. Type: error
+#. Description
+#: ../open-iscsi.templates:4001
+msgid ""
+"The iscsid daemon was restarted, but couldn't recover all iSCSI sessions. "
+"This is bad and could lead to data loss. Please check the system and kernel "
+"logs to determine the cause of the issue."
+msgstr ""
+"Démon iscsid byl restartován, ale nemohl obnovit všechny relace iSCSI. To je "
+"špatné a mohlo by dojít ke ztrátě dat. Pro zjištění příčiny prosím "
+"zkontrolujte systémový protokol a protokol jádra."
+
+#. Type: error
+#. Description
+#: ../open-iscsi.templates:4001
+msgid ""
+"Please do not acknowledge this note until you have fixed the problem from a "
+"separate login shell."
+msgstr ""
+"Dokud tento problém neopravíte z oddělené konzole, nepřeskakujte prosím toto "
+"upozornění."
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:5001
+msgid "Proceed with downgrading open-iscsi?"
+msgstr "Pokračovat v přechodu na předchozí verzi open-iscsi?"
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:5001
+msgid ""
+"You are trying to downgrade open-iscsi. Because of changes between the "
+"version you are downgrading to and the version currently installed, this "
+"downgrade will break the system."
+msgstr ""
+"Pokoušíte se instalovat předchozí verzi open-iscsi. Z důvodu změn mezi "
+"dřívější verzí, na kterou chcete přejít a právě nainstalovanou verzí, "
+"přechod na tuto předchozí verzi poškodí systém."
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:5001
+msgid ""
+"If you really intend to downgrade, please follow the following procedure "
+"instead: umount all iSCSI file systems, log out of all iSCSI sessions, back "
+"up /etc/iscsi, purge open-iscsi, and reinstall the older version."
+msgstr ""
+"Pokud skutečně máte v úmyslu přejít na předchozí verzi, postupujte prosím "
+"následovně: odpojte všechny souborové systémy na iSCSI, odhlaste všechny "
+"elace iSCSI, zazálohujte /etc/iscsi, úplně odstraňte open-iscsi a znovu "
+"nainstalujte starší verzi."
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/po/da.po b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/po/da.po
new file mode 100644 (file)
index 0000000..a3c6c2d
--- /dev/null
@@ -0,0 +1,179 @@
+# Danish translation open-iscsi.
+# Copyright (C) 2015 open-iscsi & nedenstående oversættere.
+# This file is distributed under the same license as the open-iscsi package.
+# Joe Hansen <joedalton2@yahoo.dk>, 2015.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: open-iscsi\n"
+"Report-Msgid-Bugs-To: open-iscsi@packages.debian.org\n"
+"POT-Creation-Date: 2015-09-30 06:58+0200\n"
+"PO-Revision-Date: 2015-10-15 17:30+01:00\n"
+"Last-Translator: Joe Hansen <joedalton2@yahoo.dk>\n"
+"Language-Team: Danish <debian-l10n-danish@lists.debian.org>\n"
+"Language: da\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid "Proceed with removing open-iscsi?"
+msgstr "Fortsæt med at fjerne open-iscsi?"
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid ""
+"There are currently active iSCSI sessions. If you remove open-iscsi now this "
+"may lead to data loss and/or hang the system at shutdown."
+msgstr ""
+"Der er i øjeblikket aktive iSCSI-sessioner. Hvis du fjerner open-iscsi nu "
+"kan dette føre til datatab og/eller få systemet til at hænge ved nedlukning."
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid "Do not do this if this system's root filesystem is on iSCSI."
+msgstr "Gør ikke dette hvis systemets root-filsystem er på iSCSI."
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid ""
+"If you do proceed, open-iscsi will try to unmount all filesystems on iSCSI "
+"and log out from current sessions. If that fails (because a filesystem is "
+"still in use), the kernel will keep the current iSCSI sessions open, but "
+"will not perform any recovery if there is an interruption of the network "
+"connection (or if the target is rebooted)."
+msgstr ""
+"Hvis du fortsætter, vil open-iscsi forsøge at afmontere alle filsystemer på "
+"iSCSI og logge ud fra de nuværende sessioner. Hvis dette mislykkes (på grund "
+"af at et filsystem stadig er i brug), så vil kernen holde de nuværende iSCSI-"
+"sessioner åbne, men vil ikke udføre gendannelse, hvis der opstår en "
+"afbrydelse af netværksforbindelsen (eller hvis målet genstartes)."
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid ""
+"If you really intend to remove open-iscsi, you should abort here and then "
+"stop open-iscsi:"
+msgstr ""
+"Hvis du virkelig har tænkt dig at fjerne open-iscsi, så skal du afbryde her "
+"og så stoppe open-iscsi:"
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid ""
+"If that did not clean up everything, manually umount all filesystems that "
+"are on iSCSI, manually dismantle the storage stack, and only then log out "
+"from all iSCSI sessions:"
+msgstr ""
+"Hvis dette ikke ryddede alt op, så afmonter manuelt alle filsystemer, som er "
+"på iSCSI, skil manuelt lagerstakken ad og log så først ud fra alle iSCSI-"
+"sessioner:"
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid "At that point, it should be safe to remove this package."
+msgstr "På dette punkt, bør det være sikkert at fjerne denne pakke."
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:3001
+msgid "Proceed with upgrading open-iscsi?"
+msgstr "Fortsæt med at opgradere open-iscsi?"
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:3001
+msgid ""
+"There are currently failed iSCSI sessions. Upgrading open-iscsi may cause "
+"data loss."
+msgstr ""
+"Der er i øjeblikket mislykkede iSCSI-sessioner. Opgradreing af open-iscsi "
+"kan medføre datatab."
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:3001
+msgid ""
+"If you do not proceed, the preinstallation script will be aborted and you "
+"will have the option to manually recover the iSCSI sessions. (Note that "
+"aborting an upgrade is problematic if you are dist-upgrading your entire "
+"system.) You may also recover the iSCSI sessions manually while keeping this "
+"prompt open and then choose to proceed. Or you may choose to proceed "
+"directly, after which iscsid will be restarted and session recovery will be "
+"attempted once more."
+msgstr ""
+"Hvis du ikke fortsætter vil forbrænderskriptet blive afbrudt og du vil få "
+"mulighed for manuelt at gendanne iSCSI-sessionerne. (Bemærk at afbrydelse af "
+"en opgradering er problematisk, hvis du distributionsopgraderer hele dit "
+"system). Du kan også gendanne iSCSI-sessioner manuelt mens denne dialog "
+"holdes åben og så vælge at fortsætte. Eller du kan vælge at fortsætte "
+"direkte, hvorefter iscsid vil blive genstartet og sessionsgendannelse vil "
+"blive forsøgt en gang mere."
+
+#. Type: error
+#. Description
+#: ../open-iscsi.templates:4001
+msgid "iSCSI recovery error on upgrade"
+msgstr "iSCSI-gendannelsesfejl ved opgradering"
+
+#. Type: error
+#. Description
+#: ../open-iscsi.templates:4001
+msgid ""
+"The iscsid daemon was restarted, but couldn't recover all iSCSI sessions. "
+"This is bad and could lead to data loss. Please check the system and kernel "
+"logs to determine the cause of the issue."
+msgstr ""
+"Dæmonen iscsid blev genstartet, men kunne ikke gendanne alle iSCSI-"
+"sessioner. Dette er ikke godt og kan medføre datatab. Kontroller venligst "
+"systemet og kernelogge for at bestemme årsagen til problemstillingen."
+
+#. Type: error
+#. Description
+#: ../open-iscsi.templates:4001
+msgid ""
+"Please do not acknowledge this note until you have fixed the problem from a "
+"separate login shell."
+msgstr ""
+"Bekræft venligst ikke denne besked før du har rettet problemet fra en "
+"separat logindskal."
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:5001
+msgid "Proceed with downgrading open-iscsi?"
+msgstr "Fortsæt med at nedgradere open-iscsi?"
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:5001
+msgid ""
+"You are trying to downgrade open-iscsi. Because of changes between the "
+"version you are downgrading to and the version currently installed, this "
+"downgrade will break the system."
+msgstr ""
+"Du forsøger at nedgradere open-iscsi. På grund af ændringer mellem versionen "
+"du nedgraderer til og versionen installeret, vil nedgradering ødelægge "
+"systemet."
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:5001
+msgid ""
+"If you really intend to downgrade, please follow the following procedure "
+"instead: umount all iSCSI file systems, log out of all iSCSI sessions, back "
+"up /etc/iscsi, purge open-iscsi, and reinstall the older version."
+msgstr ""
+"Hvis du har tænkt dig at nedgradere, så følg venligst denne procedure i "
+"stedet for: Afmonter alle iSCSI-filsystemer, log ud af alle iSCSI-sessioner, "
+"lav en sikkerhedskopi af /etc/iscsi, afinstaller open-iscsi og installer den "
+"ældre version."
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/po/de.po b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/po/de.po
new file mode 100644 (file)
index 0000000..1dde84a
--- /dev/null
@@ -0,0 +1,187 @@
+# German translation of open-iscsi.
+# This file is distributed under the same license as the open-iscsi package.
+# Copyright (C) 2009, Ritesh Raj Sarraf <rrs@researchut.com>.
+# Copyright (C) of this file 2015 Chris Leick <c.leick@vollbio.de>.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: open-iscsi 2.0.873+git0.3b4b4500-12\n"
+"Report-Msgid-Bugs-To: open-iscsi@packages.debian.org\n"
+"POT-Creation-Date: 2015-09-30 06:58+0200\n"
+"PO-Revision-Date: 2015-10-06 21:40+0200\n"
+"Last-Translator: Chris Leick <c.leick@vollbio.de>\n"
+"Language-Team: German <debian-l10n-german@lists.debian.org>\n"
+"Language: de\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=n != 1;\n"
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid "Proceed with removing open-iscsi?"
+msgstr "Soll das Entfernen von Open-iscsi fortgesetzt werden?"
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid ""
+"There are currently active iSCSI sessions. If you remove open-iscsi now this "
+"may lead to data loss and/or hang the system at shutdown."
+msgstr ""
+"Zur Zeit bestehen aktive iSCSI-Sitzungen. Falls Sie Open-iscsi nun "
+"entfernen, kann dies zu Datenverlust und/oder zum Absturz des Systems beim "
+"Herunterfahren führen."
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid "Do not do this if this system's root filesystem is on iSCSI."
+msgstr ""
+"Unterlassen Sie dies, wenn das Wurzeldateisystem des Systems auf iSCSI liegt."
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid ""
+"If you do proceed, open-iscsi will try to unmount all filesystems on iSCSI "
+"and log out from current sessions. If that fails (because a filesystem is "
+"still in use), the kernel will keep the current iSCSI sessions open, but "
+"will not perform any recovery if there is an interruption of the network "
+"connection (or if the target is rebooted)."
+msgstr ""
+"Falls Sie fortfahren, wird Open-iscsi versuchen, alle Dateisysteme auf iSCSI "
+"auszuhängen und sich aus aktuellen Sitzungen abzumelden. Falls dies "
+"fehlschlägt (weil ein Dateisystem immer noch benutzt wird), wird der Kernel "
+"die aktuelle iSCSI-Sitzung geöffnet halten. Er wird allerdings keine "
+"Wiederherstellung durchführen, falls es zu einer Unterbrechung der "
+"Netzwerkverbindung kommt (oder wenn das Ziel neu gestartet wird)."
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid ""
+"If you really intend to remove open-iscsi, you should abort here and then "
+"stop open-iscsi:"
+msgstr ""
+"Falls sie wirklich beabsichtigen, Open-iscsi zu entfernen, sollten Sie hier "
+"abbrechen und dann Open-iscsi stoppen:"
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid ""
+"If that did not clean up everything, manually umount all filesystems that "
+"are on iSCSI, manually dismantle the storage stack, and only then log out "
+"from all iSCSI sessions:"
+msgstr ""
+"Falls dadurch nicht alles aufgeräumt wurde, hängen Sie alle Dateisysteme, "
+"die auf iSCSI liegen, manuell aus. Lösen Sie den Verbund aus "
+"Speicherobjekten manuell auf und melden Sie sich von allen iSCSI-Sitzungen "
+"ab:"
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid "At that point, it should be safe to remove this package."
+msgstr "Danach sollten Sie dieses Paket gefahrlos entfernen können."
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:3001
+msgid "Proceed with upgrading open-iscsi?"
+msgstr "Soll das Upgrade von Open-iscsi fortgesetzt werden?"
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:3001
+msgid ""
+"There are currently failed iSCSI sessions. Upgrading open-iscsi may cause "
+"data loss."
+msgstr ""
+"Derzeit gibt es fehlgeschlagene iSCSI-Sitzungen. Das Upgrade von Open-iscsi "
+"kann zu Datenverlust führen."
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:3001
+msgid ""
+"If you do not proceed, the preinstallation script will be aborted and you "
+"will have the option to manually recover the iSCSI sessions. (Note that "
+"aborting an upgrade is problematic if you are dist-upgrading your entire "
+"system.) You may also recover the iSCSI sessions manually while keeping this "
+"prompt open and then choose to proceed. Or you may choose to proceed "
+"directly, after which iscsid will be restarted and session recovery will be "
+"attempted once more."
+msgstr ""
+"Falls Sie nicht fortfahren, wird das Vorinstallationsskript abgebrochen und "
+"Sie haben die Möglichkeit, die iSCSI-Sitzungen manuell wiederherzustellen. "
+"(Beachten Sie, dass der Abbruch eines Upgrades problematisch ist, falls Sie "
+"ein Dist-Upgrade Ihres kompletten Systems durchführen.) Sie können die iSCSI-"
+"Sitzungen auch manuell wiederherzustellen, während Sie diese Abfrage offen "
+"lassen und danach erst fortfahren. Oder Sie können direkt fortfahren, "
+"wodurch Iscsid neu gestartet und die Sitzungswiederherstellung noch einmal "
+"versucht wird."
+
+#. Type: error
+#. Description
+#: ../open-iscsi.templates:4001
+msgid "iSCSI recovery error on upgrade"
+msgstr "iSCSI-Wiederherstellungsfehler beim Upgrade"
+
+#. Type: error
+#. Description
+#: ../open-iscsi.templates:4001
+msgid ""
+"The iscsid daemon was restarted, but couldn't recover all iSCSI sessions. "
+"This is bad and could lead to data loss. Please check the system and kernel "
+"logs to determine the cause of the issue."
+msgstr ""
+"Der Iscsi-Daemon wurde neu gestartet, konnte jedoch nicht alle iSCSI-"
+"Sitzungen wiederherstellen. Dies ist schlecht und könnte zu Datenverlust "
+"führen. Bitte prüfen Sie die System- und Kernelprotokolle, um die Ursache "
+"des Problems zu bestimmen."
+
+#. Type: error
+#. Description
+#: ../open-iscsi.templates:4001
+msgid ""
+"Please do not acknowledge this note until you have fixed the problem from a "
+"separate login shell."
+msgstr ""
+"Bitte bestätigen Sie diese Notiz nicht, bevor Sie das Problem in einer "
+"separaten Anmelde-Shell behoben haben."
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:5001
+msgid "Proceed with downgrading open-iscsi?"
+msgstr "Soll das Downgrade von Open-iscsi fortgesetzt werden?"
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:5001
+msgid ""
+"You are trying to downgrade open-iscsi. Because of changes between the "
+"version you are downgrading to and the version currently installed, this "
+"downgrade will break the system."
+msgstr ""
+"Sie versuchen, ein Downgrade von Open-iscsi durchzuführen. Aufgrund der "
+"Änderungen zwischen der Version, auf die Sie das Downgrade durchführen und "
+"der derzeit installierten Version, wird dieses Downgrade das System "
+"beschädigen."
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:5001
+msgid ""
+"If you really intend to downgrade, please follow the following procedure "
+"instead: umount all iSCSI file systems, log out of all iSCSI sessions, back "
+"up /etc/iscsi, purge open-iscsi, and reinstall the older version."
+msgstr ""
+"Falls Sie wirklich beabsichtigen, ein Downgrade von Open-iscsi "
+"durchzuführen, gehen Sie stattdessen wie folgt vor: Hängen Sie alle iSCSI-"
+"Dateisysteme aus, melden Sie sich von allen iSCSI-Sitzungen ab, sichern Sie /"
+"etc/iscsi, entfernen Sie Open-iscsi vollständig (purge) und installieren Sie "
+"die ältere Version erneut."
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/po/es.po b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/po/es.po
new file mode 100644 (file)
index 0000000..33682df
--- /dev/null
@@ -0,0 +1,207 @@
+# open-iscsi po-debconf translation to Spanish
+# Copyright (C) 2015 Software in the Public Interest
+# This file is distributed under the same license as the open-iscsi package.
+#
+# Changes:
+# - Initial translation
+# Camaleón <noelamac@gmail.com>, 2015
+#
+# - Updates
+#
+#
+# Traductores, si no conocen el formato PO, merece la pena leer la
+# documentación de gettext, especialmente las secciones dedicadas a este
+# formato, por ejemplo ejecutando:
+# info -n '(gettext)PO Files'
+# info -n '(gettext)Header Entry'
+#
+# Equipo de traducción al español, por favor lean antes de traducir
+# los siguientes documentos:
+#
+# - El proyecto de traducción de Debian al español
+# http://www.debian.org/intl/spanish/
+# especialmente las notas y normas de traducción en
+# http://www.debian.org/intl/spanish/notas
+#
+# - La guía de traducción de po's de debconf:
+# /usr/share/doc/po-debconf/README-trans
+# o http://www.debian.org/intl/l10n/po-debconf/README-trans
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: open-iscsi\n"
+"Report-Msgid-Bugs-To: open-iscsi@packages.debian.org\n"
+"POT-Creation-Date: 2015-09-30 06:58+0200\n"
+"PO-Revision-Date: 2015-10-13 19:12+0200\n"
+"Last-Translator: Camaleón <noelamac@gmail.com>\n"
+"Language-Team: Debian Spanish <debian-l10n-spanish@lists.debian.org>\n"
+"Language: es\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Generator: Virtaal 0.7.1\n"
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid "Proceed with removing open-iscsi?"
+msgstr "¿Desea proceder con la eliminación de open-iscsi?"
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid ""
+"There are currently active iSCSI sessions. If you remove open-iscsi now this "
+"may lead to data loss and/or hang the system at shutdown."
+msgstr ""
+"Todavía hay sesiones iSCSI activas. Si elimina open-iscsi en este momento "
+"podría conllevar la pérdida de datos y/o dejar colgado el sistema al apagar "
+"el equipo."
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid "Do not do this if this system's root filesystem is on iSCSI."
+msgstr "No haga esto si el sistema de archivos raíz se encuentra sobre iSCSI."
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid ""
+"If you do proceed, open-iscsi will try to unmount all filesystems on iSCSI "
+"and log out from current sessions. If that fails (because a filesystem is "
+"still in use), the kernel will keep the current iSCSI sessions open, but "
+"will not perform any recovery if there is an interruption of the network "
+"connection (or if the target is rebooted)."
+msgstr ""
+"Si continúa, open-iscsi intentará desmontar todos los sistemas de archivos "
+"que se encuentran sobre iSCSI y cerrará las sesiones actuales. En caso de "
+"fallo (porque el sistema de archivos se encuentre todavía en uso) el núcleo "
+"mantendrá la sesiones iSCSI actuales abiertas pero no realizará ninguna "
+"operación de recuperación si se interrumpe la conexión de red (o si se "
+"reinicia el target)."
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid ""
+"If you really intend to remove open-iscsi, you should abort here and then "
+"stop open-iscsi:"
+msgstr ""
+"Si realmente desea eliminar open-iscsi, debe abortar este cuadro de diálogo "
+"y después detener open-iscsi:"
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid ""
+"If that did not clean up everything, manually umount all filesystems that "
+"are on iSCSI, manually dismantle the storage stack, and only then log out "
+"from all iSCSI sessions:"
+msgstr ""
+"Si eso no limpia todo, desmonte manualmente todos los sistemas de archivos "
+"que se encuentran sobre iSCSI, desmantele manualmente la pila de "
+"almacenamiento y sólo entonces cierre todas las sesiones iSCSI:"
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid "At that point, it should be safe to remove this package."
+msgstr "En ese momento debe ser seguro eliminar este paquete."
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:3001
+msgid "Proceed with upgrading open-iscsi?"
+msgstr "¿Desea proceder con la actualización de open-iscsi?"
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:3001
+msgid ""
+"There are currently failed iSCSI sessions. Upgrading open-iscsi may cause "
+"data loss."
+msgstr ""
+"Todavía hay sesiones iSCSI fallidas. Actualizar open-iscsi podría conllevar "
+"una pérdida de datos."
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:3001
+msgid ""
+"If you do not proceed, the preinstallation script will be aborted and you "
+"will have the option to manually recover the iSCSI sessions. (Note that "
+"aborting an upgrade is problematic if you are dist-upgrading your entire "
+"system.) You may also recover the iSCSI sessions manually while keeping this "
+"prompt open and then choose to proceed. Or you may choose to proceed "
+"directly, after which iscsid will be restarted and session recovery will be "
+"attempted once more."
+msgstr ""
+"Si no continúa, se abortará el script de preinstalación y tendrá la opción "
+"de recuperar manualmente las sesiones iSCSI (tenga en cuenta que abortar una "
+"actualización es problemático si está ejecutando un dist-upgrade del "
+"sistema). También puede recuperar manualmente las sesiones iSCSI si mantiene "
+"este cuadro de diálogo abierto y decide continuar. O puede elegir continuar "
+"directamente, tras lo cual se reiniciará iscsid y se intentará recuperar la "
+"sesión una vez más."
+
+#. Type: error
+#. Description
+#: ../open-iscsi.templates:4001
+msgid "iSCSI recovery error on upgrade"
+msgstr "Error de recuperación de iSCSI al actualizar"
+
+#. Type: error
+#. Description
+#: ../open-iscsi.templates:4001
+msgid ""
+"The iscsid daemon was restarted, but couldn't recover all iSCSI sessions. "
+"This is bad and could lead to data loss. Please check the system and kernel "
+"logs to determine the cause of the issue."
+msgstr ""
+"El demonio iscsd ha sido reiniciado pero no se han podido recuperar todas "
+"las sesiones iSCSI. Esto es malo y puede conllevar pérdida de datos. "
+"Compruebe el sistema y los registros del núcleo para determinar la causa del "
+"problema."
+
+#. Type: error
+#. Description
+#: ../open-iscsi.templates:4001
+msgid ""
+"Please do not acknowledge this note until you have fixed the problem from a "
+"separate login shell."
+msgstr ""
+"No tenga en cuenta este mensaje hasta que haya corregido el problema desde "
+"un intérprete de órdenes de inicio de sesión independiente."
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:5001
+msgid "Proceed with downgrading open-iscsi?"
+msgstr "¿Desea instalar una versión anterior de open-iscsi?"
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:5001
+msgid ""
+"You are trying to downgrade open-iscsi. Because of changes between the "
+"version you are downgrading to and the version currently installed, this "
+"downgrade will break the system."
+msgstr ""
+"Está intentando instalar una versión anterior de open-iscsi. Debido a los "
+"cambios entre la versión anterior y la versión que se encuentra instalada "
+"actualmente, instalar una versión anterior romperá el sistema."
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:5001
+msgid ""
+"If you really intend to downgrade, please follow the following procedure "
+"instead: umount all iSCSI file systems, log out of all iSCSI sessions, back "
+"up /etc/iscsi, purge open-iscsi, and reinstall the older version."
+msgstr ""
+"Si realmente desea instalar una versión anterior, siga el siguiente "
+"procedimiento: desmonte todos los sistemas de archivos sobre iSCSI, cierre "
+"todas las sesiones iSCSI, realice una copia de seguridad del archivo «/etc/"
+"iscsi», purgue open-iscsi y reinstale la versión más antigua."
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/po/fr.po b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/po/fr.po
new file mode 100644 (file)
index 0000000..b72e772
--- /dev/null
@@ -0,0 +1,184 @@
+# Translation of open-iscsi debconf templates to French.
+# Copyright (C) 2015 French l10n team <debian-l10n-french@lists.debian.org>
+# This file is distributed under the same license as the open-iscsi package.
+# Julien Patriarca <leatherface@debian.org>, 2015.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: open-iscsi\n"
+"Report-Msgid-Bugs-To: open-iscsi@packages.debian.org\n"
+"POT-Creation-Date: 2015-09-30 06:58+0200\n"
+"PO-Revision-Date: 2015-09-30 11:59+0100\n"
+"Last-Translator: Julien Patriarca <leatherface@debian.org>\n"
+"Language-Team: FRENCH <debian-l10n-french@lists.debian.org>\n"
+"Language: fr\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Poedit 1.6.10\n"
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid "Proceed with removing open-iscsi?"
+msgstr "Faut-il vraiment supprimer open-iscsi ?"
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid ""
+"There are currently active iSCSI sessions. If you remove open-iscsi now this "
+"may lead to data loss and/or hang the system at shutdown."
+msgstr ""
+"Des sessions iSCSI sont actuellement actives. Si vous supprimez open-iscsi "
+"maintenant, cela peut entraîner des pertes de données ou bloquer le système "
+"durant son arrêt."
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid "Do not do this if this system's root filesystem is on iSCSI."
+msgstr ""
+"Vous ne devriez pas supprimer open-iscsi si le système de fichiers racine "
+"est basé sur iSCSI."
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid ""
+"If you do proceed, open-iscsi will try to unmount all filesystems on iSCSI "
+"and log out from current sessions. If that fails (because a filesystem is "
+"still in use), the kernel will keep the current iSCSI sessions open, but "
+"will not perform any recovery if there is an interruption of the network "
+"connection (or if the target is rebooted)."
+msgstr ""
+"Si vous continuez, open-iscsi essaiera de démonter tous les systèmes de "
+"fichiers basés sur iSCSI et interrompra toutes les sessions en cours. Si "
+"cela échoue (à cause d'un système de fichiers toujours utilisé), le noyau "
+"conservera ouvertes les sessions iSCSI courantes, mais n'effectuera aucune "
+"récupération si une coupure de la connexion réseau se produit (ou si la "
+"cible est redémarrée)."
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid ""
+"If you really intend to remove open-iscsi, you should abort here and then "
+"stop open-iscsi:"
+msgstr ""
+"Si vous souhaitez réellement supprimer open-iscsi, vous devriez abandonner "
+"maintenant pour arrêter open-iscsi :"
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid ""
+"If that did not clean up everything, manually umount all filesystems that "
+"are on iSCSI, manually dismantle the storage stack, and only then log out "
+"from all iSCSI sessions:"
+msgstr ""
+"Si cela ne nettoie pas tout, veuillez démonter manuellement tous les "
+"systèmes de fichiers basés sur iSCSI, déconnecter la pile de stockage, et, "
+"seulement après, vous déconnecter de toutes les sessions iSCSI :"
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid "At that point, it should be safe to remove this package."
+msgstr "Ensuite seulement, vous pourrez supprimer ce paquet en toute sécurité."
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:3001
+msgid "Proceed with upgrading open-iscsi?"
+msgstr "Faut-il vraiment mettre à jour open-iscsi ?"
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:3001
+msgid ""
+"There are currently failed iSCSI sessions. Upgrading open-iscsi may cause "
+"data loss."
+msgstr ""
+"Des sessions échouées iSCSI existent actuellement. Mettre à jour open-iscsi "
+"peut conduire à des pertes de données."
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:3001
+msgid ""
+"If you do not proceed, the preinstallation script will be aborted and you "
+"will have the option to manually recover the iSCSI sessions. (Note that "
+"aborting an upgrade is problematic if you are dist-upgrading your entire "
+"system.) You may also recover the iSCSI sessions manually while keeping this "
+"prompt open and then choose to proceed. Or you may choose to proceed "
+"directly, after which iscsid will be restarted and session recovery will be "
+"attempted once more."
+msgstr ""
+"Si vous ne continuez pas, le script de pré-installation sera annulé et vous "
+"aurez la possibilité de restaurer manuellement les sessions iSCSI. Veuillez "
+"noter que l'abandon d'une procédure de mise à jour peut poser problème si "
+"vous mettez à jour le système dans sa globalité. Vous pourrez également "
+"restaurer les sessions manuellement tout en conservant cette question "
+"ouverte et ensuite choisir de continuer. Ou bien, vous pourrez choisir de "
+"poursuivre directement après qu'iscsid soit redémarré, et la restauration "
+"des sessions sera alors tentée une fois de plus."
+
+#. Type: error
+#. Description
+#: ../open-iscsi.templates:4001
+msgid "iSCSI recovery error on upgrade"
+msgstr "Erreur de restauration iSCSI lors de la mise à jour"
+
+#. Type: error
+#. Description
+#: ../open-iscsi.templates:4001
+msgid ""
+"The iscsid daemon was restarted, but couldn't recover all iSCSI sessions. "
+"This is bad and could lead to data loss. Please check the system and kernel "
+"logs to determine the cause of the issue."
+msgstr ""
+"Le démon iscsid a été redémarré, mais n'a pas pu restaurer les sessions "
+"iSCSI. Cela pourrait conduire à une perte de données. Veuillez vérifier les "
+"journaux du noyau et du système pour déterminer la cause du problème."
+
+#. Type: error
+#. Description
+#: ../open-iscsi.templates:4001
+msgid ""
+"Please do not acknowledge this note until you have fixed the problem from a "
+"separate login shell."
+msgstr ""
+"Veuillez ne pas acquitter ce message tant que vous n'avez pas réglé le "
+"problème depuis une autre console."
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:5001
+msgid "Proceed with downgrading open-iscsi?"
+msgstr "Faut-il vraiment revenir à une version antérieure d'open-iscsi ?"
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:5001
+msgid ""
+"You are trying to downgrade open-iscsi. Because of changes between the "
+"version you are downgrading to and the version currently installed, this "
+"downgrade will break the system."
+msgstr ""
+"Vous tentez d'installer une version antérieure d'open-iscsi. À cause des "
+"changements entre la version plus ancienne que vous tentez d'installer et la "
+"version actuellement installée, cette opération rendra le système inopérant."
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:5001
+msgid ""
+"If you really intend to downgrade, please follow the following procedure "
+"instead: umount all iSCSI file systems, log out of all iSCSI sessions, back "
+"up /etc/iscsi, purge open-iscsi, and reinstall the older version."
+msgstr ""
+"Si vous avez réellement l'intention de revenir à une version antérieure, "
+"veuillez plutôt suivre la procédure suivante : démontez tous les systèmes de "
+"fichiers basés sur iSCSI, fermez toutes les sessions iSCSI, sauvegardez /etc/"
+"iscsi, purgez open-iscsi, et réinstallez l'ancienne version."
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/po/it.po b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/po/it.po
new file mode 100644 (file)
index 0000000..463b948
--- /dev/null
@@ -0,0 +1,184 @@
+# Italian translation of open-iscsi debconf messages
+# Copyright (C) 2015 open-iscsi package's copyright holder
+# This file is distributed under the same license as the open-iscsi package.
+# Beatrice Torracca <beatricet@libero.it>, 2015.
+msgid ""
+msgstr ""
+"Project-Id-Version: open-iscsi\n"
+"Report-Msgid-Bugs-To: open-iscsi@packages.debian.org\n"
+"POT-Creation-Date: 2015-09-30 06:58+0200\n"
+"PO-Revision-Date: 2015-10-15 10:40+0200\n"
+"Last-Translator: Beatrice Torracca <beatricet@libero.it>\n"
+"Language-Team: Italian <debian-l10n-italian@lists.debian.org>\n"
+"Language: it\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Generator: Virtaal 0.7.1\n"
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid "Proceed with removing open-iscsi?"
+msgstr "Procedere alla rimozione di open-iscsi?"
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid ""
+"There are currently active iSCSI sessions. If you remove open-iscsi now this "
+"may lead to data loss and/or hang the system at shutdown."
+msgstr ""
+"Ci sono sessioni iSCSI attualmente attive. Se si rimuove open-iscsi adesso "
+"ciò potrebbe portare a perdite di dati o a blocchi del sistema al momento "
+"dello spegnimento."
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid "Do not do this if this system's root filesystem is on iSCSI."
+msgstr "Non farlo se il file system radice di questo sistema è su iSCSI."
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid ""
+"If you do proceed, open-iscsi will try to unmount all filesystems on iSCSI "
+"and log out from current sessions. If that fails (because a filesystem is "
+"still in use), the kernel will keep the current iSCSI sessions open, but "
+"will not perform any recovery if there is an interruption of the network "
+"connection (or if the target is rebooted)."
+msgstr ""
+"Se si procede, open-iscsi cercherà di smontare tutti i file system su iSCSI "
+"e disconnettere le sessioni attuali. Se ciò fallisce (perché un file system "
+"è ancora in uso), il kernel manterrà le sessioni iSCSI attuali aperte, ma "
+"non effettuerà alcun ripristino in caso di interruzione della connessione di "
+"rete (o se la destinazione viene riavviata)."
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid ""
+"If you really intend to remove open-iscsi, you should abort here and then "
+"stop open-iscsi:"
+msgstr ""
+"Se si desidera veramente rimuovere open-iscsi, si dovrebbe interrompere qui "
+"e poi fermare open-iscsi:"
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid ""
+"If that did not clean up everything, manually umount all filesystems that "
+"are on iSCSI, manually dismantle the storage stack, and only then log out "
+"from all iSCSI sessions:"
+msgstr ""
+"Se ciò non ripulisce tutto, smontare manualmente tutti i file system che "
+"sono su iSCSI, smantellare manualmente lo stack di archiviazione e solo "
+"allora fare il logout da tutte le sessioni iSCSI:"
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid "At that point, it should be safe to remove this package."
+msgstr ""
+"A quel punto dovrebbe essere possibile rimuovere questo pacchetto in modo "
+"sicuro."
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:3001
+msgid "Proceed with upgrading open-iscsi?"
+msgstr "Procedere all'aggiornamento di open-iscsi?"
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:3001
+msgid ""
+"There are currently failed iSCSI sessions. Upgrading open-iscsi may cause "
+"data loss."
+msgstr ""
+"Ci sono sessioni iSCSI attualmente fallite. L'aggiornamento di open-iscsi "
+"potrebbe portare a perdita di dati."
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:3001
+msgid ""
+"If you do not proceed, the preinstallation script will be aborted and you "
+"will have the option to manually recover the iSCSI sessions. (Note that "
+"aborting an upgrade is problematic if you are dist-upgrading your entire "
+"system.) You may also recover the iSCSI sessions manually while keeping this "
+"prompt open and then choose to proceed. Or you may choose to proceed "
+"directly, after which iscsid will be restarted and session recovery will be "
+"attempted once more."
+msgstr ""
+"Se non si procede, lo script di preinstallazione sarà terminato e si avrà "
+"l'opzione di recuperare manualmente le sessioni iSCSI. (Notare che la "
+"terminazione di un aggiornamento è problematica se si sta facendo il dist-"
+"upgrade di tutto il sistema.) Si possono anche recuperare le sessioni iSCSI "
+"manualmente mentre si tiene questo prompt aperto e poi scegliere di "
+"procedere. Oppure si può scegliere di procedere direttamente, dopo di che "
+"iscsid sarà riavviato e verrà tentato nuovamente il recupero delle sessioni."
+
+#. Type: error
+#. Description
+#: ../open-iscsi.templates:4001
+msgid "iSCSI recovery error on upgrade"
+msgstr "Errore di ripristino di iSCSI durante l'aggiornamento"
+
+#. Type: error
+#. Description
+#: ../open-iscsi.templates:4001
+msgid ""
+"The iscsid daemon was restarted, but couldn't recover all iSCSI sessions. "
+"This is bad and could lead to data loss. Please check the system and kernel "
+"logs to determine the cause of the issue."
+msgstr ""
+"Il demone iscsid è stato riavviato ma non ha potuto recuperare tutte le "
+"sessioni iSCSI. Ciò non è corretto e potrebbe portare a perdita di dati. "
+"Controllare i log di sistema e del kernel per determinare la causa del "
+"problema."
+
+#. Type: error
+#. Description
+#: ../open-iscsi.templates:4001
+msgid ""
+"Please do not acknowledge this note until you have fixed the problem from a "
+"separate login shell."
+msgstr ""
+"Non procedere oltre questo avvertimento fino a che non si è risolto il "
+"problema da una shell di login separata."
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:5001
+msgid "Proceed with downgrading open-iscsi?"
+msgstr "Procedere con la retrocessione di open-iscsi?"
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:5001
+msgid ""
+"You are trying to downgrade open-iscsi. Because of changes between the "
+"version you are downgrading to and the version currently installed, this "
+"downgrade will break the system."
+msgstr ""
+"Si sta cercando di retrocedere a una versione precedente di open-iscsi. A "
+"causa di cambiamenti tra la versione a cui si sta retrocedendo e quella "
+"attualmente installata, questa retrocessione renderà il sistema non "
+"funzionante."
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:5001
+msgid ""
+"If you really intend to downgrade, please follow the following procedure "
+"instead: umount all iSCSI file systems, log out of all iSCSI sessions, back "
+"up /etc/iscsi, purge open-iscsi, and reinstall the older version."
+msgstr ""
+"Se si ha veramente intenzione di retrocedere, seguire invece la seguente "
+"procedura: smontare tutti i file system iSCSI, fare il logout da tutte le "
+"sessioni iSCSI, fare il backup di /etc/iscsi, rimuovere completamente "
+"(«purge») open-iscsi e reinstallare la versione più vecchia."
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/po/nl.po b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/po/nl.po
new file mode 100644 (file)
index 0000000..3743aa3
--- /dev/null
@@ -0,0 +1,188 @@
+# Dutch translation of open-iscsi debconf templates.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the open-iscsi package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+# Frans Spiesschaert <Frans.Spiesschaert@yucom.be>, 2015.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: open-iscsi\n"
+"Report-Msgid-Bugs-To: open-iscsi@packages.debian.org\n"
+"POT-Creation-Date: 2015-09-30 06:58+0200\n"
+"PO-Revision-Date: 2015-09-30 12:00+0200\n"
+"Last-Translator: Frans Spiesschaert <Frans.Spiesschaert@yucom.be>\n"
+"Language-Team: Debian Dutch l10n Team <debian-l10n-dutch@lists.debian.org>\n"
+"Language: nl\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Generator: Gtranslator 2.91.6\n"
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid "Proceed with removing open-iscsi?"
+msgstr "Voortgaan met het verwijderen van open-iscsi?"
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid ""
+"There are currently active iSCSI sessions. If you remove open-iscsi now this "
+"may lead to data loss and/or hang the system at shutdown."
+msgstr ""
+"Er zijn momenteel iSCSI-sessies actief. Indien u nu open-iscsi verwijdert, "
+"kan dit leiden tot verlies van gegevens en/of kan het systeem vastlopen "
+"wanneer het uitgeschakeld wordt."
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid "Do not do this if this system's root filesystem is on iSCSI."
+msgstr ""
+"Doe dit niet indien het basisbestandsysteem van dit systeem op ISCSI staat."
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid ""
+"If you do proceed, open-iscsi will try to unmount all filesystems on iSCSI "
+"and log out from current sessions. If that fails (because a filesystem is "
+"still in use), the kernel will keep the current iSCSI sessions open, but "
+"will not perform any recovery if there is an interruption of the network "
+"connection (or if the target is rebooted)."
+msgstr ""
+"Indien u voortgaat, zal open-iscsi trachten alle bestandssystemen op iSCSI "
+"af te koppelen en alle actieve sessies af te sluiten. Indien dat niet lukt "
+"(omdat er nog een bestandssysteem in gebruik is), zal de kernel de actieve "
+"iSCSI-sessies open houden, maar ze niet herstellen in het geval er een "
+"netwerkonderbreking optreedt (of het doelsysteem opnieuw opgestart wordt, "
+"enz.)."
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid ""
+"If you really intend to remove open-iscsi, you should abort here and then "
+"stop open-iscsi:"
+msgstr ""
+"Indien u open-iscsi werkelijk wenst te verwijderen, moet u de huidige "
+"operatie hier afbreken en vervolgens open-iscsi stoppen:"
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid ""
+"If that did not clean up everything, manually umount all filesystems that "
+"are on iSCSI, manually dismantle the storage stack, and only then log out "
+"from all iSCSI sessions:"
+msgstr ""
+"Indien hierdoor niet alles opgeruimd werd, moet u handmatig alle "
+"bestandssystemen die zich op iSCSI bevinden afkoppelen, handmatig de "
+"opslagstack liquideren en u pas dan afmelden bij alle iSCSI-sessies:"
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid "At that point, it should be safe to remove this package."
+msgstr ""
+"Nadien zou het verwijderen van dit pakket veilig moeten kunnen gebeuren."
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:3001
+msgid "Proceed with upgrading open-iscsi?"
+msgstr "Voortgaan met het opwaarderen van open-iscsi?"
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:3001
+msgid ""
+"There are currently failed iSCSI sessions. Upgrading open-iscsi may cause "
+"data loss."
+msgstr ""
+"Er zijn momenteel iSCSI-sessies die fouten vertonen. Het opwaarderen van "
+"open-iscsi kan tot gegevensverlies leiden."
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:3001
+msgid ""
+"If you do not proceed, the preinstallation script will be aborted and you "
+"will have the option to manually recover the iSCSI sessions. (Note that "
+"aborting an upgrade is problematic if you are dist-upgrading your entire "
+"system.) You may also recover the iSCSI sessions manually while keeping this "
+"prompt open and then choose to proceed. Or you may choose to proceed "
+"directly, after which iscsid will be restarted and session recovery will be "
+"attempted once more."
+msgstr ""
+"Indien u niet voortgaat, zal dit script dat voor de eigenlijke installatie "
+"uitgevoerd wordt, afgebroken worden en zult u de mogelijkheid hebben om "
+"handmatig de iSCSI-sessies te herstellen. (Weet dat een opwaardering "
+"afbreken problematisch is indien u de hele distributie op uw systeem aan het "
+"opwaarderen bent.) U kunt de iSCSI-sessies ook handmatig herstellen terwijl "
+"u deze prompt open houdt en nadien kiezen om voort te gaan. U kunt ook "
+"onmiddellijk kiezen om voort te gaan. In dat geval zal iscsid opnieuw "
+"gestart worden en er zal een nieuwe poging tot sessieherstel gedaan worden."
+
+#. Type: error
+#. Description
+#: ../open-iscsi.templates:4001
+msgid "iSCSI recovery error on upgrade"
+msgstr ""
+"Bij het opwaarderen trad een fout op tijdens een hersteloperatie van iSCSI"
+
+#. Type: error
+#. Description
+#: ../open-iscsi.templates:4001
+msgid ""
+"The iscsid daemon was restarted, but couldn't recover all iSCSI sessions. "
+"This is bad and could lead to data loss. Please check the system and kernel "
+"logs to determine the cause of the issue."
+msgstr ""
+"De achtergronddienst iscsid werd opnieuw gestart maar slaagde er niet in "
+"alle iSCSI-sessies te herstellen. Dit is niet goed en kan leiden tot "
+"gegevensverlies. Gelieve uw systeem- en kernellogboeken te raadplegen om de "
+"oorzaak van dit probleem te achterhalen."
+
+#. Type: error
+#. Description
+#: ../open-iscsi.templates:4001
+msgid ""
+"Please do not acknowledge this note until you have fixed the problem from a "
+"separate login shell."
+msgstr ""
+"Bevestig niet dat u deze aantekening gelezen heeft vooraleer u zich in een "
+"aparte shell aangemeld hebt en het probleem er opgelost hebt."
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:5001
+msgid "Proceed with downgrading open-iscsi?"
+msgstr "Voortgaan met het degraderen van open-iscsi?"
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:5001
+msgid ""
+"You are trying to downgrade open-iscsi. Because of changes between the "
+"version you are downgrading to and the version currently installed, this "
+"downgrade will break the system."
+msgstr ""
+"U probeert open-iscsi te degraderen. Wegens de verschillen tussen de versie "
+"waarnaar u degradeert en die welke momenteel geïnstalleerd is, zal deze "
+"degradatie uw systeem onklaar maken."
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:5001
+msgid ""
+"If you really intend to downgrade, please follow the following procedure "
+"instead: umount all iSCSI file systems, log out of all iSCSI sessions, back "
+"up /etc/iscsi, purge open-iscsi, and reinstall the older version."
+msgstr ""
+"Indien u echt wilt degraderen, gelieve dan eerder de volgende procedure te "
+"volgen: koppel alle iSCSI-bestandssystemen af, meld u af bij alle iSCSI-"
+"sessies, maak een reservekopie van /etc/iscsi, wis open-iscsi en "
+"herinstalleer de oudere versie."
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/po/pt.po b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/po/pt.po
new file mode 100644 (file)
index 0000000..631e93f
--- /dev/null
@@ -0,0 +1,182 @@
+# Translation of open-iscsi's debconf messages to European Portuguese
+# Copyright (C) 2015 THE open-iscsi'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the open-iscsi package.
+#
+# Américo Monteiro <a_monteiro@gmx.com>, 2015.
+msgid ""
+msgstr ""
+"Project-Id-Version: open-iscsi 2.0.873+git0.3b4b4500-12\n"
+"Report-Msgid-Bugs-To: open-iscsi@packages.debian.org\n"
+"POT-Creation-Date: 2015-09-30 06:58+0200\n"
+"PO-Revision-Date: 2015-10-14 00:05+0100\n"
+"Last-Translator: Américo Monteiro <a_monteiro@gmx.com>\n"
+"Language-Team: Portuguese <traduz@debianpt.org>\n"
+"Language: pt\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Generator: Lokalize 1.4\n"
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid "Proceed with removing open-iscsi?"
+msgstr "Prosseguir com a remoção do open-iscsi?"
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid ""
+"There are currently active iSCSI sessions. If you remove open-iscsi now this "
+"may lead to data loss and/or hang the system at shutdown."
+msgstr ""
+"Existem sessões actuais activas de iSCSI. Se remover o open-iscsi agora, "
+"isto pode levar a perdas de dados e/ou encravar o sistema durante o desligar."
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid "Do not do this if this system's root filesystem is on iSCSI."
+msgstr ""
+"Não faça isto se o sistema de ficheiros raiz deste sistema estiver em iSCSI."
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid ""
+"If you do proceed, open-iscsi will try to unmount all filesystems on iSCSI "
+"and log out from current sessions. If that fails (because a filesystem is "
+"still in use), the kernel will keep the current iSCSI sessions open, but "
+"will not perform any recovery if there is an interruption of the network "
+"connection (or if the target is rebooted)."
+msgstr ""
+"Se prosseguir, o open-iscsi ira tentar desmontar todos os sistemas de "
+"ficheiros em iSCSI e terminar as sessões actuais, se tal falhar (porque um "
+"sistema de ficheiros está a ser usado), o kernel irá manter as sessões iSCSI "
+"actuais abertas, mas não irá executar nenhuma recuperação se existir uma "
+"interrupção na ligação de rede (ou se a máquina destino for reiniciada)."
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid ""
+"If you really intend to remove open-iscsi, you should abort here and then "
+"stop open-iscsi:"
+msgstr ""
+"Se realmente pretende remover o open-iscsi, deve abortar agora aqui e depois "
+"parar o open-iscsi:"
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid ""
+"If that did not clean up everything, manually umount all filesystems that "
+"are on iSCSI, manually dismantle the storage stack, and only then log out "
+"from all iSCSI sessions:"
+msgstr ""
+"Se isso não limpar tudo, desmonte manualmente todos os sistemas de ficheiros "
+"que estão em iSCSI, desmonte manualmente a pilha de armazenamento, e só "
+"depois termine todas as sessões iSCSI. "
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid "At that point, it should be safe to remove this package."
+msgstr "Nessa altura, deverá ser seguro remover este pacote."
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:3001
+msgid "Proceed with upgrading open-iscsi?"
+msgstr "Prosseguir com a actualização do open-iscsi?"
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:3001
+msgid ""
+"There are currently failed iSCSI sessions. Upgrading open-iscsi may cause "
+"data loss."
+msgstr ""
+"Existem sessões actuais de iSCSI com falha. Actualizar o open-iscsi pode "
+"causar perdas de dados."
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:3001
+msgid ""
+"If you do not proceed, the preinstallation script will be aborted and you "
+"will have the option to manually recover the iSCSI sessions. (Note that "
+"aborting an upgrade is problematic if you are dist-upgrading your entire "
+"system.) You may also recover the iSCSI sessions manually while keeping this "
+"prompt open and then choose to proceed. Or you may choose to proceed "
+"directly, after which iscsid will be restarted and session recovery will be "
+"attempted once more."
+msgstr ""
+"Se não prosseguir, o script de pré-instalação será abortado e você terá a "
+"opção de recuperar manualmente as sessões iSCSI. (Note que abortar uma "
+"actualização é problemático se estiver a fazer dist-upgrade a todo o seu "
+"sistema.) Você também pode recuperar as sessões iSCSI manualmente enquanto "
+"mantêm este aviso em aberto e depois então escolher prosseguir. Ou pode "
+"escolher prosseguir directamente, onde o iscsid será reiniciado e será "
+"tentada mais uma vez a recuperação de sessão."
+
+#. Type: error
+#. Description
+#: ../open-iscsi.templates:4001
+msgid "iSCSI recovery error on upgrade"
+msgstr "Erro de recuperação do iSCSI durante a actualização"
+
+#. Type: error
+#. Description
+#: ../open-iscsi.templates:4001
+msgid ""
+"The iscsid daemon was restarted, but couldn't recover all iSCSI sessions. "
+"This is bad and could lead to data loss. Please check the system and kernel "
+"logs to determine the cause of the issue."
+msgstr ""
+"O daemon iscsid foi reiniciado, mas foi incapaz de recuperar todos as "
+"sessões iSCSI. Isto é mau e pode levar a perdas de dados. Por favor "
+"verifique os relatórios (logs) do sistema e do kernel para determinar a "
+"causa do problema."
+
+#. Type: error
+#. Description
+#: ../open-iscsi.templates:4001
+msgid ""
+"Please do not acknowledge this note until you have fixed the problem from a "
+"separate login shell."
+msgstr ""
+"Por favor não responda a esta nota até que tenha corrigido este problema a "
+"partir de uma linha de comandos separada."
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:5001
+msgid "Proceed with downgrading open-iscsi?"
+msgstr "Prosseguir com a regressão do open-iscsi?"
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:5001
+msgid ""
+"You are trying to downgrade open-iscsi. Because of changes between the "
+"version you are downgrading to and the version currently installed, this "
+"downgrade will break the system."
+msgstr ""
+"Você está a tentar regredir (instalar versão anterior) o open-iscsi. Devido "
+"a alterações entre a versão que está a instalar e a que está instalada "
+"actualmente, esta regressão irá estragar o sistema."
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:5001
+msgid ""
+"If you really intend to downgrade, please follow the following procedure "
+"instead: umount all iSCSI file systems, log out of all iSCSI sessions, back "
+"up /etc/iscsi, purge open-iscsi, and reinstall the older version."
+msgstr ""
+"Se realmente pretende regredir a versão instalada, por favor siga o seguinte "
+"procedimento: desmonte todos os sistemas de ficheiros iSCSI, termine todas "
+"as sessões iSCSI, faça cópia de salvaguarda de /etc/iscsi, purgue o open-"
+"iscsi, e depois reinstale a versão anterior."
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/po/pt_BR.po b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/po/pt_BR.po
new file mode 100644 (file)
index 0000000..f81ea25
--- /dev/null
@@ -0,0 +1,181 @@
+# Debconf translations for open-iscsi.
+# Copyright (C) 2015 THE open-iscsi'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the open-iscsi package.
+# Adriano Rafael Gomes <adrianorg@arg.eti.br>, 2015.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: open-iscsi\n"
+"Report-Msgid-Bugs-To: open-iscsi@packages.debian.org\n"
+"POT-Creation-Date: 2015-09-30 06:58+0200\n"
+"PO-Revision-Date: 2015-10-01 21:28-0300\n"
+"Last-Translator: Adriano Rafael Gomes <adrianorg@arg.eti.br>\n"
+"Language-Team: Brazilian Portuguese <debian-l10n-portuguese@lists.debian."
+"org>\n"
+"Language: pt_BR\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid "Proceed with removing open-iscsi?"
+msgstr "Prosseguir com a remoção do open-iscsi?"
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid ""
+"There are currently active iSCSI sessions. If you remove open-iscsi now this "
+"may lead to data loss and/or hang the system at shutdown."
+msgstr ""
+"Existem sessões iSCSI ativas atualmente. Se você remover o open-iscsi agora, "
+"isso pode levar a perda de dados e/ou travamento do sistema ao desligá-lo."
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid "Do not do this if this system's root filesystem is on iSCSI."
+msgstr ""
+"Não faça isso se o sistema de arquivos root desse sistema estiver sobre "
+"iSCSI."
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid ""
+"If you do proceed, open-iscsi will try to unmount all filesystems on iSCSI "
+"and log out from current sessions. If that fails (because a filesystem is "
+"still in use), the kernel will keep the current iSCSI sessions open, but "
+"will not perform any recovery if there is an interruption of the network "
+"connection (or if the target is rebooted)."
+msgstr ""
+"Se você prosseguir, o open-iscsi tentará desmontar todos os sistemas de "
+"arquivos sobre iSCSI e fazer \"log out\" das sessões atuais. Se isso falhar "
+"(porque um sistema de arquivos ainda estiver em uso), o kernel manterá as "
+"sessões iSCSI atuais abertas, mas não executará qualquer recuperação se "
+"houver uma interrupção na conexão de rede (ou se o alvo for reinicializado)."
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid ""
+"If you really intend to remove open-iscsi, you should abort here and then "
+"stop open-iscsi:"
+msgstr ""
+"Se você realmente pretende remover o open-iscsi, você deve cancelar aqui e "
+"então parar o open-iscsi:"
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid ""
+"If that did not clean up everything, manually umount all filesystems that "
+"are on iSCSI, manually dismantle the storage stack, and only then log out "
+"from all iSCSI sessions:"
+msgstr ""
+"Se isso não tiver limpado tudo, desmonte manualmente todos os sistemas de "
+"arquivos que estejam sobre iSCSI, desfaça a pilha de armazenamento, e "
+"somente então faça \"log out\" de todas as sessões iSCSI:"
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid "At that point, it should be safe to remove this package."
+msgstr "Nesse ponto, deve ser seguro remover esse pacote."
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:3001
+msgid "Proceed with upgrading open-iscsi?"
+msgstr "Prosseguir com a atualização do open-iscsi?"
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:3001
+msgid ""
+"There are currently failed iSCSI sessions. Upgrading open-iscsi may cause "
+"data loss."
+msgstr ""
+"Existem sessões iSCSI falhadas atualmente. Atualizar o open-iscsi pode "
+"causar perda de dados."
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:3001
+msgid ""
+"If you do not proceed, the preinstallation script will be aborted and you "
+"will have the option to manually recover the iSCSI sessions. (Note that "
+"aborting an upgrade is problematic if you are dist-upgrading your entire "
+"system.) You may also recover the iSCSI sessions manually while keeping this "
+"prompt open and then choose to proceed. Or you may choose to proceed "
+"directly, after which iscsid will be restarted and session recovery will be "
+"attempted once more."
+msgstr ""
+"Se você não prosseguir, o script de pré instalação será cancelado e você "
+"terá a opção de recuperar manualmente as sessões iSCSI. (Note que cancelar "
+"uma atualização é problemático se você estiver fazendo um \"dist-upgrade\" "
+"de seu sistema todo.) Você também pode recuperar as sessões iSCSI "
+"manualmente enquanto mantém essa tela aberta e depois escolher prosseguir. "
+"Ou você pode escolher prosseguir diretamente, após o que o iscsid reiniciará "
+"e a recuperação de sessões será tentada mais uma vez."
+
+#. Type: error
+#. Description
+#: ../open-iscsi.templates:4001
+msgid "iSCSI recovery error on upgrade"
+msgstr "Erro de recuperação iSCSI na atualização"
+
+#. Type: error
+#. Description
+#: ../open-iscsi.templates:4001
+msgid ""
+"The iscsid daemon was restarted, but couldn't recover all iSCSI sessions. "
+"This is bad and could lead to data loss. Please check the system and kernel "
+"logs to determine the cause of the issue."
+msgstr ""
+"O daemon iscsid foi reiniciado, mas não conseguiu recuperar todas as sessões "
+"iSCSI. Isso é ruim e pode levar a perda de dados. Por favor, verifique os "
+"\"logs\" do kernel e do sistema para descobrir a causa do problema."
+
+#. Type: error
+#. Description
+#: ../open-iscsi.templates:4001
+msgid ""
+"Please do not acknowledge this note until you have fixed the problem from a "
+"separate login shell."
+msgstr ""
+"Por favor, não confirme esse aviso até que você tenha corrigido o problema a "
+"partir de um \"login shell\" separado."
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:5001
+msgid "Proceed with downgrading open-iscsi?"
+msgstr "Prosseguir com o rebaixamento de versão do open-iscsi?"
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:5001
+msgid ""
+"You are trying to downgrade open-iscsi. Because of changes between the "
+"version you are downgrading to and the version currently installed, this "
+"downgrade will break the system."
+msgstr ""
+"Você está tentando rebaixar a versão do open-iscsi. Por causa de mudanças "
+"entre a versão para a qual você está rebaixando e a versão instalada "
+"atualmente, esse rebaixamento de versão quebrará o sistema."
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:5001
+msgid ""
+"If you really intend to downgrade, please follow the following procedure "
+"instead: umount all iSCSI file systems, log out of all iSCSI sessions, back "
+"up /etc/iscsi, purge open-iscsi, and reinstall the older version."
+msgstr ""
+"Se você realmente pretende rebaixar a versão, por favor, ao invés disso siga "
+"este procedimento: desmonte todos os sistemas de arquivos iSCSI, faça \"log "
+"out\" de todas as sessões iSCSI, faça um cópia de /etc/iscsi, expurgue o "
+"open-iscsi, e reinstale a versão antiga."
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/po/ru.po b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/po/ru.po
new file mode 100644 (file)
index 0000000..716121e
--- /dev/null
@@ -0,0 +1,182 @@
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the open-iscsi package.
+#
+# Yuri Kozlov <yuray@komyakino.ru>, 2015.
+msgid ""
+msgstr ""
+"Project-Id-Version: open-iscsi 2.0.873+git0.3b4b4500-12\n"
+"Report-Msgid-Bugs-To: open-iscsi@packages.debian.org\n"
+"POT-Creation-Date: 2015-09-30 06:58+0200\n"
+"PO-Revision-Date: 2015-10-12 20:43+0300\n"
+"Last-Translator: Yuri Kozlov <yuray@komyakino.ru>\n"
+"Language-Team: Russian <debian-l10n-russian@lists.debian.org>\n"
+"Language: ru\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
+"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
+"X-Generator: Lokalize 1.5\n"
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid "Proceed with removing open-iscsi?"
+msgstr "Продолжить удаление open-iscsi?"
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid ""
+"There are currently active iSCSI sessions. If you remove open-iscsi now this "
+"may lead to data loss and/or hang the system at shutdown."
+msgstr ""
+"В настоящий момент имеются активные сеансы iSCSI. Если вы удалите open-iscsi "
+"прямо сейчас, то это может привести к потере данных и/или подвисании системы "
+"при выключении."
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid "Do not do this if this system's root filesystem is on iSCSI."
+msgstr ""
+"Не делайте этого, если в качестве корневой файловой системы используется "
+"iSCSI."
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid ""
+"If you do proceed, open-iscsi will try to unmount all filesystems on iSCSI "
+"and log out from current sessions. If that fails (because a filesystem is "
+"still in use), the kernel will keep the current iSCSI sessions open, but "
+"will not perform any recovery if there is an interruption of the network "
+"connection (or if the target is rebooted)."
+msgstr ""
+"При продолжении open-iscsi попытается размонтировать все файловые системы с "
+"iSCSI и отключить все текущие сеансы. Если возникнет ошибка (так как "
+"файловая система всё ещё используется), то ядро оставит текущие сеансы iSCSI "
+"открытыми, но не будет выполнять их восстановление при проблемах с сетью "
+"(или если дальний конец перезагрузится)."
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid ""
+"If you really intend to remove open-iscsi, you should abort here and then "
+"stop open-iscsi:"
+msgstr ""
+"Если вы действительно намерены удалить open-iscsi, то прервите удаление "
+"прямо сейчас и остановите open-iscsi:"
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid ""
+"If that did not clean up everything, manually umount all filesystems that "
+"are on iSCSI, manually dismantle the storage stack, and only then log out "
+"from all iSCSI sessions:"
+msgstr ""
+"Если что-то при этом не очистилось, то вручную размонтируйте все файловые "
+"системы с iSCSI, вручную разберите стек хранения и только затем отключите "
+"все текущие сеансы iSCSI:"
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid "At that point, it should be safe to remove this package."
+msgstr "После этого можно безопасно удалять этот пакет."
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:3001
+msgid "Proceed with upgrading open-iscsi?"
+msgstr "Продолжить обновление open-iscsi?"
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:3001
+msgid ""
+"There are currently failed iSCSI sessions. Upgrading open-iscsi may cause "
+"data loss."
+msgstr ""
+"В настоящий момент имеются сеансы iSCSI с ошибкой. Обновление open-iscsi "
+"может привести к потере данных."
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:3001
+msgid ""
+"If you do not proceed, the preinstallation script will be aborted and you "
+"will have the option to manually recover the iSCSI sessions. (Note that "
+"aborting an upgrade is problematic if you are dist-upgrading your entire "
+"system.) You may also recover the iSCSI sessions manually while keeping this "
+"prompt open and then choose to proceed. Or you may choose to proceed "
+"directly, after which iscsid will be restarted and session recovery will be "
+"attempted once more."
+msgstr ""
+"При отказе от продолжения предустановочный сценарий будет прерван и вы "
+"можете вручную восстановить сеансы iSCSI (заметим, что прерывание обновления "
+"проблематично, если вы выполняете обновление всей системы с дистрибутива). "
+"Также вы можете восстановить сеансы iSCSI вручную оставив это окно с "
+"предложением открытым и затем выберете продолжить. Или вы можете выбрать "
+"продолжить сразу, после чего будет перезапущен iscsid и будет предпринята "
+"ещё одна попытка восстановления сеанса."
+
+#. Type: error
+#. Description
+#: ../open-iscsi.templates:4001
+msgid "iSCSI recovery error on upgrade"
+msgstr "Ошибка восстановления iSCSI при обновлении"
+
+#. Type: error
+#. Description
+#: ../open-iscsi.templates:4001
+msgid ""
+"The iscsid daemon was restarted, but couldn't recover all iSCSI sessions. "
+"This is bad and could lead to data loss. Please check the system and kernel "
+"logs to determine the cause of the issue."
+msgstr ""
+"Служба iscsid была перезапущена, но не смогла восстановить все сеансы iSCSI. "
+"Это плохо и могло привести к потере данных. Чтобы найти причину проблемы "
+"проверьте журналы системы и ядра."
+
+#. Type: error
+#. Description
+#: ../open-iscsi.templates:4001
+msgid ""
+"Please do not acknowledge this note until you have fixed the problem from a "
+"separate login shell."
+msgstr ""
+"Не игнорируйте это замечание, пока не решите проблему в другой оболочке "
+"входа в систему."
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:5001
+msgid "Proceed with downgrading open-iscsi?"
+msgstr "Продолжить установку старой версии open-iscsi?"
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:5001
+msgid ""
+"You are trying to downgrade open-iscsi. Because of changes between the "
+"version you are downgrading to and the version currently installed, this "
+"downgrade will break the system."
+msgstr ""
+"Вы пытаетесь установить версию open-iscsi, которая старее имеющейся. Из-за "
+"разницы в версиях такая установка сломает систему."
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:5001
+msgid ""
+"If you really intend to downgrade, please follow the following procedure "
+"instead: umount all iSCSI file systems, log out of all iSCSI sessions, back "
+"up /etc/iscsi, purge open-iscsi, and reinstall the older version."
+msgstr ""
+"Если вам действительно нужно установить старую версию, то делайте так: "
+"размонтируйте все файловые системы iSCSI, завершите все сеансы iSCSI, "
+"сделайте резервную копию /etc/iscsi, вычистите пакет open-iscsi и "
+"переустановите старую версию."
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/po/templates.pot b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/po/templates.pot
new file mode 100644 (file)
index 0000000..593e65a
--- /dev/null
@@ -0,0 +1,146 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the open-iscsi package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: open-iscsi\n"
+"Report-Msgid-Bugs-To: open-iscsi@packages.debian.org\n"
+"POT-Creation-Date: 2015-09-30 06:58+0200\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid "Proceed with removing open-iscsi?"
+msgstr ""
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid ""
+"There are currently active iSCSI sessions. If you remove open-iscsi now this "
+"may lead to data loss and/or hang the system at shutdown."
+msgstr ""
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid "Do not do this if this system's root filesystem is on iSCSI."
+msgstr ""
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid ""
+"If you do proceed, open-iscsi will try to unmount all filesystems on iSCSI "
+"and log out from current sessions. If that fails (because a filesystem is "
+"still in use), the kernel will keep the current iSCSI sessions open, but "
+"will not perform any recovery if there is an interruption of the network "
+"connection (or if the target is rebooted)."
+msgstr ""
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid ""
+"If you really intend to remove open-iscsi, you should abort here and then "
+"stop open-iscsi:"
+msgstr ""
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid ""
+"If that did not clean up everything, manually umount all filesystems that "
+"are on iSCSI, manually dismantle the storage stack, and only then log out "
+"from all iSCSI sessions:"
+msgstr ""
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:2001
+msgid "At that point, it should be safe to remove this package."
+msgstr ""
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:3001
+msgid "Proceed with upgrading open-iscsi?"
+msgstr ""
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:3001
+msgid ""
+"There are currently failed iSCSI sessions. Upgrading open-iscsi may cause "
+"data loss."
+msgstr ""
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:3001
+msgid ""
+"If you do not proceed, the preinstallation script will be aborted and you "
+"will have the option to manually recover the iSCSI sessions. (Note that "
+"aborting an upgrade is problematic if you are dist-upgrading your entire "
+"system.) You may also recover the iSCSI sessions manually while keeping this "
+"prompt open and then choose to proceed. Or you may choose to proceed "
+"directly, after which iscsid will be restarted and session recovery will be "
+"attempted once more."
+msgstr ""
+
+#. Type: error
+#. Description
+#: ../open-iscsi.templates:4001
+msgid "iSCSI recovery error on upgrade"
+msgstr ""
+
+#. Type: error
+#. Description
+#: ../open-iscsi.templates:4001
+msgid ""
+"The iscsid daemon was restarted, but couldn't recover all iSCSI sessions. "
+"This is bad and could lead to data loss. Please check the system and kernel "
+"logs to determine the cause of the issue."
+msgstr ""
+
+#. Type: error
+#. Description
+#: ../open-iscsi.templates:4001
+msgid ""
+"Please do not acknowledge this note until you have fixed the problem from a "
+"separate login shell."
+msgstr ""
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:5001
+msgid "Proceed with downgrading open-iscsi?"
+msgstr ""
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:5001
+msgid ""
+"You are trying to downgrade open-iscsi. Because of changes between the "
+"version you are downgrading to and the version currently installed, this "
+"downgrade will break the system."
+msgstr ""
+
+#. Type: boolean
+#. Description
+#: ../open-iscsi.templates:5001
+msgid ""
+"If you really intend to downgrade, please follow the following procedure "
+"instead: umount all iSCSI file systems, log out of all iSCSI sessions, back "
+"up /etc/iscsi, purge open-iscsi, and reinstall the older version."
+msgstr ""
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/rules b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/rules
new file mode 100755 (executable)
index 0000000..59dd8e4
--- /dev/null
@@ -0,0 +1,93 @@
+#!/usr/bin/make -f
+# export DH_VERBOSE = 1
+
+export DEB_BUILD_MAINT_OPTIONS = hardening=+all
+DPKG_EXPORT_BUILDFLAGS = 1
+include /usr/share/dpkg/buildflags.mk
+include /usr/share/dpkg/pkg-info.mk
+export KBUILD_BUILD_TIMESTAMP = "@$(SOURCE_DATE_EPOCH)"
+
+UDEB := $(filter open-iscsi-udeb,$(shell dh_listpackages))
+
+ifneq ($(UDEB),)
+TREENAMES = build-deb build-udeb
+else
+TREENAMES = build-deb
+endif
+
+%:
+       dh $@
+
+execute_before_dh_clean:
+       for treename in $(TREENAMES); do \
+               rm -rf debian/$$treename ;\
+       done
+       rm -rf debian/tmp-udeb
+
+execute_before_dh_auto_configure:
+       # no out of tree build support, prepare two source trees
+       for treename in $(TREENAMES); do \
+               mkdir debian/$$treename ;\
+               cp -r -t debian/$$treename $$(find . -mindepth 1 -maxdepth 1 \! -name debian \! -name .git) ;\
+       done
+
+override_dh_auto_configure:
+       for treename in $(TREENAMES); do \
+               cat debian/buildconfig.common debian/buildconfig.$$treename Makefile > debian/$$treename/Makefile ;\
+               CFLAGS="$(CPPFLAGS) $(CFLAGS)" dh_auto_configure --sourcedirectory=debian/$$treename ;\
+               CFLAGS="$(CPPFLAGS) $(CFLAGS)" dh_auto_configure --sourcedirectory=debian/$$treename/iscsiuio ;\
+       done
+
+override_dh_auto_build:
+       for treename in $(TREENAMES); do \
+               CFLAGS="$(CPPFLAGS) $(CFLAGS)" NO_SYSTEMD=$$NO_SYSTEMD dh_auto_build --sourcedirectory=debian/$$treename ;\
+       done
+
+override_dh_auto_install:
+       # workaround upstream makefile parallelism problem
+       dh_auto_install --no-parallel --sourcedirectory=debian/build-deb
+ifneq ($(UDEB),)
+       dh_auto_install --no-parallel --sourcedirectory=debian/build-udeb --destdir=$(CURDIR)/debian/tmp-udeb
+endif
+
+ifneq ($(UDEB),)
+execute_after_dh_install:
+       if strings debian/open-iscsi-udeb/sbin/iscsid | grep libsystemd.so ; then \
+               echo ERROR: udeb linked to libsystemd ;\
+               exit 1 ;\
+       fi
+endif
+
+override_dh_installinit:
+       dh_installinit -p open-iscsi --no-start --no-enable --no-stop-on-upgrade --name=iscsid
+       dh_installinit -p open-iscsi --no-start --no-enable --no-stop-on-upgrade
+       dh_installinit -p iscsiuio --no-start --no-enable --no-stop-on-upgrade
+
+override_dh_installsystemd:
+       dh_installsystemd -p open-iscsi --no-restart-on-upgrade iscsid.socket
+       dh_installsystemd -p open-iscsi --no-restart-on-upgrade open-iscsi.service
+       dh_installsystemd -p iscsiuio --no-restart-on-upgrade iscsiuio.service
+
+override_dh_installdocs:
+       dh_installdocs -p open-iscsi README sysfs-documentation THANKS
+       dh_installdocs -p iscsiuio iscsiuio/RELEASE.TXT iscsiuio/README
+       dh_installdocs -p libopeniscsiusr
+       dh_installdocs -p libopeniscsiusr-dev
+
+override_dh_makeshlibs:
+ifneq ($(UDEB),)
+       dh_makeshlibs --add-udeb=open-iscsi-udeb
+else
+       dh_makeshlibs
+endif
+
+# The following is taken from the initramfs-tools package. (We recommend
+# busybox in the initramfs because otherwise we don't have access to the
+# ip utility to set the default gateway after iscsistart -N is done.)
+# On Debian we can use either busybox or busybox-static, but on Ubuntu
+# and derivatives only busybox-initramfs will work.
+BUSYBOX_PACKAGES := $(shell if dpkg-vendor --derives-from ubuntu; then echo busybox-initramfs; else echo busybox busybox-static; fi)
+
+override_dh_gencontrol:
+       echo >> debian/open-iscsi.substvars "busybox:Recommends=$(wordlist 2,100,$(BUSYBOX_PACKAGES:%=| %))"
+       dh_gencontrol
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/source/format b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/source/format
new file mode 100644 (file)
index 0000000..163aaf8
--- /dev/null
@@ -0,0 +1 @@
+3.0 (quilt)
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/tests/control b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/tests/control
new file mode 100644 (file)
index 0000000..7b3c9e2
--- /dev/null
@@ -0,0 +1,6 @@
+Tests: install
+Restrictions: needs-root, isolation-machine, breaks-testbed
+
+Tests: nested
+Restrictions: needs-root, isolation-machine, breaks-testbed, allow-stderr
+Depends: targetcli-fb, qemu-system, qemu-utils, python3, python3-netifaces
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/tests/control.nested b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/tests/control.nested
new file mode 100644 (file)
index 0000000..2682ca1
--- /dev/null
@@ -0,0 +1,3 @@
+Tests: login
+Restrictions: needs-root, isolation-machine, breaks-testbed
+Depends: open-iscsi
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/tests/find_free_ip.py b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/tests/find_free_ip.py
new file mode 100755 (executable)
index 0000000..6aa0fbe
--- /dev/null
@@ -0,0 +1,93 @@
+#!/usr/bin/python3
+
+import ipaddress, netifaces, socket, subprocess
+from functools import reduce
+
+# These are the private IP ranges that are available.
+allowed_ranges = list(map(lambda x: ipaddress.IPv4Network(x), [
+  '10.0.0.0/8',
+  '172.16.0.0/12',
+  '192.168.0.0/16'
+]))
+
+# Exclude IP addresses we have already assigned to ourselves
+def network_links():
+  for interface in netifaces.interfaces():
+    for link in netifaces.ifaddresses(interface).get(netifaces.AF_INET, ()):
+      yield link
+own_ranges = [ipaddress.IPv4Network('%s/%s' % (link['addr'], link['netmask']), strict=False) for link in network_links()]
+
+# Exclude any /24 range containing the nameserver
+try:
+  with open('/etc/resolv.conf', 'r') as f:
+    for line in f:
+      line = line.split()
+      if len(line) != 2:
+        continue
+      if line[0] == 'nameserver':
+        try:
+          range = ipaddress.IPv4Network('%s/24' % line[1], strict=False)
+          own_ranges.append(range)
+        except ipaddress.AddressValueError:
+          pass
+except IOError:
+  pass
+
+# Exclude any /24 range containing the APT proxy
+try:
+  for line in subprocess.check_output(['apt-config', 'dump', '--format=%v%n', 'Acquire::http::Proxy']).split(b'\n'):
+    try:
+      line = line.decode()
+      # ignore IPv6
+      if len(line) == 0 or line[0] == '[':
+        continue
+      line = line.split(':')
+      if len(line) > 2:
+        continue
+      port = None
+      if len(line) > 1:
+        port = line[1]
+      for family, type, proto, canonname, addrport in socket.getaddrinfo(line[0], port, family=socket.AddressFamily.AF_INET, type=socket.SocketType.SOCK_STREAM):
+        try:
+          range = ipaddress.IPv4Network('%s/24' % addrport[0], strict=False)
+          own_ranges.append(range)
+        except ipaddress.AddressValueError:
+          pass
+    except (UnicodeDecodeError, socket.gaierror):
+      continue
+except subprocess.CalledProcessError:
+  pass
+
+# First let's try our first choice of a range
+chosen_range = ipaddress.IPv4Network('10.0.4.0/24')
+collides = False
+for own_range in own_ranges:
+  if chosen_range.overlaps(own_range):
+    collides = True
+    break
+
+# If our first go-to IP range collides: subtract that from all
+# private IP ranges and get the first available /24 subnet from
+# there.
+if collides:
+  chosen_range = None
+
+  for own_range in own_ranges:
+    new_allowed_ranges = []
+    for allowed_range in allowed_ranges:
+      if not allowed_range.overlaps(own_range):
+        new_allowed_ranges.append(allowed_range)
+      else:
+        new_allowed_ranges += allowed_range.address_exclude(own_range)
+    allowed_ranges = new_allowed_ranges
+
+  for allowed_range in allowed_ranges:
+    try:
+      chosen_range = next(allowed_range.subnets(new_prefix=24))
+      break
+    except ValueError:
+      pass
+
+base = chosen_range.network_address
+print(str(base + 1))
+
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/tests/install b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/tests/install
new file mode 100755 (executable)
index 0000000..5077b7b
--- /dev/null
@@ -0,0 +1,35 @@
+#!/bin/sh
+
+set -e
+
+die()
+{
+  echo "$@" >&2
+  exit 1
+}
+
+die_with_file()
+{
+  file="$1"
+  shift
+  echo "$@" >&2
+  echo "contents of $file:" >&2
+  cat "$file" >&2
+  exit 1
+}
+
+DEBIAN_FRONTEND=noninteractive apt-get -y install open-iscsi </dev/null
+
+[ -d /etc/iscsi ] || die "/etc/iscsi not a directory"
+
+# Make sure an initiator name was generated
+[ -f /etc/iscsi/initiatorname.iscsi ] || die "/etc/iscsi/initiatorname.iscsi not a file"
+grep -vq '^GenerateName=yes' /etc/iscsi/initiatorname.iscsi || die_with_file /etc/iscsi/initiatorname.iscsi "GenerateName=yes is set"
+grep -q '^InitiatorName=' /etc/iscsi/initiatorname.iscsi || die_with_file /etc/iscsi/initiatorname.iscsi "InitiatorName is not set"
+
+# Make sure the daemon is started
+systemctl is-active iscsid.socket || die "iscsid socket not running"
+# no-op discovery to socket activate service
+iscsiadm -m discovery -t sendtargets -p 127.0.0.1 >/dev/null 2>&1|| /bin/true
+systemctl is-active iscsid.service || die "iscsid service not running"
+pgrep -c iscsid >/dev/null || die "iscsid process not running"
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/tests/login b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/tests/login
new file mode 100755 (executable)
index 0000000..664802e
--- /dev/null
@@ -0,0 +1,38 @@
+#!/bin/sh
+
+set -e
+
+die()
+{
+  echo "$@" >&2
+  exit 1
+}
+
+if [ -z "$ISCSI_TARGET_IP" ] || [ -z "$ISCSI_TARGET_NAME" ] ; then
+  echo "SKIP: skipping current test because ISCSI_TARGET_IP/ISCSI_TARGET_NAME are not set"
+  exit 0
+fi
+
+service iscsid status >/dev/null 2>&1 || die "iscsid not running"
+
+# Discover targets
+iscsiadm -m discovery -t sendtargets -p "$ISCSI_TARGET_IP" || die "iSCSI discovery failed"
+
+# Log in to nodes
+iscsiadm -m node -p "$ISCSI_TARGET_IP" -T "$ISCSI_TARGET_NAME" --login || die "iSCSI login failed"
+
+# Make sure udev had time to process the device events (wait max 60s)
+udevadm settle -t 60 || die "udevadm settle failed"
+
+# Check that we imported a single iSCSI drive
+num_devices=0
+last_device=
+for dev in /sys/class/iscsi_session/session*/device/target*/*\:*/block/* ; do
+  [ -d "$dev/" ] || continue
+  num_devices=$((num_devices + 1))
+  last_device="$dev"
+done
+[ $num_devices -eq 1 ] || die "Found $num_devices iSCSI drives, expected 1 (last device was ${last_device})"
+
+last_device=$(basename $last_device)
+echo "Found 1 iSCSI drive: /dev/$last_device"
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/tests/nested b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/tests/nested
new file mode 100755 (executable)
index 0000000..d7e1b19
--- /dev/null
@@ -0,0 +1,87 @@
+#!/bin/sh
+
+set -e
+
+die()
+{
+  echo "$@" >&2
+  exit 1
+}
+
+if ! [ -e "/dev/baseimage" ] ; then
+  echo "SKIP: skipping nested tests because /dev/baseimage does not exist"
+  exit 0
+fi
+
+ISCSI_IP=$(python3 debian/tests/find_free_ip.py)
+ISCSI_NAME=iqn.2003-01.org.linux-iscsi.debian.autopkgtest
+
+[ -n "$ISCSI_IP" ]      || die "$0: couldn't find free ip to use for iSCSI target"
+[ -n "$ADT_ARTIFACTS" ] || die "$0: ADT_ARTIFACTS not set"
+
+echo "Creating dummy interface with iSCSI target IP $ISCSI_IP"
+
+# Create iSCSI interface
+modprobe dummy
+ip link add name iscsi0 type dummy
+ip link set dev iscsi0 up
+ip -4 addr add "${ISCSI_IP}/24" dev iscsi0
+
+echo "Setting up iSCSI target"
+
+# Create disk image and export it (qemu-img create will be sparse by default)
+qemu-img create -f raw /tmp/iscsi_disk.img 100M
+# Since we add a portal manually, we need to make sure not to automatically
+# add a new portal when creating the initial TPG, otherwise the portal
+# creation command will fail.
+targetcli set global auto_add_default_portal=false
+targetcli backstores/fileio/ create name=disk0 file_or_dev=/tmp/iscsi_disk.img size=100M
+targetcli iscsi/ create "${ISCSI_NAME}"
+targetcli iscsi/"${ISCSI_NAME}"/tpg1/luns/ create /backstores/fileio/disk0
+targetcli iscsi/"${ISCSI_NAME}"/tpg1/portals/ create "$ISCSI_IP" 3260
+targetcli iscsi/"${ISCSI_NAME}"/tpg1/ set attribute authentication=0 demo_mode_write_protect=0 generate_node_acls=1 cache_dynamic_acls=1
+
+BINARY_PATH="$(grep -v ^# /etc/apt/sources.list.d/autopkgtest.list 2>/dev/null | grep -v ^$ | sed 's%.*file://\([^ ]*\) .*%\1%' | head -n 1)"
+
+# Reuse binary packages
+BINARY_ARGS=""
+
+for pkg in "${BINARY_PATH}/"*.deb ; do
+  if [ -f "$pkg" ] ; then
+    BINARY_ARGS="${BINARY_ARGS:+$BINARY_ARGS }$pkg"
+  fi
+done
+
+# We pretend that this is a built tree here, because we don't want to
+# trigger a rebuild. That's fine, because even if there was a build
+# required here, they will have been added to the binary package
+# repository.
+
+echo "Calling nested autopkgtest with debian/tests/control.nested"
+
+# Call autopkgtest for the nested tests; also allocate less RAM than we
+# have, otherwise QEMU won't start. 10/16ths is a good ration, because
+# we haven't started much in this VM - and with a default ram size of
+# 1 GiB (see autopkgtest-qemu) this would give us a reasonable 640 MiB
+# of RAM in the nested VM.
+# FIXME: Possibly add some swap space...
+RAM_SIZE=$(grep MemTotal: /proc/meminfo | awk '{print int($2/1024/16*10)}')
+
+set +e
+autopkgtest -B -o "$ADT_ARTIFACTS/nested" -U --override-control debian/tests/control.nested \
+   --env "ISCSI_TARGET_IP=$ISCSI_IP" --env "ISCSI_TARGET_NAME=$ISCSI_NAME" \
+   $BINARY_ARGS $PWD/ \
+   -- qemu --ram-size $RAM_SIZE /dev/baseimage
+RC=$?
+case $RC in
+  0|2)
+    # adt-run exit code 2 signifies skipped tests - but that shouldn't
+    # cause the outer-layered test to fail
+    exit 0
+    ;;
+  *)
+    exit $RC
+    ;;
+esac
+
+exit 0
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/upstream/metadata b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/upstream/metadata
new file mode 100644 (file)
index 0000000..42f44cc
--- /dev/null
@@ -0,0 +1,5 @@
+---
+Bug-Database: https://github.com/open-iscsi/open-iscsi/issues
+Bug-Submit: https://github.com/open-iscsi/open-iscsi/issues/new
+Repository: https://github.com/open-iscsi/open-iscsi.git
+Repository-Browse: https://github.com/open-iscsi/open-iscsi
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/debian/watch b/pkgs/open-iscsi/open-iscsi-2.1.8/debian/watch
new file mode 100644 (file)
index 0000000..ffdff6a
--- /dev/null
@@ -0,0 +1,3 @@
+version=3
+opts=filenamemangle=s/.+\/v?(\d\S*)\.tar\.gz/open-iscsi-$1\.tar\.gz/ \
+  https://github.com/open-iscsi/open-iscsi/releases .*/v?(\d\S*)\.tar\.gz
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/doc/.gitignore b/pkgs/open-iscsi/open-iscsi-2.1.8/doc/.gitignore
new file mode 100644 (file)
index 0000000..1828889
--- /dev/null
@@ -0,0 +1,4 @@
+iscsi-gen-initiatorname.8
+iscsiadm.8
+iscsid.8
+iscsistart.8
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/doc/Makefile b/pkgs/open-iscsi/open-iscsi-2.1.8/doc/Makefile
new file mode 100644 (file)
index 0000000..882bea1
--- /dev/null
@@ -0,0 +1,55 @@
+# This Makefile will work only with GNU make.
+#
+# Make file for the doc sub-directory
+#
+
+ifeq ($(TOPDIR),)
+       TOPDIR = ..
+endif
+
+SED ?= sed
+INSTALL = install
+
+DESTDIR ?=
+etcdir = /etc
+DBROOT ?= $(etcdir)/iscsi
+HOMEDIR ?= $(etcdir)/iscsi
+
+prefix ?= /usr
+mandir ?= $(prefix)/share/man
+
+MAN8DIR = $(DESTDIR)$(mandir)/man8
+
+MANPAGES_SOURCES       = iscsi_discovery.8 \
+                         iscsi_fw_login.8 \
+                         iscsi-iname.8
+MANPAGES_TEMPLATES     = iscsid.8.template \
+                         iscsiadm.8.template \
+                         iscsi-gen-initiatorname.8 \
+                         iscsistart.8.template
+MANPAGES_GENERATED     = $(MANPAGES_TEMPLATES:.template=)
+MANPAGES_DEST          = $(addprefix $(MAN8DIR)/,$(MANPAGES_GENERATED)) \
+                         $(addprefix $(MAN8DIR)/,$(MANPAGES_SOURCES))
+
+all: $(MANPAGES_GENERATED)
+
+install: install_doc
+
+install_doc: $(MAN8DIR) $(MANPAGES_DEST)
+
+$(MANPAGES_GENERATED): %.8: %.8.template
+       $(SED) -e 's:@HOMEDIR@:$(HOMEDIR):' -e 's:@DBROOT@:$(DBROOT):' $? > $@
+
+$(MANPAGES_DEST): $(MAN8DIR)/%: %
+       $(INSTALL) -m 644 $? $@
+
+
+$(MAN8DIR):
+       [ -d $@ ] || $(INSTALL) -d $@
+
+clean: ;
+
+distclean:
+       $(RM) $(MANPAGES_GENERATED)
+
+.PHONY: all install install_doc clean distclean
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/doc/iscsi-gen-initiatorname.8.template b/pkgs/open-iscsi/open-iscsi-2.1.8/doc/iscsi-gen-initiatorname.8.template
new file mode 100644 (file)
index 0000000..97a6e21
--- /dev/null
@@ -0,0 +1,51 @@
+.TH ISCSI_GEN_INITIATORNAME 8 "APR 2022" "" "Linux Administrator's Manual"
+.SH NAME
+iscsi-gen-initiatorname \- smart iSCSI initiator name generation tool
+.SH SYNOPSIS
+.BI iscsi-gen-initiatorname
+[OPTIONS]
+.SH "DESCRIPTION"
+.B iscsi-gen-initiatorname
+generates an iSCSI Initiator Name in the
+.I initiatorname.iscsi
+file. It is an error to try to overwrite an existing Initiator Name,
+unless the \fB-f\fP (\fIforce\fR) option is supplied.
+.P
+The Initiator Name will be taken from the kernel command line,
+if present (from the \fIrd.initiatorname\fR parameter), else from
+the iBFT subsystem (if present in \fIsysfs\fR), else it will be
+generated using the \fBiscsi-iname\fR command.
+.P
+It is an error if both the kernel command-line Initiator Name
+and the iBFT Initiator Name are both set, and they are different.
+it is also an error to try to write over an Initiator Name file
+if it read-only, or to create one if its directory is not writable.
+.P
+You
+.B must
+be
+.I root
+to run this command.
+.SH OPTIONS
+.TP
+.BI [-h]
+Display a help message and exit.
+.TP
+.BI [-f]
+Force overwrite of existing initiator name, if present.
+.TP
+.BI [-p] \fIIQN-PREFIX\fP
+Use \fIIQN-PREFIX\fP as the prefix to the IQN generated,
+instead of the default of \fBiqn.1996-04.de.suse:01\fP.
+.SH FILES
+.TP
+@HOMEDIR@/initiatorname.iscsi
+The file containing the initiator name. Do not edit manually.
+.SH "SEE ALSO"
+.BR iscsi-iname (8)
+.SH AUTHORS
+Open-iSCSI project <http://www.open-iscsi.com/>
+.br
+Hannes Reinecke <hare@suse.de>
+.br
+Lee Duncan <lduncan@suse.com>
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/doc/iscsi-iname.8 b/pkgs/open-iscsi/open-iscsi-2.1.8/doc/iscsi-iname.8
new file mode 100644 (file)
index 0000000..6a413f6
--- /dev/null
@@ -0,0 +1,22 @@
+.TH ISCSI_INAME 8 "Jan 2010" "" "Linux Administrator's Manual"
+.SH NAME
+iscsi-iname \- iSCSI initiator name generation tool
+.SH SYNOPSIS
+.BI iscsi-iname
+[OPTION]
+.SH "DESCRIPTION"
+.B iscsi-iname
+generates a unique iSCSI node name on every invocation.
+
+.SH OPTIONS
+.TP
+.BI [-h|--help]
+Display help
+.TP
+.BI [-p=]\fIprefix\fP
+Use the prefix passed in instead of the default "iqn.2016-04.com.open-iscsi"
+
+.SH AUTHORS
+Open-iSCSI project <http://www.open-iscsi.com/>
+.br
+Mike Christie <mchristi@redhat.com>
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/doc/iscsi_discovery.8 b/pkgs/open-iscsi/open-iscsi-2.1.8/doc/iscsi_discovery.8
new file mode 100644 (file)
index 0000000..489783a
--- /dev/null
@@ -0,0 +1,62 @@
+.de Vb \" Begin verbatim text
+.ft CW
+.nf
+.ne \\$1
+..
+
+.TH "iscsi_discovery" 8
+.SH NAME
+iscsi_discovery \- discover iSCSI targets
+.SH SYNOPSIS
+.B iscsi_discovery
+.I <IP>
+.RB [ -p
+.IR <port> ]
+.RB [ -d ]
+.RB [\  -t
+.IR <tcp|iser>
+.RB [ -f ]
+]
+.RB [ -m ]
+.RB [ -l ]
+
+.SH DESCRIPTION
+Perform send-targets discovery to the specified IP. If a discovery record
+is generated, try to login to the portal using the preferred transport
+(\-t flag specifies the requested transport type, TCP is the default).
+If login using a certain transport succeeds, mark the portal for automatic
+login (unless \-m flag is used), and disconnect (unless \-l flag is used).
+
+For iSCSI discovery to work, open-iscsi services must be running. i.e. iscsid
+should be up, and the iSCSI modules loaded. This is best accomplished by the
+init.d startup script.
+
+.\" .SH OPTIONS
+.TP
+.BI [-p=]\fIport\-number\fP
+set the port number (default is 3260).
+.TP
+.BI [-d]
+print debugging information.
+.TP
+.BI [-t=]\fItransport\-type\fP
+set transport (default is tcp).
+.TP
+.BI [-f]
+force specific transport -
+disable the fallback to tcp (default is fallback enabled).
+force the transport specified by the argument of the \-t flag.
+
+.TP
+.BI [-m]
+manual startup - will set manual startup (default is automatic startup).
+.TP
+.BI [-l]
+login - login to the new discovered nodes (default is false).
+
+.SH AUTHOR
+Written by Dan Bar Dov
+.SH "REPORTING BUGS"
+Report bugs to <erezzi.list@gmail.com>.
+.SH COPYRIGHT
+Copyright \(co Voltaire Ltd. 2006.
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/doc/iscsi_fw_login.8 b/pkgs/open-iscsi/open-iscsi-2.1.8/doc/iscsi_fw_login.8
new file mode 100644 (file)
index 0000000..e9fccd2
--- /dev/null
@@ -0,0 +1,16 @@
+.TH "iscsi_fw_login" 8
+.SH NAME
+iscsi_fw_login \- Login to all iSCSI Firmware targets
+.SH SYNOPSIS
+.B iscsi_fw_login
+.SH DESCRIPTION
+This helper function logs into all known iSCSI firmware targets.
+.P
+It is meant as a helper function to be called by udev when new
+firmware targets are detected asynchronously.
+.SH AUTHOR
+Written by Lee Duncan
+.SH "REPORTING BUGS"
+Report bugs to <lduncan@suse.com>.
+.SH COPYRIGHT
+Copyright \(co 2015 Lee Duncan <lduncan@suse.com>
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/doc/iscsiadm.8.template b/pkgs/open-iscsi/open-iscsi-2.1.8/doc/iscsiadm.8.template
new file mode 100644 (file)
index 0000000..438e40c
--- /dev/null
@@ -0,0 +1,726 @@
+.TH ISCSIADM 8 "Mar 2022" "" "Linux Administrator's Manual"
+.SH NAME
+iscsiadm \- open-iscsi administration utility
+.SH SYNOPSIS
+.B iscsiadm
+.B \-m discoverydb
+.RB [ \-hV ]
+.RB [ \-d
+.IR debug_level ]
+.RB [ \-P
+.IR printlevel ]
+.RB [ \-I
+.I iface
+.BI \-t\  type\  \-p\  ip:port
+.RB [ \-lD ]
+] | [
+.RB [ \-p
+.I ip:port
+.B \-t
+.IR type ]
+.RB [ \-o
+.IR operation ]
+.RB [ \-n
+.IR name ]
+.RB [ \-v
+.IR value ]
+.RB [ \-lD ]
+]
+.PP
+.B iscsiadm
+.B \-m discovery
+.RB [ \-hV ]
+.RB [ \-d
+.IR debug_level ]
+.RB [ \-P
+.IR printlevel ]
+.RB [ \-I
+.IR iface ]
+.RB [ \-t
+.IR type ]
+.RB [ \-p
+.IR ip:port ]
+.RB [ \-l ]
+.PP
+.B iscsiadm
+.B \-m node
+.RB [ \-hV ]
+.RB [ \-d
+.IR debug_level ]
+.RB [ \-P
+.IR printlevel ]
+.RB [ \-L
+.IR all,manual,automatic,onboot ]
+.RB [ \-W ]
+.RB [ \-U
+.IR all,manual,automatic,onboot ]
+.RB [ \-S ]
+[
+.RB [ \-T
+.IB targetname\  \-p\  ip:port\  \-I
+.IR iface ]
+.RB [ \-l | \-u | \-R | \-s ]
+]
+[
+.RB [ \-o
+.IR operation ]
+.RB [ \-n
+.IR name ]
+.RB [ \-v
+.IR value ]
+.RB [ \-p
+.IR ip:port ]
+]
+.PP
+.B iscsiadm
+.B \-m session
+.RB [ \-hV ]
+.RB [ \-d
+.IR debug_level ]
+.RB [ \-P
+.IR printlevel ]
+.RB [ \-r
+.IR sessionid | sysfsdir
+.RB [ \-R ]
+.RB [ \-u | \-s | \-o
+.IR new ]
+]
+.PP
+.B iscsiadm
+.B \-m iface
+.RB [ \-hV ]
+.RB [ \-d
+.IR debug_level ]
+.RB [ \-P
+.IR printlevel ]
+.RB [ \-I
+.IR ifacename\  |
+.B \-H
+.IR hostno|MAC ]
+[
+.RB [ \-o
+.IR operation ]
+.RB [ \-n
+.IR name ]
+.RB [ \-v
+.IR value ]
+]
+[
+.BI \-C\  ping
+.RB [ \-a
+.IR ip ]
+.RB [ \-b
+.IR packetsize ]
+.RB [ \-c
+.IR count ]
+.RB [ \-i
+.IR interval ]
+]
+.PP
+.B iscsiadm
+.B \-m fw
+.RB [ \-d
+.IR debug_level ]
+.RB [ \-l ]
+.RB [ \-W ]
+.RB [ \-n
+.IR name ]
+.RB [ \-v
+.IR value ]
+.PP
+.B iscsiadm
+.B \-m host
+.RB [ \-P
+.IR printlevel ]
+.RB [ \-H
+.IR hostno|MAC ]
+[
+.RB [ \-C
+.I chap
+.RB [ \-x
+.IR chap_tbl_idx ]
+] |
+.RB [ \-C
+.I flashnode
+.RB [ \-A
+.IR portal_type ]
+.RB [ \-x
+.IR flashnode_idx ]
+] |
+.RB [ \-C
+.IR stats ]
+]
+[
+.RB [ \-o
+.IR operation ]
+.RB [ \-n
+.IR name ]
+.RB [ \-v
+.IR value ]
+]
+.PP
+.B iscsiadm
+.B \-k priority
+.SH DESCRIPTION
+The iscsiadm utility is a command-line tool allowing discovery and login
+to iSCSI targets, as well as access and management of the open-iscsi
+database.
+.PP
+Open-iscsi does not use the term \fInode\fR as defined by the iSCSI RFC,
+where a node is a single iSCSI initiator or target. Open-iscsi uses the
+term \fInode\fR to refer to a portal on a target.
+.PP
+For \fIsession\fR mode, a session id (\fIsid\fR) is used. The \fIsid\fR of a session can be
+found by running \fIiscsiadm \-m session \-P 1\fR. The session id and sysfs
+path are not currently persistent and is partially determined by when the
+session is setup.
+.SH NOTES
+.PP
+Many of the node and discovery operations require that the iSCSI
+daemon (iscsid) be running. If running on a system that uses systemd,
+the daemon may start up automatically, if enabled, when needed.
+.PP
+Open-iscsi has two groups of files it needs to store or get access to,
+while running: the \fBHOMEDIR\fR and the \fBDBROOT\fR. The following
+describes them:
+.TP
+.B Home Directory
+The \fIhome directory\fR for open-iscsi is @HOMEDIR@. This is
+where it keeps it's configuration file (\fIiscsid.conf\fR) and it's
+initiator name file (\fIinitiatorname.iscsi\fR).
+.TP
+.B Database Root Directory
+The \fIdatabase root directory\fR for open-iscsi is @DBROOT@. This
+is where it keeps its flat database files, such as it's list of \fInode\fRs
+(see below).
+.SH OPTIONS
+.TP
+\fB\-a\fR, \fB\-\-ip=\fIipaddr\fP
+\fIipaddr\fR can be IPv4 or IPv6.
+.IP
+This option is only valid for \fIping\fR 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 \fIflashnode\fR submode of \fIhost\fR mode and only with \fInew\fR operation.
+.TP
+\fB\-b\fR, \fB\-\-packetsize=\fIpacketsize\fP
+Specify the ping \fIpacketsize\fR.
+.IP
+This option is only valid for \fIping\fR submode.
+.TP
+\fB\-c\fR, \fB\-\-count=\fIcount\fP
+\fIcount\fR specifies the number of ping iterations.
+.IP
+This option is only valid for \fIping\fR submode.
+.TP
+\fB\-C\fR, \fB\-\-submode=\fIop\fP
+Specify the submode for mode. \fIop\fR must be name of submode.
+.IP
+Currently iscsiadm supports \fIping\fR as a submode for \fIiface\fR. For example:
+.IP
+iscsiadm \-m iface \-I ifacename \-C ping \-a ipaddr \-b packetsize \-c count \-i interval
+.IP
+For \fIhost\fR, it supports \fIchap\fR, \fIflashnode\fR and \fIstats\fR as submodes. For example:
+.IP
+iscsiadm \-m host \-H hostno \-C chap \-x chap_tbl_idx \-o operation
+.IP
+iscsiadm \-m host \-H hostno \-C flashnode \-x flashnode_idx \-o operation
+.IP
+iscsiadm \-m host \-H hostno \-C stats
+.TP
+\fB\-d\fR, \fB\-\-debug=\fIdebug_level\fP
+print debugging information. Valid values for \fIdebug_level\fR are 0 to 8.
+.TP
+\fB\-h\fR, \fB\-\-help\fR
+display help text and exit
+.TP
+\fB\-H\fR, \fB\-\-host=\fI[hostno|MAC]\fR
+The \fIhost\fR argument specifies the SCSI host to use for the operation. It can be
+the scsi host number assigned to the host by the kernel's scsi layer, or the
+MAC address of a scsi host.
+.TP
+\fB\-i\fR, \fB\-\-interval=\fIinterval\fP
+\fIinterval\fP specifies the delay between two ping iterations.
+.IP
+This option is only valid for \fIping\fR submode.
+.TP
+\fB\-I\fR, \fB\-\-interface=\fI[iface]\fR
+The \fIinterface\fR argument specifies the iSCSI interface to use for the operation.
+iSCSI interfaces (\fIiface\fR) are defined in @DBROOT@/ifaces. For hardware
+iSCSI (e.g. qla4xxx) the \fIiface\fR configuration must have the hardware address
+(\fIiface.hwaddress\fR = port's MAC address)
+and the driver/transport_name (\fIiface.transport_name\fR). The \fIiface\fR's name is
+then the filename of the iface configuration. For software iSCSI, the iface configuration
+must have either the hardware address (\fIiface.hwaddress\fR), or the network
+layer's interface name (\fIiface.net_ifacename\fR), and it must have the
+driver/transport_name.
+.IP
+The available drivers/iscsi_transports are \fItcp\fR (software iSCSI over TCP/IP),
+\fIiser\fR (software iSCSI over InfiniBand),
+\fIqla4xxx\fR (Qlogic 4XXXX and 82XXX HBAs),
+\fIcxgb3i\fR and \fIcxgb4i\fR (Chelsio T3 and T4 adapters),
+\fIbnx2i\fR (QLogic Netextreme II adapters),
+\fIbe2iscsi\fR (Emulex 10G adapter),
+\fIqedi\fR (QLogic QEDI 25/40/100Gb adapter), and
+\fIocs\fR (Emulex One Connect storage).
+Some of these are considered experimental, as they are not fully tested.
+.IP
+The \fIhwaddress\fR is the MAC address or for software iSCSI it may be the special
+value \fIdefault\fR which directs the initiator to not bind the session to a
+specific hardware resource and instead allow the network or InfiniBand layer
+to decide what to do. There is no need to create an iface configuration with the default
+behavior. If you do not specify an \fIiface\fR, then the default behavior is used.
+.IP
+As mentioned above there is a special iface name \fIdefault\fR. There are
+others which do not bind the session to a specific card, but instead bind
+the session to the transport:
+\fIiser\fR,
+\fIcxgb3i\fR,
+\fIcxgb4i\fR, and
+\fIbnx2i\fR.
+.IP
+In \fIdiscovery\fR mode multiple interfaces can be specified by passing in
+multiple \fI\-I/\-\-interface\fR instances. For example:
+.IP
+\fBsh#\fR iscsiadm \-m discoverydb \-t st \-p ip:port \-I iface0 \-I iface2 \-\-discover
+.IP
+Will direct iscsiadm to setup the node db to create records which will create
+sessions through the two interfaces passed in.
+.IP
+In \fInode\fR mode, only a single interface is supported in each call to iscsiadm.
+.IP
+This option is valid for \fIdiscovery\fR, \fInode\fR and \fIiface\fR modes.
+.TP
+\fB\-k\fR, \fB\-\-killiscsid=\fI[priority]\fR
+Currently \fIpriority\fR must be zero. This will immediately stop all iscsid
+operations and shutdown iscsid. It does not logout any sessions. Running
+this command is the same as doing \fIkillall iscsid\fR. Neither should
+normally be used, because if iscsid is doing error recovery or if there
+is an error while iscsid is not running, the system may not be able to recover.
+This command and iscsid's SIGTERM handling are experimental.
+.TP
+\fB\-D\fR, \fB\-\-discover\fR
+Discover targets using the discovery record with the \fIrecid\fR matching
+the the discovery type and portal passed in. If there is no matching record,
+it will be created using the iscsid.conf discovery settings.
+This must be passed in to \fIdiscoverydb\fR mode to instruct iscsiadm to perform
+discovery.
+.IP
+This option is only valid for \fISendTargets\fR discovery mode.
+.TP
+\fB\-l\fR, \fB\-\-login\fR
+For \fInode\fR and \fIfw\fR modes, login to a specified record. For \fIdiscovery\fR mode,
+login to all discovered targets.
+.IP
+This option is only valid for \fIdiscovery\fR, \fInode\fR, and \fIfw\fR modes.
+For \fIfw\fR mode only, \fIname\fR and \fIvalue\fR pairs can optionally be passed in,
+so that those values get used for the sessions created. In this case, no \fIop\fR
+is needed, since \fIupdate\fR is assumed.
+.TP
+\fB\-L\fR, \fB\-\-loginall=\fI[all|manual|automatic|onboot]\fR
+For \fInode\fR mode, login to all sessions with the node or conn startup values passed
+in or all running session, except ones marked \fIonboot\fR, if \fIall\fR is passed in.
+.IP
+This option is only valid for \fInode\fR mode (it is valid but not functional
+for \fIsession\fR mode).
+.TP
+\fB\-W\fR, \fB\-\-\-no_wait\fR
+In \fInode\fR, \fIdiscovery\fR, or \fIfw\fR (firmware) mode,
+do not wait for a response from the target(s).
+This means that success will be returned if the command is able to
+send the login requests, whether or not they succeed. In this case, it will
+be up to the caller to poll for success (i.e. session creation).
+.TP
+\fB\-m\fR, \fB\-\-mode \fIop\fR
+specify the mode. \fIop\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 \fIdiscovery\fR, \fIdiscoverydb\fR and
+\fInode\fR mode, all of their respective records are displayed; for \fIsession\fR mode,
+all active sessions and connections are displayed; for \fIfw\fR mode, all boot
+firmware values are displayed; for \fIhost\fR mode, all iSCSI hosts are displayed;
+and for \fIiface\fR mode, all interfaces setup in @DBROOT@/ifaces are displayed.
+.TP
+\fB\-n\fR, \fB\-\-name=\fIname\fR
+In \fInode\fR mode, specify a field \fIname\fR in a record. In \fIflashnode\fR submode
+of \fIhost\fR mode, specify name of the flash node parameter.
+.IP
+For use with the \fIupdate\fR operator.
+.TP
+\fB\-o\fR, \fB\-\-op=\fIop\fR
+Specifies a database operator \fIop\fR. \fIop\fR must be one of
+\fInew\fR, \fIdelete\fR, \fIupdate\fR, \fIshow\fR or \fInonpersistent\fR.
+.IP
+For \fIiface\fR mode, \fIapply\fR and \fIapplyall\fR are also applicable.
+.IP
+For \fIflashnode\fR submode of \fIhost\fR mode, \fIlogin\fR and \fIlogout\fR are also applicable.
+.IP
+This option is valid for all modes except \fIfw\fR. Delete should not be used
+on a running session. If it is iscsiadm will stop the session and then delete the
+record.
+.IP
+An \fIop\fR of \fInew\fR creates a new database record for a given object. In \fInode\fR mode, the
+\fIrecid\fR is the target name and portal (IP:port). In \fIiface\fR mode, the \fIrecid\fR
+is the iface name. In \fIdiscovery\fR mode, the \fIrecid\fR is the portal and
+discovery type.
+.IP
+In \fIsession\fR mode, the \fInew\fR operation logs in a new session using
+the same node database and iface information as the specified session.
+.IP
+In \fIdiscovery\fR mode, if the \fIrecid\fR and \fInew\fR operation is passed in,
+but the \fI\-\-discover\fR argument is not passed in, then iscsiadm will only create a
+discovery record (it will not perform discovery). If the \fI\-\-discover\fR
+argument is passed in with the portal and discovery type, then iscsiadm
+will create the discovery record if needed, and it will create records
+for portals returned by the target that do not yet have a node DB record.
+.IP
+Setting \fIop\fR to \fIdelete\fR deletes the specified \fIrecid\fR. In \fIdiscovery\fR mode, if
+iscsiadm is performing discovery, it will delete records for portals that
+are no longer returned.
+.IP
+Setting \fIop\fR to \fIupdate\fR will update the \fIrecid\fR with \fIname\fR to the specified
+\fIvalue\fR. In discovery mode, if iscsiadm is performing discovery the
+\fIrecid\fR, \fIname\fR and \fIvalue\fR arguments are not needed. The
+update operation will operate on the portals returned by the target,
+and will update the node records with information from the configuration file and
+command line.
+.IP
+The \fIop\fR value of \fIshow\fR is the default behaviour for \fInode\fR,
+\fIdiscovery\fR and \fIiface\fR mode. It is
+also used when there are no commands passed into \fIsession\fR mode and a
+running \fIsid\fR is passed in.
+If \fIname\fR and \fIvalue\fR are passed in, they are currently ignored in \fIshow\fR mode.
+.IP
+An \fIop\fR value of \fInonpersistent\fR instructs iscsiadm to not manipulate the node DB.
+.IP
+An \fIop\fR value of \fIapply\fR will cause the network settings to take effect on the specified iface.
+.IP
+An \fIop\fR value of \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
+An \fIop\fR value of \fIlogin\fR will log into the specified flash node entry.
+.IP
+An \fIop\fR value of \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 port \fIport\fR. If \fIport\fI is not passed
+in the default value of 3260 is used.
+.IP
+IPv6 addresses can be specified as \fI[ddd.ddd.ddd.ddd]:port\fI or \fIddd.ddd.ddd.ddd\fR.
+.IP
+Hostnames can also be used for the \fIip\fI argument.
+.IP
+This option is only valid for \fIdiscovery\fR, or for \fInode\fR operations with
+the \fInew\fR operator.
+.IP
+This should be used along with \fI\-\-target\fR in \fInode\fR mode, to specify what
+the open-iscsi documents refer to as a node or node record. Note: open-iscsi's
+use of the word node, does not match the iSCSI RFC's iSCSI Node term.
+.TP
+\fB\-P\fR, \fB\-\-print=\fIprintlevel\fR
+If in \fInode\fR mode print nodes in tree format. If in \fIsession\fR mode print
+sessions in tree format. If in \fIdiscovery\fR mode print the nodes in
+tree format.
+.TP
+\fB\-T\fR, \fB\-\-targetname=\fItargetname\fR
+Use target \fItargetname\fR.
+.IP
+This should be used along with \fI\-\-portal\fR in \fInode\fR mode, to specify what
+the open-iscsi documents refer to as a node or node record. Note: open-iscsi's
+use of the word node, does not match the iSCSI RFC's iSCSI Node term.
+.TP
+\fB\-r\fR, \fB\-\-sid=\fIsid | sysfsdir\fR
+Use session ID \fIsid\fR. The session ID of a session can be found from running
+iscsiadm in session mode with the \fI\-\-info\fR argument.
+.IP
+Instead of a session ID, a sysfs path containing the session can be used.
+For example using one of the following:
+/sys/devices/platform/hostH/sessionS/targetH:B:I/H:B:I:L,
+/sys/devices/platform/hostH/sessionS/targetH:B:I, or
+/sys/devices/platform/hostH/sessionS, for the \fIsysfsdir\fR argument would
+result in the session with session ID \fIS\fR to be used.
+.IP
+\fIsid | sysfsdir\fR is only required for \fIsession\fR mode.
+.TP
+\fB\-R\fR, \fB\-\-rescan\fR
+In \fIsession\fR mode, if \fIsid\fR is also passed in, rescan the session.
+If no \fIsid\fR has been passed in rescan all running sessions.
+.IP
+In \fInode\fR mode, rescan a session running through the target, portal, iface
+tuple passed in.
+.TP
+\fB\-s\fR, \fB\-\-stats\fR
+Display session statistics.
+This option when used with \fIhost\fR mode, displays host statistics.
+.TP
+\fB\-S\fR, \fB\-\-show\fR
+When displaying records, do not hide masked values, such as the CHAP
+secret (password).
+.IP
+This option is only valid for \fInode\fR and \fIsession\fR mode.
+.TP
+\fB\-t\fR, \fB\-\-type=\fItype\fR
+\fItype\fR must be \fIsendtargets\fR (or abbreviated as \fIst\fR),
+\fIslp\fR, \fIisns\fR or \fIfw\fR. Currently only \fIsendtargets\fR, \fIfw\fR, and
+\fIiSNS\fR are supported, see the \fBDISCOVERY TYPES\fR section.
+.IP
+This option is only valid for \fIdiscovery\fR mode.
+.TP
+\fB\-u\fR, \fB\-\-logout\fR
+Logout for the specified record.
+.IP
+This option is only valid for \fInode\fR and \fIsession\fR mode.
+.TP
+\fB\-U\fR, \fB\-\-logoutall=\fI[all,manual,automatic|onboot]\fR
+Logout of all sessions with the node or conn startup values passed in or all
+running sessions, except ones marked \fIonboot\fR, if \fIall\fR is passed in.
+.IP
+This option is only valid for \fInode\fR mode (it is valid but not functional
+for \fIsession\fR mode).
+.TP
+\fB\-v\fR, \fB\-\-value=\fIvalue\fR
+Specify a \fIvalue\fR for use with the \fIupdate\fR operator, or for firmware login mode.
+.IP
+This option is only valid for \fInode\fR mode and \fIflashnode\fR submode of \fIhost\fR 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 \fIchap\fR and \fIflashnode\fR submodes of \fIhost\fR mode.
+.SH DISCOVERY TYPES
+iSCSI defines 3 discovery types: \fISendTargets\fR, \fISLP\fR, and \fIiSNS\fR.
+.PP
+A special discovery type called
+.I fw
+(for firmware) is also supported, for discovering firmware interfaces,
+and populating the interface database in the process.
+.TP
+.B
+SendTargets
+A native iSCSI protocol which allows each iSCSI
+target to send a list of available targets to the initiator.
+.TP
+.B
+SLP
+Optionally an iSCSI target can use the Service Location Protocol (SLP)
+to announce the available targets. The initiator can either implement
+SLP queries directly or can use a separate tool to acquire the
+information about available targets.
+.TP
+.B
+iSNS
+iSNS (Internet Storage Name Service) records information about storage
+volumes within a larger network. To utilize iSNS, pass the address and
+optionally the port of the iSNS server to do discovery to.
+.TP
+.B
+fw
+Firmware mode.
+Several NICs and systems contain a mini iSCSI initiator which can be used
+for boot. To get the values used for boot the \fIfw\fR option can be used.
+Doing \fIfw\fR discovery does not store persistent records in the node or
+discovery DB, because the values are stored in the system's or NIC's
+resource.
+.IP
+Performing \fIfw\fR discovery will print the portals, like with other discovery
+methods. To see other settings like CHAP values and initiator settings,
+like you would in \fInode\fR mode, run \fIiscsiadm \-m fw\fR.
+.P
+Note that the \fISLP\fR implementation is under development and currently
+is not supported.
+.SH EXIT STATUS
+On success 0 is returned. On error one of the return codes below will
+be returned.
+.PP
+Commands that operate on multiple objects (sessions, records, etc),
+iscsiadm/iscsistart will return the first error that is encountered.
+iscsiadm/iscsistart will attempt to execute the operation on the objects it
+can. If no objects are found ISCSI_ERR_NO_OBJS_FOUND is returned.
+.TP
+.B
+0
+ISCSI_SUCCESS - command executed successfully.
+.TP
+.B
+1
+ISCSI_ERR - generic error code.
+.TP
+.B
+2
+ISCSI_ERR_SESS_NOT_FOUND - session could not be found.
+.TP
+.B
+3
+ISCSI_ERR_NOMEM - could not allocate resource for operation.
+.TP
+.B
+4
+ISCSI_ERR_TRANS - connect problem caused operation to fail.
+.TP
+.B
+5
+ISCSI_ERR_LOGIN - generic iSCSI login failure.
+.TP
+.B
+6
+ISCSI_ERR_IDBM - error accessing/managing iSCSI DB.
+.TP
+.B
+7
+ISCSI_ERR_INVAL - invalid argument.
+.TP
+.B
+8
+ISCSI_ERR_TRANS_TIMEOUT - connection timer expired while trying to connect.
+.TP
+.B
+9
+ISCSI_ERR_INTERNAL - generic internal iscsid/kernel failure.
+.TP
+.B
+10
+ISCSI_ERR_LOGOUT - iSCSI logout failed.
+.TP
+.B
+11
+ISCSI_ERR_PDU_TIMEOUT - iSCSI PDU timed out.
+.TP
+.B
+12
+ISCSI_ERR_TRANS_NOT_FOUND - iSCSI transport module not loaded in kernel or iscsid.
+.TP
+.B
+13
+ISCSI_ERR_ACCESS - did not have proper OS permissions to access iscsid or execute iscsiadm command.
+.TP
+.B
+14
+ISCSI_ERR_TRANS_CAPS - transport module did not support operation.
+.TP
+.B
+15
+ISCSI_ERR_SESS_EXISTS - session is logged in.
+.TP
+.B
+16
+ISCSI_ERR_INVALID_MGMT_REQ - invalid IPC MGMT request.
+.TP
+.B
+17
+ISCSI_ERR_ISNS_UNAVAILABLE - iSNS service is not supported.
+.TP
+.B
+18
+ISCSI_ERR_ISCSID_COMM_ERR - a read/write to iscsid failed.
+.TP
+.B
+19
+ISCSI_ERR_FATAL_LOGIN - fatal iSCSI login error.
+.TP
+.B
+20
+ISCSI_ERR_ISCSID_NOTCONN - could not connect to iscsid.
+.TP
+.B
+21
+ISCSI_ERR_NO_OBJS_FOUND - no records/targets/sessions/portals found to execute operation on.
+.TP
+.B
+22
+ISCSI_ERR_SYSFS_LOOKUP - could not lookup object in sysfs.
+.TP
+.B
+23
+ISCSI_ERR_HOST_NOT_FOUND - could not lookup host.
+.TP
+.B
+24
+ISCSI_ERR_LOGIN_AUTH_FAILED - login failed due to authorization failure.
+.TP
+.B
+25
+ISCSI_ERR_ISNS_QUERY - iSNS query failure.
+.TP
+.B
+26
+ISCSI_ERR_ISNS_REG_FAILED - iSNS registration/deregistration failed.
+.TP
+.B
+27
+ISCSI_ERR_OP_NOT_SUPP - operation not support
+.TP
+.B
+28
+ISCSI_ERR_BUSY - device or resource in use
+.TP
+.B
+29
+ISCSI_ERR_AGAIN - operation failed, but retrying later may succeed
+.TP
+.B
+30
+ISCSI_ERR_UNKNOWN_DISCOVERY_TYPE - unknown discovery type
+.TP
+.B
+31
+ISCSI_ERR_CHILD_TERMINATED - child process terminated
+.TP
+.B
+32
+ISCSI_ERR_SESSION_NOT_CONNECTED - session likely not connected
+.SH EXAMPLES
+Discover targets at a given IP address:
+.IP
+\fBsh#\fR iscsiadm \-\-mode discoverydb \-\-type sendtargets \-\-portal 192.168.1.10 \-\-discover
+.PP
+Login, must use a node record id found by the discovery:
+.IP
+\fBsh#\fR iscsiadm \-\-mode node \-\-targetname iqn.2001-05.com.doe:test \-\-portal 192.168.1.1:3260 \-\-login
+.PP
+Logout:
+.IP
+\fBsh#\fR iscsiadm \-\-mode node \-\-targetname iqn.2001-05.com.doe:test \-\-portal 192.168.1.1:3260 \-\-logout
+.PP
+List node records:
+.IP
+\fBsh#\fR iscsiadm \-\-mode node
+.PP
+Display all data for a given node record:
+.IP
+\fBsh#\fR iscsiadm \-\-mode node \-\-targetname iqn.2001-05.com.doe:test \-\-portal 192.168.1.1:3260
+.PP
+List all sessions:
+.IP
+\fBsh#\fR iscsiadm \-\-mode session
+.PP
+List all sessions in tree format:
+.IP
+\fBsh#\fR iscsiadm \-\-mode session  \-\-print
+.SH FILES
+.TP
+@HOMEDIR@/iscsid.conf
+The configuration file read by \fBiscsid\fR and \fBiscsiadm\fR on startup.
+.TP
+@HOMEDIR@/initiatorname.iscsi
+The file containing the iSCSI InitiatorName and InitiatorAlias read by
+\fBiscsid\fR and \fBiscsiadm\fR on startup.
+.TP
+@DBROOT@/nodes/
+This directory contains the nodes with their targets.
+.TP
+@DBROOT@/send_targets
+This directory contains the portals.
+.SH "SEE ALSO"
+.BR iscsid (8)
+.SH AUTHORS
+Open-iSCSI project <http://www.open-iscsi.com/>
+.br
+Alex Aizman <itn780@yahoo.com>
+.br
+Dmitry Yusupov <dmitry_yus@yahoo.com>
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/doc/iscsid.8.template b/pkgs/open-iscsi/open-iscsi-2.1.8/doc/iscsid.8.template
new file mode 100644 (file)
index 0000000..0d122a0
--- /dev/null
@@ -0,0 +1,84 @@
+.TH ISCSID 8 "July 2005" "" "Linux Administrator's Manual"
+.SH NAME
+iscsid \- Open-iSCSI daemon
+.SH SYNOPSIS
+.BI iscsid
+[OPTION]
+.SH "DESCRIPTION"
+The
+.B iscsid
+implements the control path of iSCSI protocol, plus some management
+facilities. For example, the daemon could be configured to automatically 
+re-start discovery at startup, based on the contents of persistent 
+iSCSI database.
+.SH OPTIONS
+.TP
+.BI [-c|--config=]\fIconfig\-file\fP
+Read configuration from \fIconfig\-file\fR rather than the default
+\fI@HOMEDIR@/iscsid.conf\fR file.
+.TP
+.BI [-i|--initiatorname=]\fIiname\-file\fP
+Read initiator name from \fIiname\-file\fR rather than the default
+\fI@HOMEDIR@/initiatorname.iscsi\fR file.
+.TP
+.BI [-f|--foreground]
+run
+.B iscsid
+in the foreground. Implies
+.BR --no-pid-file .
+.TP
+.BI [-d|--debug=] debug_level
+print debugging information. Valid values for debug_level are 0 to 8.
+.TP
+.BI [-u|--uid=] uid
+run under user ID \fIuid\fR (default is the current user ID).
+.TP
+.BI [-g|--gid=] gid
+run under user group ID \fIgid\fR (default is the current user group ID).
+.TP
+.BI [-n|--no-pid-file]
+do not write a process ID file. Conflicts with the
+.BI --pid=
+option.
+.TP
+.BI [-p|--pid=] pid\-file
+write process ID to \fIpid\-file\fR rather than the default
+\fI/run/iscsid.pid\fR. Conflicts with the 
+.BI --no-pid-file
+option. 
+.TP
+.BI [-h|--help]
+display this help and exit
+.TP
+.BI [-v|--version]
+display version and exit.
+
+.SH FILES
+.TP
+@HOMEDIR@/iscsid.conf
+The configuration file read by
+.B iscsid
+and
+.B iscsiadm
+on startup.
+.TP
+@HOMEDIR@/initiatorname.iscsi
+The file containing the iSCSI initiatorname
+and initiatoralias read by
+.B iscsid
+and
+.B iscsiadm
+on startup.
+.TP
+@DBROOT@/nodes
+Open-iSCSI persistent configuration database
+
+.SH "SEE ALSO"
+.BR iscsiadm (8)
+
+.SH AUTHORS
+Open-iSCSI project <http://www.open-iscsi.com/>
+.br
+Alex Aizman <itn780@yahoo.com>
+.br
+Dmitry Yusupov <dmitry_yus@yahoo.com>
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/doc/iscsistart.8.template b/pkgs/open-iscsi/open-iscsi-2.1.8/doc/iscsistart.8.template
new file mode 100644 (file)
index 0000000..62fae4d
--- /dev/null
@@ -0,0 +1,75 @@
+.TH ISCSISTART 8 "Jan 2010" "" "Linux Administrator's Manual"
+.SH NAME
+iscsistart \- iSCSI boot tool
+.SH SYNOPSIS
+.BI iscsistart
+[OPTION]
+.SH "DESCRIPTION"
+.B iscsistart
+will start a session using the settings passed in, or
+using the iBFT or Open Firmware [OF] boot information. This program should
+not be run to manage sessions. Its primary use is to start
+sessions used for iSCSI root boot.
+.SH OPTIONS
+.TP
+.BI [-c|--config=]\fIconfig\-file\fP
+Read configuration from \fIconfig\-file\fR rather than the default
+\fI@HOMEDIR@/iscsid.conf\fR file.
+.TP
+.BI [-i|--initiatorname=]\fIname\fP
+Set InitiatorName to name (Required if not using iBFT or OF)
+.TP
+.BI [-t|--targetname=]\fIname\fP
+Set TargetName to name (Required if not using iBFT or OF)
+.TP
+.BI [-g|--tgpt=]\fIN\fP
+Set target portal group tag to N (Required if not using iBFT or OF)
+.TP
+.BI [-a|--address=]\fIA.B.C.D\fP
+Set IP address to A.B.C.D (Required if not using iBFT or OF)
+.TP
+.BI [-p|--port=]\fIN\fP
+Set port to N (Optional. Default 3260)
+.TP
+.BI [-u|--username=]\fIN\fP
+Set username to N (Optional)
+.TP
+.BI [-w|--password=]\fIN\fP
+Set password to N (Optional)
+.TP
+.BI [-U|-username_in=]\fIN\fP
+Set incoming username to N (Optional)
+.TP
+.BI [-W|--password_in=]\fIN\fP
+Set incoming password to N (Optional)
+.TP
+.BI [-d|--debug=]\fIdebug_level\fP
+Print debugging information
+.TP
+.BI [-b|--fwparam_connect]
+Create a session to the target using the iBFT or OF info
+.TP
+.BI [-N|--fwparam_network]
+Bring up the network as specified by iBFT or OF
+.TP
+.BI [-f|--fwparam_print]
+Print the iBFT or OF info to STDOUT
+.TP
+.BI [-P|--param=]\fINAME=VALUE\fP
+Set the parameter with the name NAME to VALUE. NAME is one of the settings
+in the node record or iscsid.conf. Multiple params can be passed in.
+.TP
+.BI [-h|--help]
+Display this help and exit
+.TP
+.BI [-v|--version]
+Display version and exit
+
+
+.SH "SEE ALSO"
+.BR iscsiadm (8)
+
+.SH AUTHORS
+Open-iSCSI project <http://www.open-iscsi.com/>
+.br
+Mike Christie <mchristi@redhat.com>
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/etc/Makefile b/pkgs/open-iscsi/open-iscsi-2.1.8/etc/Makefile
new file mode 100644 (file)
index 0000000..6dd6a41
--- /dev/null
@@ -0,0 +1,115 @@
+#
+# gnu Makefile for the etc subdirectory, including
+#      initd and systemd subdirectories
+#
+
+ifeq ($(TOPDIR),)
+       TOPDIR = ..
+endif
+
+prefix = /usr
+DESTDIR ?=
+SBINDIR ?= /sbin
+
+ISCSI_INAME ?= $(TOPDIR)/utils/iscsi-iname
+
+systemddir ?= $(prefix)/lib/systemd
+etcdir = /etc
+initddir ?= $(etcdir)/init.d
+
+HOMEDIR ?= $(etcdir)/iscsi
+
+SED ?= sed
+INSTALL = install
+
+SYSTEMD_SOURCE_FILES   = iscsid.socket iscsiuio.socket
+SYSTEMD_SOURCES                = $(addprefix systemd/,$(SYSTEMD_SOURCE_FILES))
+SYSTEMD_TEMPLATE_FILES = iscsi-init.service.template \
+                         iscsid.service.template \
+                         iscsi.service.template \
+                         iscsiuio.service.template
+SYSTEMD_TEMPLATES      = $(addprefix systemd/,$(SYSTEMD_TEMPLATE_FILES))
+SYSTEMD_RULES_FILES    = ibft-rule-generator
+SYSTEMD_RULES_SOURCES  = $(addprefix systemd/,$(SYSTEMD_RULES_FILES))
+SYSTEMD_GENERATED_SERVICE_FILES        = $(SYSTEMD_TEMPLATES:.template=)
+SYSTEMD_DEST_SVC_FILES = $(addprefix $(DESTDIR)$(systemddir)/system/,$(SYSTEMD_SOURCE_FILES)) \
+                         $(addprefix $(DESTDIR)$(systemddir)/system/,$(notdir $(SYSTEMD_GENERATED_SERVICE_FILES)))
+SYSTEMD_DEST_GEN_FILES = $(addprefix $(DESTDIR)$(systemddir)/system-generators/,$(notdir $(SYSTEMD_RULES_SOURCES)))
+IFACE_FILES            = iface.example
+IFACE_DEST_FILES       = $(addprefix $(DESTDIR)$(DBROOT)/ifaces/,$(IFACE_FILES))
+ETC_FILES              = iscsid.conf
+ETC_DEST_FILES         = $(addprefix $(DESTDIR)$(HOMEDIR)/,$(ETC_FILES))
+
+INAME_DEST_FILE                = $(DESTDIR)$(HOMEDIR)/initiatorname.iscsi
+
+all: $(SYSTEMD_SOURCES) $(SYSTEMD_GENERATED_SERVICE_FILES)
+
+$(SYSTEMD_GENERATED_SERVICE_FILES): systemd/%.service: systemd/%.service.template
+       $(SED) -e 's:@SBINDIR@:$(SBINDIR):' $? > $@
+
+install: install_systemd install_iface install_etc
+
+install_iface: $(DESTDIR)$(DBROOT)/ifaces $(IFACE_DEST_FILES)
+
+$(IFACE_DEST_FILES): $(DESTDIR)$(DBROOT)/ifaces/%: %
+       $(INSTALL) -m 644 $? $@
+
+install_etc: $(DESTDIR)$(HOMEDIR) $(ETC_DEST_FILES)
+
+$(ETC_DEST_FILES): $(DESTDIR)$(HOMEDIR)/%: %
+       $(INSTALL) -m 644 $? $@
+
+install_initd_distro = $(INSTALL) -m 755 $(1) $(DESTDIR)$(initddir)/open-iscsi/
+
+install_initd: $(DESTDIR)$(initddir)/open-iscsi
+       @if [ -f /etc/debian_version ]; then \
+               $(call install_initd_distro,initd/initd.redhat) ; \
+       elif [ -f /etc/redhat-release ]; then \
+               $(call install_initd_distro,initd/initd.debian) ; \
+       fi
+
+install_initd_redhat: $(DESTDIR)$(initddir)/open-iscsi
+       $(call install_initd_distro,initd/initd.redhat)
+
+install_initd_debian: $(DESTDIR)$(initddir)/open-iscsi
+       $(call install_initd_distro,initd/initd.debian)
+
+install_systemd: install_systemd_service_files install_systemd_generator_files
+
+install_systemd_service_files: $(DESTDIR)$(systemddir)/system $(SYSTEMD_DEST_SVC_FILES)
+
+install_systemd_generator_files: $(DESTDIR)$(systemddir)/system-generators $(SYSTEMD_DEST_GEN_FILES)
+
+$(SYSTEMD_DEST_SVC_FILES): $(DESTDIR)$(systemddir)/system/%: systemd/%
+       $(INSTALL) -m 644 $? $@
+
+$(SYSTEMD_DEST_GEN_FILES): $(DESTDIR)$(systemddir)/system-generators/%: systemd/%
+       $(INSTALL) -m 755 $? $@
+
+install_iname: $(DESTDIR)$(HOMEDIR) $(ISCSI_INAME)
+       if [ ! -f $(INAME_DEST_FILE) ]; then \
+               INAME="`$(ISCSI_INAME)`" ; \
+               echo "InitiatorName=$$INAME" > $(INAME_DEST_FILE) ; \
+               echo "***************************************************" ; \
+               echo "Setting InitiatorName to $$INAME" ; \
+               echo "To override edit $(INAME_DEST_FILE)" ; \
+               echo "***************************************************" ; \
+       fi
+
+$(ISCSI_INAME):
+       $(MAKE) $(MFLAGS) -c $(TOPDIR)/utils $(notdir $@)
+
+# make needed directories
+$(DESTDIR)$(systemddir)/system $(DESTDIR)$(systemddir)/system-generators $(DESTDIR)$(HOMEDIR) \
+               $(DESTDIR)$(DBROOT)/ifaces $(DESTDIR)$(initddir)/open-iscsi:
+       [ -d $@ ] || $(INSTALL) -d -m 775 $@
+
+clean: ;
+
+distclean:
+       $(RM) $(SYSTEMD_GENERATED_SERVICE_FILES)
+
+.PHONY: all clean install install_iface install_initd install_initd_redhat \
+       install_initd_debian install_systemd distclean install_iname \
+       install_systemd_generator_files install_systemd_service_files \
+       install_initd_distro install_etc
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/etc/iface.example b/pkgs/open-iscsi/open-iscsi-2.1.8/etc/iface.example
new file mode 100644 (file)
index 0000000..17894cb
--- /dev/null
@@ -0,0 +1,204 @@
+#
+# Example iSCSI interface config
+#
+# There must be a separate iscsi interface config file for each NIC, network
+# interface or port or iscsi HBA you want to bind sessions to.
+#
+# For hardware iscsi, this is created for you when you run iscsiadm.
+# For software iscsi, you must define these files yourself.
+#
+
+# REQUIRED: iface.transport_name
+#
+# Set the iscsi transport/driver to use for the iface by setting
+# iface.transport_name
+# example:
+# iface.transport_name = tcp
+
+# This value is required and valid values for iface.transport_name are:
+# - tcp (Software iSCSI over TCP/IP)
+# - iser (Software iSCSI over infinniband
+# - qla4xxx (Qlogic QLA4XXX HBAs)
+# - bnx2i (Broadcom bnx iSCSI HBAs);
+# - cxgb3i (Chelsio cxgb S3 iSCSI HBAs);
+#
+#OPTIONAL: iface.initiatorname
+# To use an initiator name other than the one set in
+# /etc/iscsi/initiatorname.iscsi for normal sessions set the
+# iface.initiatorname. This is only used for normal sessions.
+# For discovery sessions the /etc/iscsi/initiatorname.iscsi value
+# is used.
+#
+# iface.initiatorname = iqn.2003-04.com.fedora:test
+#
+#
+# REQUIRED to be able to bind a session to a network device:
+#                      [iface.net_ifacename | iface.hwaddress]
+#
+# OPTIONAL if you are creating ifaces so you can create multiple sessions
+# using the default behavior where the network layer selects the device.
+#
+# __One__ of the following values are required for binding a session
+# to a specific nic/netdevice.
+#
+# To bind by network interface name (example: eth0, eth2:2, eth1.3)
+# set iface.net_ifacename
+# example:
+# iface.net_ifacename = eth0
+
+# To bind by hardware address set the NIC's MAC address to iface.hwaddress
+# example:
+# iface.hwaddress = 00:0F:1F:92:6B:BF
+
+# Note you can only bind using one value. If you set multiple values
+# the bahavior is not defined.
+
+# For some transport (cxgb3i), a user could to set the private ip address for
+# the iscsi traffic for an network interface:
+# example:
+#  - set iscsi ip on eth0 to be 102.50.50.101, eth0 needs to be up and be on
+#    the same subnet.
+# iface.net_ifacename = eth0
+# iface.ipaddress = 102.50.50.101
+
+# OPTIONAL: iface.bootproto
+#
+# Valid values are:
+# "dhcp" and "static"
+#
+# REQUIRED when IPv4 address need to be obtained dynamically using DHCP
+# example:
+# iface.bootproto = dhcp
+#
+# OPTIONAL when the IPv4 address is set statically
+# example:
+# iface.ipaddress = 102.50.50.101
+# iface.bootproto = static
+#
+
+# OPTIONAL: iface.vlan_id
+# Used to set the VLAN ID for the iSCSI interfae.
+# example
+# iface.vlan_id = 1022
+
+# OPTIONAL: iface.vlan_priority
+# Used to set the VLAN priority for the iSCSI interfae.
+# example
+# iface.vlan_priority = 1
+
+# OPTIONAL: iface.vlan_state
+# Used to enable or disable the VLAN on the iSCSI interface
+# example
+# iface.vlan_state = enable
+
+#
+# The IPv6 attributes require the interface file
+# be named with the string "ipv6" in it. Otherwise,
+# parsing such a file will cause errors, since IPv4
+# is otherwise assumed.
+#
+
+# OPTIONAL: iface.ipv6_linklocal
+# Specify the IPV6 Link Local Address with the
+# link local prefix of FE80::0/64
+# example:
+# iface.ipv6_linklocal = fe80:0000:0000:0000:020e:1eff:1111:2221
+
+# OPTIONAL: iface.ipv6_router
+# Used to set a default IPV6 router
+# example:
+# iface.ipv6_router = fe80:0000:0000:0000:7ae7:d1ff:fe72:4048
+
+# OPTIONAL: iface.ipv6_autocfg
+# Used to set the discovery protocol to obtain IPV6 address
+# For example qla4xxx support neighbor discovery
+# example:
+# iface.ipv6_autocfg = nd
+
+# OPTIONAL: iface.linklocal_autocfg
+# For transport like qla4xxx this allows to auto configure the
+# IPV6 link local address based on the MAC address of the iSCSI
+# interface
+
+# OPTIONAL: iface.router_autocfg
+# Required to set the IPv6 router discovery protocol
+# To set the  router discovery  protocol to Neighbor Discovery specify "nd"
+# example:
+# iface.router_autocfg = nd
+
+# OPTIONAL: iface.state
+# By default the iface is enabled
+# iface.state = enable
+# To disable the iface set the state to "disable"
+# iface.state = disable
+
+# iface.iface_num
+# REQUIRED: When there are more than 1 interface to be configured.
+# For transports like qla4xxx, one can specify two IPV6 interfaces
+# in such case the iface_num must be set correctly
+# example:
+# iface settings for first IPV6 interface
+# iface.iscsi_ifacename = iface-qla4xxx-ipv6-1
+# iface.iface_num = 0
+#
+# iface settings for second IPV6 interface
+# iface.iscsi_ifacename = iface-qla4xxx-ipv6-2
+# iface.iface_num = 1
+
+# Here are some example iface files
+# IPV4 sample config file with static IP address:
+# BEGIN RECORD 2.0-872
+# iface.iscsi_ifacename = qla4xxx-3
+# iface.ipaddress = 192.168.1.75
+# iface.hwaddress = 00:0e:1e:04:93:92
+# iface.transport_name = qla4xxx
+# iface.bootproto = static
+# iface.subnet_mask = 255.255.255.0
+# iface.gateway = 192.168.1.1
+# iface.state = enable
+# iface.vlan = <empty>
+# iface.iface_num = 0
+# END RECORD
+#
+# IPV6 sample config file with neighbor discovery:
+#  BEGIN RECORD 2.0-872
+# iface.iscsi_ifacename = qla4xxx-3-1-ipv6
+# iface.ipaddress =
+# iface.hwaddress = 00:0e:1e:04:93:92
+# iface.transport_name = qla4xxx
+# iface.ipv6_autocfg = nd
+# iface.linklocal_autocfg = auto
+# iface.router_autocfg = nd
+# iface.ipv6_linklocal = fe80:0000:0000:0000:020e:1eff:1111:2221
+# iface.ipv6_router = auto
+# iface.state = enable
+# iface.vlan = <empty>
+# iface.iface_num = 0
+# END RECORD
+
+# Ipv4 sample config file (DHCP configuration):
+#  BEGIN RECORD 2.0-872
+# iface.iscsi_ifacename = qla4xxx-3
+# iface.hwaddress = 00:0e:1e:04:93:92
+# iface.transport_name = qla4xxx
+# iface.bootproto = dhcp
+# iface.state = enable
+# iface.vlan = <empty>
+# iface.iface_num = 0
+# END RECORD
+
+# Sample ipv6 config file(manual configured IPs):
+# BEGIN RECORD 2.0-872
+# iface.iscsi_ifacename = iface-new-file-ipv6
+# iface.ipaddress = fec0:ce00:7014:0041:1111:2222:1e04:9392
+# iface.hwaddress = 00:0e:1e:04:93:92
+# iface.transport_name = qla4xxx
+# iface.ipv6_autocfg = <empty>
+# iface.linklocal_autocfg = <empty>
+# iface.router_autocfg = <empty>
+# iface.ipv6_linklocal = fe80:0000:0000:0000:0000:0000:1e04:9392
+# iface.ipv6_router = fe80:0000:0000:0000:7ae7:d1ff:fe72:4048
+# iface.state = enable
+# iface.vlan = <empty>
+# iface.iface_num = 0
+# END RECORD
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/etc/initd/initd.debian b/pkgs/open-iscsi/open-iscsi-2.1.8/etc/initd/initd.debian
new file mode 100644 (file)
index 0000000..b531be5
--- /dev/null
@@ -0,0 +1,110 @@
+#! /bin/sh
+### BEGIN INIT INFO
+# Provides:
+# Required-Start:
+# Required-Stop:
+# Default-Start:
+# Default-Stop:
+# Short-Description: Starts and stops the iSCSI initiator services and logins to default targets
+### END INIT INFO
+
+PATH=/sbin:/bin:/usr/sbin:/usr/bin
+DAEMON=/sbin/iscsid
+ADM=/sbin/iscsiadm
+PIDFILE=/run/iscsid.pid
+
+[ -x "$DAEMON" ] || exit 0
+
+. /lib/lsb/init-functions
+
+if [ ! -d /sys/class/ ]; then
+  log_failure_msg "iSCSI requires a mounted sysfs, not started."
+  exit 1
+fi
+
+nodestartup_re='s/^node\.conn\[0]\.startup[    ]*=[    ]*//p'
+
+RETVAL=0
+
+start() {
+       log_daemon_msg "Starting iSCSI initiator service" "iscsid"
+       modprobe -q iscsi_tcp 2>/dev/null || :
+       modprobe -q ib_iser 2>/dev/null || :
+       start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON
+       RETVAL=$?
+       log_end_msg $RETVAL
+       starttargets
+}
+
+starttargets() {
+       log_daemon_msg "Setting up iSCSI targets"
+       $ADM -m node --loginall=automatic
+       log_end_msg 0
+}
+
+stoptargets() {
+       log_daemon_msg "Disconnecting iSCSI targets"
+       sync
+       $ADM -m node --logoutall=all
+       RETVAL=$?
+       log_end_msg $RETVAL
+}
+
+stop() {
+       stoptargets
+       if [ $RETVAL -ne 0 ]; then
+               log_failure_msg "Could not stop all targets, try again later"
+               return $RETVAL
+       fi
+
+       log_daemon_msg "Stopping iSCSI initiator service"
+       start-stop-daemon --stop --quiet --pidfile $PIDFILE --exec $DAEMON
+       rm -f $PIDFILE
+       status=0
+       modprobe -r ib_iser 2>/dev/null
+       if [ "$?" -ne "0" -a "$?" -ne "1" ]; then
+               status=1
+       fi
+       modprobe -r iscsi_tcp 2>/dev/null
+       if [ "$?" -ne "0" -a "$?" -ne "1" ]; then
+               status=1
+       fi
+       log_end_msg $status
+}
+
+restart() {
+       stop
+       if [ $RETVAL -ne 0 ]; then
+               log_failure_msg "Stopping iSCSI initiator service failed, not starting"
+               return $RETVAL
+       fi
+       start
+}
+
+restarttargets() {
+       stoptargets
+       if [ $RETVAL -ne 0 ]; then
+               log_failure_msg "Could not stop all targets, try again later"
+               return $RETVAL
+       fi
+       starttargets
+}
+
+status() {
+       #XXX FIXME: what to do here?
+       #status iscsid
+       # list active sessions
+       echo Current active iSCSI sessions:
+       $ADM -m session
+}
+
+case "$1" in
+       start|starttargets|stop|stoptargets|restart|restarttargets|status)
+               $1
+               ;;
+       *)
+               echo "Usage: $0 {start|stop|restart|status}"
+               exit 1
+               ;;
+esac
+exit $RETVAL
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/etc/initd/initd.redhat b/pkgs/open-iscsi/open-iscsi-2.1.8/etc/initd/initd.redhat
new file mode 100644 (file)
index 0000000..568f0cf
--- /dev/null
@@ -0,0 +1,104 @@
+#!/bin/sh
+#
+# chkconfig: 345 13 89
+# description: Starts and stops the iSCSI initiator
+#
+# processname: iscsid
+# pidfile: /run/iscsid.pid
+# config:  /etc/iscsi/iscsid.conf
+
+# Source function library.
+. /etc/init.d/functions
+
+PATH=/sbin:/bin:/usr/sbin:/usr/bin
+
+RETVAL=0
+
+start()
+{
+       echo -n $"Starting iSCSI initiator service: "
+       daemon iscsid
+       RETVAL=$?
+       success
+       echo
+       [ $RETVAL -eq 0 ] || return
+
+       touch /run/lock/subsys/open-iscsi
+
+       echo -n $"Setting up iSCSI targets: "
+       iscsiadm -m node --loginall=automatic
+       success
+       echo
+
+}
+
+stop()
+{
+       echo -n $"Stopping iSCSI initiator service: "
+       sync
+       iscsiadm -m node --logoutall=all
+       RETVAL=$?
+       if [ $RETVAL -ne 0 ]; then
+               echo "Could not logout from all nodes, try again later"
+               return $RETVAL
+       fi
+       iscsiadm -k 0
+       rm -f /run/iscsid.pid
+       [ $RETVAL -eq 0 ] && rm -f /run/lock/subsys/open-iscsi
+       status=0
+       modprobe -r iscsi_tcp 2>/dev/null
+       if [ "$?" -ne "0" -a "$?" -ne "1" ]; then
+               status=1
+       fi
+       modprobe -r ib_iser 2>/dev/null
+       if [ "$?" -ne "0" -a "$?" -ne "1" ]; then
+               status=1
+       fi
+       if [ "$status" -eq "0" ]; then
+               success
+       else
+               failure
+       fi
+       echo
+
+}
+
+restart()
+{
+       stop
+       if [ $RETVAL -ne 0 ]; then
+               echo "Stopping iSCSI initiator service failed, not starting"
+               return $RETVAL
+       fi
+       start
+
+}
+
+case "$1" in
+       start)
+                       start
+                       ;;
+       stop)
+                       stop
+                       ;;
+       restart)
+                       stop
+                       if [ $RETVAL -ne 0 ]; then
+                               echo "Stopping iSCSI initiator service failed, not starting"
+                               exit $RETVAL
+                       fi
+                       start
+                       ;;
+       status)
+                       status iscsid
+                       RETVAL=$?
+                       ;;
+       condrestart)
+                       [ -f /run/lock/subsys/open-iscsi ] && restart
+                       ;;
+       *)
+                       echo $"Usage: $0 {start|stop|restart|status|condrestart}"
+                       exit 1
+esac
+
+exit $RETVAL
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/etc/iscsid.conf b/pkgs/open-iscsi/open-iscsi-2.1.8/etc/iscsid.conf
new file mode 100644 (file)
index 0000000..79d8127
--- /dev/null
@@ -0,0 +1,348 @@
+#
+# Open-iSCSI default configuration.
+# Could be located at /etc/iscsi/iscsid.conf or ~/.iscsid.conf
+#
+# Note: To set any of these values for a specific node/session run
+# the iscsiadm --mode node --op command for the value. See the README
+# and man page for iscsiadm for details on the --op command.
+#
+
+######################
+# iscsid daemon config
+######################
+#
+# If you want iscsid to start the first time an iscsi tool
+# needs to access it, instead of starting it when the init
+# scripts run, set the iscsid startup command here. This
+# should normally only need to be done by distro package
+# maintainers. If you leave the iscsid daemon running all
+# the time then leave this attribute commented out.
+#
+# Default for Fedora and RHEL. Uncomment to activate.
+# iscsid.startup = /bin/systemctl start iscsid.socket iscsiuio.socket
+#
+# Default for Debian and Ubuntu. Uncomment to activate.
+# iscsid.startup = /bin/systemctl start iscsid.socket
+#
+# Default if you are not using systemd. Uncomment to activate.
+# iscsid.startup = /usr/bin/service start 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
+
+# Only require UID auth for MGMT IPCs, and not username.
+# Useful if you want to run iscsid in a constrained environment.
+# Note: Only do this if you are aware of the security implications.
+# Defaults to "No".
+# iscsid.ipc_auth_uid = Yes
+
+#############################
+# NIC/HBA and driver settings
+#############################
+# open-iscsi can create a session and bind it to a NIC/HBA.
+# To set this up see the example iface config file.
+
+#*****************
+# Startup settings
+#*****************
+
+# To request that the iscsi service scripts startup a session, use "automatic":
+# node.startup = automatic
+#
+# To manually startup the session, use "manual". The default is manual.
+node.startup = manual
+
+# For "automatic" startup nodes, setting this to "Yes" will try logins on each
+# available iface until one succeeds, and then stop.  The default "No" will try
+# logins on all available ifaces simultaneously.
+node.leading_login = No
+
+# *************
+# CHAP Settings
+# *************
+
+# To enable CHAP authentication set node.session.auth.authmethod
+# to CHAP. The default is None.
+#node.session.auth.authmethod = CHAP
+
+# To configure which CHAP algorithms to enable, set
+# node.session.auth.chap_algs to a comma separated list.
+# The algorithms should be listed in order of decreasing
+# preference — in particular, with the most preferred algorithm first.
+# Valid values are MD5, SHA1, SHA256, and SHA3-256.
+# The default is MD5.
+#node.session.auth.chap_algs = SHA3-256,SHA256,SHA1,MD5
+
+# To set a CHAP username and password for initiator
+# authentication by the target(s), uncomment the following lines:
+#node.session.auth.username = username
+#node.session.auth.password = password
+
+# To set a CHAP username and password for target(s)
+# authentication by the initiator, uncomment the following lines:
+#node.session.auth.username_in = username_in
+#node.session.auth.password_in = password_in
+
+# To enable CHAP authentication for a discovery session to the target,
+# set discovery.sendtargets.auth.authmethod to CHAP. The default is None.
+#discovery.sendtargets.auth.authmethod = CHAP
+
+# To set a discovery session CHAP username and password for the initiator
+# authentication by the target(s), uncomment the following lines:
+#discovery.sendtargets.auth.username = username
+#discovery.sendtargets.auth.password = password
+
+# To set a discovery session CHAP username and password for target(s)
+# authentication by the initiator, uncomment the following lines:
+#discovery.sendtargets.auth.username_in = username_in
+#discovery.sendtargets.auth.password_in = password_in
+
+# ********
+# Timeouts
+# ********
+#
+# 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
+# before failing SCSI commands back to the application when running
+# the Linux SCSI Layer error handler, edit the line.
+# The value is in seconds and the default is 120 seconds.
+# Special values:
+# - If the value is 0, IO will be failed immediately.
+# - If the value is less than 0, IO will remain queued until the session
+# is logged back in, or until the user runs the logout command.
+node.session.timeo.replacement_timeout = 120
+
+# To specify the time to wait for login to complete, edit the line.
+# The value is in seconds and the default is 15 seconds.
+node.conn[0].timeo.login_timeout = 15
+
+# To specify the time to wait for logout to complete, edit the line.
+# The value is in seconds and the default is 15 seconds.
+node.conn[0].timeo.logout_timeout = 15
+
+# Time interval to wait for on connection before sending a ping.
+# The value is in seconds and the default is 5 seconds.
+node.conn[0].timeo.noop_out_interval = 5
+
+# To specify the time to wait for a Nop-out response before failing
+# the connection, edit this line. Failing the connection will
+# cause IO to be failed back to the SCSI layer. If using dm-multipath
+# this will cause the IO to be failed to the multipath layer.
+# The value is in seconds and the default is 5 seconds.
+node.conn[0].timeo.noop_out_timeout = 5
+
+# To specify the time to wait for an abort response before
+# failing the operation and trying a logical unit reset, edit the line.
+# The value is in seconds and the default is 15 seconds.
+node.session.err_timeo.abort_timeout = 15
+
+# To specify the time to wait for a logical unit response
+# before failing the operation and trying session re-establishment,
+# edit the line.
+# The value is in seconds and the default is 30 seconds.
+node.session.err_timeo.lu_reset_timeout = 30
+
+# To specify the time to wait for a target response
+# before failing the operation and trying session re-establishment,
+# edit the line.
+# The value is in seconds and the default is 30 seconds.
+node.session.err_timeo.tgt_reset_timeout = 30
+
+# The value is in seconds and the default is 60 seconds.
+node.session.err_timeo.host_reset_timeout = 60
+
+
+#******
+# Retry
+#******
+
+# To specify the number of times iscsid should retry a login
+# if the login attempt fails due to the node.conn[0].timeo.login_timeout
+# expiring, modify the following line. Note that if the login fails
+# quickly (before node.conn[0].timeo.login_timeout fires) because the network
+# layer or the target returns an error, iscsid may retry the login more than
+# node.session.initial_login_retry_max times.
+#
+# This retry count along with node.conn[0].timeo.login_timeout
+# determines the maximum amount of time iscsid will try to
+# establish the initial login. node.session.initial_login_retry_max is
+# multiplied by the node.conn[0].timeo.login_timeout to determine the
+# maximum amount.
+#
+# The default node.session.initial_login_retry_max is 8 and
+# node.conn[0].timeo.login_timeout is 15 so we have:
+#
+# node.conn[0].timeo.login_timeout * node.session.initial_login_retry_max = 120s
+#
+# Valid values are any integer value. This only
+# affects the initial login. Setting it to a high value can slow
+# down the iscsi service startup. Setting it to a low value can
+# cause a session to not get logged into, if there are distuptions
+# during startup or if the network is not ready at that time.
+node.session.initial_login_retry_max = 8
+
+################################
+# session and device queue depth
+################################
+
+# To control how many commands the session will queue, set
+# node.session.cmds_max to an integer between 2 and 2048 that is also
+# a power of 2. The default is 128.
+node.session.cmds_max = 128
+
+# To control the device's queue depth, set node.session.queue_depth
+# to a value between 1 and 1024. The default is 32.
+node.session.queue_depth = 32
+
+##################################
+# MISC SYSTEM PERFORMANCE SETTINGS
+##################################
+
+# For software iscsi (iscsi_tcp) and iser (ib_iser), each session
+# has a thread used to transmit or queue data to the hardware. For
+# cxgb3i, you will get a thread per host.
+#
+# Setting the thread's priority to a lower value can lead to higher throughput
+# and lower latencies. The lowest value is -20. Setting the priority to
+# a higher value, can lead to reduced IO performance, but if you are seeing
+# the iscsi or scsi threads dominate the use of the CPU then you may want
+# to set this value higher.
+#
+# Note: For cxgb3i, you must set all sessions to the same value.
+# Otherwise the behavior is not defined.
+#
+# The default value is -20. The setting must be between -20 and 20.
+node.session.xmit_thread_priority = -20
+
+
+#***************
+# iSCSI settings
+#***************
+
+# To enable R2T flow control (i.e., the initiator must wait for an R2T
+# command before sending any data), uncomment the following line:
+#
+#node.session.iscsi.InitialR2T = Yes
+#
+# To disable R2T flow control (i.e., the initiator has an implied
+# initial R2T of "FirstBurstLength" at offset 0), uncomment the following line:
+#
+# The defaults is No.
+node.session.iscsi.InitialR2T = No
+
+#
+# To disable immediate data (i.e., the initiator does not send
+# unsolicited data with the iSCSI command PDU), uncomment the following line:
+#
+#node.session.iscsi.ImmediateData = No
+#
+# To enable immediate data (i.e., the initiator sends unsolicited data
+# with the iSCSI command packet), uncomment the following line:
+#
+# The default is Yes.
+node.session.iscsi.ImmediateData = Yes
+
+# To specify the maximum number of unsolicited data bytes the initiator
+# can send in an iSCSI PDU to a target, edit the following line.
+#
+# The value is the number of bytes in the range of 512 to (2^24-1) and
+# the default is 262144.
+node.session.iscsi.FirstBurstLength = 262144
+
+# To specify the maximum SCSI payload that the initiator will negotiate
+# with the target for, edit the following line.
+#
+# The value is the number of bytes in the range of 512 to (2^24-1) and
+# the defauls it 16776192.
+node.session.iscsi.MaxBurstLength = 16776192
+
+# To specify the maximum number of data bytes the initiator can receive
+# in an iSCSI PDU from a target, edit the following line.
+#
+# The value is the number of bytes in the range of 512 to (2^24-1) and
+# the default is 262144.
+node.conn[0].iscsi.MaxRecvDataSegmentLength = 262144
+
+# To specify the maximum number of data bytes the initiator will send
+# in an iSCSI PDU to the target, edit the following line.
+#
+# The value is the number of bytes in the range of 512 to (2^24-1).
+# Zero is a special case. If set to zero, the initiator will use
+# the target's MaxRecvDataSegmentLength for the MaxXmitDataSegmentLength.
+# The default is 0.
+node.conn[0].iscsi.MaxXmitDataSegmentLength = 0
+
+# To specify the maximum number of data bytes the initiator can receive
+# in an iSCSI PDU from a target during a discovery session, edit the
+# following line.
+#
+# The value is the number of bytes in the range of 512 to (2^24-1) and
+# the default is 32768.
+discovery.sendtargets.iscsi.MaxRecvDataSegmentLength = 32768
+
+# To allow the targets to control the setting of the digest checking,
+# with the initiator requesting a preference of enabling the checking,
+# uncomment one or both of the following lines:
+#node.conn[0].iscsi.HeaderDigest = CRC32C,None
+#node.conn[0].iscsi.DataDigest = CRC32C,None
+#
+# To allow the targets to control the setting of the digest checking,
+# with the initiator requesting a preference of disabling the checking,
+# uncomment one or both of the following lines:
+#node.conn[0].iscsi.HeaderDigest = None,CRC32C
+#node.conn[0].iscsi.DataDigest = None,CRC32C
+#
+# To enable CRC32C digest checking for the header and/or data part of
+# iSCSI PDUs, uncomment one or both of the following lines:
+#node.conn[0].iscsi.HeaderDigest = CRC32C
+#node.conn[0].iscsi.DataDigest = CRC32C
+#
+# To disable digest checking for the header and/or data part of
+# iSCSI PDUs, uncomment one or both of the following lines:
+#node.conn[0].iscsi.HeaderDigest = None
+#node.conn[0].iscsi.DataDigest = None
+#
+# The default is to never use DataDigests or HeaderDigests.
+#
+
+# For multipath configurations, you may want more than one session to be
+# created on each iface record. If node.session.nr_sessions is greater
+# than 1, performing a 'login' for that node will ensure that the
+# appropriate number of sessions is created.
+node.session.nr_sessions = 1
+
+# When iscsid starts up, it recovers existing sessions (if possible).
+# If the target for a session has gone away when this occurs, the
+# iscsid daemon normally tries to reestablish each session,
+# in succession, in the background, by trying again every two
+# seconds until all sessions are restored. This configuration
+# variable can limits the number of retries for each session.
+# For example, setting reopen_max=150 would mean that each session
+# recovery was limited to about five minutes.
+node.session.reopen_max = 0
+
+#************
+# Workarounds
+#************
+
+# Some targets like IET prefer that an initiator does not respond to PDUs like
+# R2Ts after it has sent a task management function like an ABORT TASK or a
+# LOGICAL UNIT RESET. To adopt this behavior, uncomment the following line.
+# The default is Yes.
+node.session.iscsi.FastAbort = Yes
+
+# Some targets like Equalogic prefer that an initiator continue to respond to
+# R2Ts after it has sent a task management function like an ABORT TASK or a
+# LOGICAL UNIT RESET. To adopt this behavior, uncomment the following line.
+# node.session.iscsi.FastAbort = No
+
+# To prevent doing automatic scans that would add unwanted luns to the system,
+# we can disable them and have sessions only do manually requested scans.
+# Automatic scans are performed on startup, on login, and on AEN/AER reception
+# on devices supporting it. For HW drivers, all sessions will use the value
+# defined in the configuration file. This configuration option is independent
+# of the scsi_mod.scan parameter. The default is auto.
+node.session.scan = auto
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/etc/systemd/.gitignore b/pkgs/open-iscsi/open-iscsi-2.1.8/etc/systemd/.gitignore
new file mode 100644 (file)
index 0000000..2b3a64e
--- /dev/null
@@ -0,0 +1,4 @@
+iscsi-init.service
+iscsi.service
+iscsid.service
+iscsiuio.service
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/etc/systemd/ibft-rule-generator b/pkgs/open-iscsi/open-iscsi-2.1.8/etc/systemd/ibft-rule-generator
new file mode 100644 (file)
index 0000000..a464fd6
--- /dev/null
@@ -0,0 +1,36 @@
+#!/bin/bash
+#
+# Systemd rule generator for ibft interfaces
+#
+# Copyright (c) 2022 Hannes Reinecke, SUSE Labs
+# This script is licensed under the GPL.
+#
+# When booted with 'ip=ibft' dracut will rename the
+# interface to 'ibft*'. After systemd has started
+# it'll try to rename the interface yet again with
+# a persistent name.
+# But as the ibft interface is already renamed _and_
+# in use, the second renaming will fail and udev
+# will complain.
+# So add a dummy rule which signals udev the correct name
+#
+# Interface renaming happes at 80-net-setup-link.rules,
+# so we need to hook in before that.
+#
+IBFT_RULE_DIR=/run/udev/rules.d
+IBFT_RULES=${IBFT_RULE_DIR}/79-ibft.rules
+
+# ensure we have a rules directory and no rules file
+if [ -d ${IBFT_RULE_DIR} ] ; then
+    rm -f ${IBFT_RULES} 2> /dev/null
+else
+    mkdir -p ${IBFT_RULE_DIR}
+fi
+
+# create an iBFT udev rule for each iBFT NIC found
+for d in /sys/firmware/ibft/ethernet* ; do
+    [ -d "$d" ] || break
+    num="${d##*/ethernet}"
+    read mac < $d/mac
+    printf 'SUBSYSTEM=="net", KERNEL=="ibft*", ACTION=="add", DRIVERS=="?*", ATTR{address}=="%s", ATTR{type}=="1", NAME="ibft%s"\n' "$mac" "$num" >> $IBFT_RULES
+done
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/etc/systemd/iscsi-init.service.template b/pkgs/open-iscsi/open-iscsi-2.1.8/etc/systemd/iscsi-init.service.template
new file mode 100644 (file)
index 0000000..8f9a8aa
--- /dev/null
@@ -0,0 +1,19 @@
+[Unit]
+Description=One time configuration for iscsi.service
+ConditionPathExists=!/etc/iscsi/initiatorname.iscsi
+DefaultDependencies=no
+RequiresMountsFor=/etc/iscsi
+# systemd-remount-fs.service is optionally pulled in by
+# local-fs.target, don't start it here (no Wants=) but if
+# it's running wait for it to finish
+After=systemd-remount-fs.service
+
+[Install]
+# this ensures we are in the same transaction with
+# systemd-remount-fs.service
+WantedBy=systemd-remount-fs.service
+
+[Service]
+Type=oneshot
+RemainAfterExit=no
+ExecStart=/usr/bin/sh -c 'echo "InitiatorName=`@SBINDIR@/iscsi-iname`" > /etc/iscsi/initiatorname.iscsi'
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/etc/systemd/iscsi.service.template b/pkgs/open-iscsi/open-iscsi-2.1.8/etc/systemd/iscsi.service.template
new file mode 100644 (file)
index 0000000..6becab4
--- /dev/null
@@ -0,0 +1,18 @@
+[Unit]
+Description=Login and scanning of iSCSI devices
+Documentation=man:iscsiadm(8) man:iscsid(8)
+Before=remote-fs.target
+After=network-online.target iscsid.service
+Requires=iscsid.socket iscsi-init.service
+Wants=network-online.target
+
+[Service]
+Type=oneshot
+ExecStart=@SBINDIR@/iscsiadm -m node --loginall=automatic -W
+ExecStop=@SBINDIR@/iscsiadm -m node --logoutall=automatic
+ExecStop=@SBINDIR@/iscsiadm -m node --logoutall=manual
+SuccessExitStatus=21 15
+RemainAfterExit=true
+
+[Install]
+WantedBy=remote-fs.target
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/etc/systemd/iscsid.service.template b/pkgs/open-iscsi/open-iscsi-2.1.8/etc/systemd/iscsid.service.template
new file mode 100644 (file)
index 0000000..e2a50d3
--- /dev/null
@@ -0,0 +1,19 @@
+[Unit]
+Description=Open-iSCSI
+Documentation=man:iscsid(8) man:iscsiuio(8) man:iscsiadm(8)
+DefaultDependencies=no
+After=network-online.target iscsiuio.service iscsi-init.service
+Before=remote-fs-pre.target
+Wants=remote-fs-pre.target
+Requires=iscsi-init.service
+
+[Service]
+Type=notify
+NotifyAccess=main
+ExecStart=@SBINDIR@/iscsid -f
+KillMode=mixed
+Restart=on-failure
+
+[Install]
+WantedBy=multi-user.target
+Also=iscsid.socket
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/etc/systemd/iscsid.socket b/pkgs/open-iscsi/open-iscsi-2.1.8/etc/systemd/iscsid.socket
new file mode 100644 (file)
index 0000000..58a8d12
--- /dev/null
@@ -0,0 +1,9 @@
+[Unit]
+Description=Open-iSCSI iscsid Socket
+Documentation=man:iscsid(8) man:iscsiadm(8)
+
+[Socket]
+ListenStream=@ISCSIADM_ABSTRACT_NAMESPACE
+
+[Install]
+WantedBy=sockets.target
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/etc/systemd/iscsiuio.service.template b/pkgs/open-iscsi/open-iscsi-2.1.8/etc/systemd/iscsiuio.service.template
new file mode 100644 (file)
index 0000000..2e721fe
--- /dev/null
@@ -0,0 +1,20 @@
+[Unit]
+Description=iSCSI UserSpace I/O driver
+Documentation=man:iscsiuio(8)
+DefaultDependencies=no
+Conflicts=shutdown.target
+Requires=iscsid.service
+BindTo=iscsid.service
+After=network.target
+Before=remote-fs-pre.target iscsid.service
+Wants=remote-fs-pre.target
+
+[Service]
+Type=notify
+NotifyAccess=main
+ExecStart=@SBINDIR@/iscsiuio -f
+KillMode=mixed
+Restart=on-failure
+
+[Install]
+WantedBy=multi-user.target
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/etc/systemd/iscsiuio.socket b/pkgs/open-iscsi/open-iscsi-2.1.8/etc/systemd/iscsiuio.socket
new file mode 100644 (file)
index 0000000..d42cedc
--- /dev/null
@@ -0,0 +1,9 @@
+[Unit]
+Description=Open-iSCSI iscsiuio Socket
+Documentation=man:iscsiuio(8)
+
+[Socket]
+ListenStream=@ISCSID_UIP_ABSTRACT_NAMESPACE
+
+[Install]
+WantedBy=sockets.target
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/include/fw_context.h b/pkgs/open-iscsi/open-iscsi-2.1.8/include/fw_context.h
new file mode 100644 (file)
index 0000000..88c6a02
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright (C) IBM Corporation. 2007
+ * Author: Doug Maxey <dwm@austin.ibm.com>
+ *         "Prasanna Mumbai" <mumbai.prasanna@gmail.com>
+ *
+ */
+#ifndef FWPARAM_CONTEXT_H_
+#define FWPARAM_CONTEXT_H_
+
+#include <netdb.h>
+#include <net/if.h>
+
+#include "iscsi_proto.h"
+#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];
+       char chap_name[AUTH_STR_MAX_LEN];
+       char chap_password[AUTH_STR_MAX_LEN];
+       char chap_name_in[AUTH_STR_MAX_LEN];
+       char chap_password_in[AUTH_STR_MAX_LEN];
+
+       /* initiator settings */
+       char isid[10];
+       char initiatorname[TARGET_NAME_MAXLEN + 1];
+
+       /* network settings */
+       int nic_flags;
+       enum ibft_ip_prefix_origin origin;
+       int prefix;
+       char dhcp[NI_MAXHOST];
+       char iface[IF_NAMESIZE];
+       char mac[18];
+       char ipaddr[NI_MAXHOST];
+       char gateway[NI_MAXHOST];
+       char primary_dns[NI_MAXHOST];
+       char secondary_dns[NI_MAXHOST];
+       char mask[NI_MAXHOST];
+       char lun[17];
+       char vlan[15];
+
+       char scsi_host_name[64];
+};
+
+extern int fw_get_entry(struct boot_context *context);
+extern void fw_print_entry(struct boot_context *context);
+extern int fw_get_targets(struct list_head *list);
+extern void fw_free_targets(struct list_head *list);
+extern int fw_setup_nics(void);
+
+#endif /* FWPARAM_CONTEXT_H_ */
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/include/iscsi_err.h b/pkgs/open-iscsi/open-iscsi-2.1.8/include/iscsi_err.h
new file mode 100644 (file)
index 0000000..c31b05a
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Return codes used by iSCSI tools.
+ */
+#ifndef _ISCSI_ERR_
+#define _ISCSI_ERR_
+
+enum iscsi_error_list {
+       ISCSI_SUCCESS                   = 0,
+       /* Generic error */
+       ISCSI_ERR                       = 1,
+       /* session could not be found */
+       ISCSI_ERR_SESS_NOT_FOUND        = 2,
+       /* Could not allocate resource for operation */
+       ISCSI_ERR_NOMEM                 = 3,
+       /* Transport error caused operation to fail */
+       ISCSI_ERR_TRANS                 = 4,
+       /* Generic login failure */
+       ISCSI_ERR_LOGIN                 = 5,
+       /* Error accessing/managing iSCSI DB */
+       ISCSI_ERR_IDBM                  = 6,
+       /* Invalid argument */
+       ISCSI_ERR_INVAL                 = 7,
+       /* Connection timer exired while trying to connect */
+       ISCSI_ERR_TRANS_TIMEOUT         = 8,
+       /* Generic internal iscsid failure */
+       ISCSI_ERR_INTERNAL              = 9,
+       /* Logout failed */
+       ISCSI_ERR_LOGOUT                = 10,
+       /* iSCSI PDU timedout */
+       ISCSI_ERR_PDU_TIMEOUT           = 11,
+       /* iSCSI transport module not loaded in kernel or iscsid */
+       ISCSI_ERR_TRANS_NOT_FOUND       = 12,
+       /* Permission denied */
+       ISCSI_ERR_ACCESS                = 13,
+       /* Transport module did not support operation */
+       ISCSI_ERR_TRANS_CAPS            = 14,
+       /* Session is logged in */
+       ISCSI_ERR_SESS_EXISTS           = 15,
+       /* Invalid IPC MGMT request */
+       ISCSI_ERR_INVALID_MGMT_REQ      = 16,
+       /* iSNS service is not supported */
+       ISCSI_ERR_ISNS_UNAVAILABLE      = 17,
+       /* A read/write to iscsid failed */
+       ISCSI_ERR_ISCSID_COMM_ERR       = 18,
+       /* Fatal login error */
+       ISCSI_ERR_FATAL_LOGIN           = 19,
+       /* Could ont connect to iscsid */
+       ISCSI_ERR_ISCSID_NOTCONN        = 20,
+       /* No records/targets/sessions/portals found to execute operation on */
+       ISCSI_ERR_NO_OBJS_FOUND         = 21,
+       /* Could not lookup object in sysfs */
+       ISCSI_ERR_SYSFS_LOOKUP          = 22,
+       /* Could not lookup host */
+       ISCSI_ERR_HOST_NOT_FOUND        = 23,
+       /* Login failed due to authorization failure */
+       ISCSI_ERR_LOGIN_AUTH_FAILED     = 24,
+       /* iSNS query failure */
+       ISCSI_ERR_ISNS_QUERY            = 25,
+       /* iSNS registration/deregistration failed */
+       ISCSI_ERR_ISNS_REG_FAILED       = 26,
+       /* operation not supported */
+       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,
+       /* child process terminated */
+       ISCSI_ERR_CHILD_TERMINATED      = 31,
+       /* session likely not connected */
+       ISCSI_ERR_SESSION_NOT_CONNECTED = 32,
+       /* iscsid request timed out */
+       ISCSI_ERR_REQ_TIMEDOUT = 33,
+
+       /* Always last. Indicates end of error code space */
+       ISCSI_MAX_ERR_VAL,
+};
+
+extern enum iscsi_error_list iscsi_err;
+
+extern void iscsi_err_print_msg(int err);
+extern char *iscsi_err_to_str(int err);
+
+#endif
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/include/iscsi_if.h b/pkgs/open-iscsi/open-iscsi-2.1.8/include/iscsi_if.h
new file mode 100644 (file)
index 0000000..22b7c09
--- /dev/null
@@ -0,0 +1,982 @@
+/*
+ * iSCSI User/Kernel Shares (Defines, Constants, Protocol definitions, etc)
+ *
+ * Copyright (C) 2005 Dmitry Yusupov
+ * Copyright (C) 2005 Alex Aizman
+ * 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 ISCSI_IF_H
+#define ISCSI_IF_H
+
+#ifdef __KERNEL__
+#include <linux/in.h>
+#include <linux/in6.h>
+#else
+#include <netinet/in.h>
+#endif
+
+#include "iscsi_proto.h"
+
+/*
+ * NOTE: This file should be kept in sync with the kernel include file
+ * of the same name. In particular, iscsi_param and iscsi_err need
+ * to be in sync.
+ */
+
+#define ISCSI_NL_GRP_ISCSID    1
+#define ISCSI_NL_GRP_UIP       2
+
+#define UEVENT_BASE                    10
+#define KEVENT_BASE                    100
+#define ISCSI_ERR_BASE                 1000
+
+enum iscsi_uevent_e {
+       ISCSI_UEVENT_UNKNOWN            = 0,
+
+       /* down events */
+       ISCSI_UEVENT_CREATE_SESSION     = UEVENT_BASE + 1,
+       ISCSI_UEVENT_DESTROY_SESSION    = UEVENT_BASE + 2,
+       ISCSI_UEVENT_CREATE_CONN        = UEVENT_BASE + 3,
+       ISCSI_UEVENT_DESTROY_CONN       = UEVENT_BASE + 4,
+       ISCSI_UEVENT_BIND_CONN          = UEVENT_BASE + 5,
+       ISCSI_UEVENT_SET_PARAM          = UEVENT_BASE + 6,
+       ISCSI_UEVENT_START_CONN         = UEVENT_BASE + 7,
+       ISCSI_UEVENT_STOP_CONN          = UEVENT_BASE + 8,
+       ISCSI_UEVENT_SEND_PDU           = UEVENT_BASE + 9,
+       ISCSI_UEVENT_GET_STATS          = UEVENT_BASE + 10,
+       ISCSI_UEVENT_GET_PARAM          = UEVENT_BASE + 11,
+
+       ISCSI_UEVENT_TRANSPORT_EP_CONNECT       = UEVENT_BASE + 12,
+       ISCSI_UEVENT_TRANSPORT_EP_POLL          = UEVENT_BASE + 13,
+       ISCSI_UEVENT_TRANSPORT_EP_DISCONNECT    = UEVENT_BASE + 14,
+
+       ISCSI_UEVENT_TGT_DSCVR          = UEVENT_BASE + 15,
+       ISCSI_UEVENT_SET_HOST_PARAM     = UEVENT_BASE + 16,
+       ISCSI_UEVENT_UNBIND_SESSION     = UEVENT_BASE + 17,
+       ISCSI_UEVENT_CREATE_BOUND_SESSION               = UEVENT_BASE + 18,
+       ISCSI_UEVENT_TRANSPORT_EP_CONNECT_THROUGH_HOST  = UEVENT_BASE + 19,
+
+       ISCSI_UEVENT_PATH_UPDATE        = UEVENT_BASE + 20,
+       ISCSI_UEVENT_SET_IFACE_PARAMS   = UEVENT_BASE + 21,
+       ISCSI_UEVENT_PING               = UEVENT_BASE + 22,
+       ISCSI_UEVENT_GET_CHAP           = UEVENT_BASE + 23,
+       ISCSI_UEVENT_DELETE_CHAP        = UEVENT_BASE + 24,
+       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,
+       ISCSI_KEVENT_CONN_ERROR         = KEVENT_BASE + 2,
+       ISCSI_KEVENT_IF_ERROR           = KEVENT_BASE + 3,
+       ISCSI_KEVENT_DESTROY_SESSION    = KEVENT_BASE + 4,
+       ISCSI_KEVENT_UNBIND_SESSION     = KEVENT_BASE + 5,
+       ISCSI_KEVENT_CREATE_SESSION     = KEVENT_BASE + 6,
+
+       ISCSI_KEVENT_PATH_REQ           = KEVENT_BASE + 7,
+       ISCSI_KEVENT_IF_DOWN            = KEVENT_BASE + 8,
+       ISCSI_KEVENT_CONN_LOGIN_STATE   = KEVENT_BASE + 9,
+       ISCSI_KEVENT_HOST_EVENT         = KEVENT_BASE + 10,
+       ISCSI_KEVENT_PING_COMP          = KEVENT_BASE + 11,
+
+       ISCSI_KEVENT_MAX                = ISCSI_KEVENT_PING_COMP,
+};
+
+enum iscsi_tgt_dscvr {
+       ISCSI_TGT_DSCVR_SEND_TARGETS    = 1,
+       ISCSI_TGT_DSCVR_ISNS            = 2,
+       ISCSI_TGT_DSCVR_SLP             = 3,
+};
+
+enum iscsi_host_event_code {
+       ISCSI_EVENT_LINKUP              = 1,
+       ISCSI_EVENT_LINKDOWN,
+       /* must always be last */
+       ISCSI_EVENT_MAX,
+};
+
+struct iscsi_uevent {
+       uint32_t type; /* k/u events type */
+       uint32_t iferror; /* carries interface or resource errors */
+       uint64_t transport_handle;
+
+       union {
+               /* messages u -> k */
+               struct msg_create_session {
+                       uint32_t        initial_cmdsn;
+                       uint16_t        cmds_max;
+                       uint16_t        queue_depth;
+               } c_session;
+               struct msg_create_bound_session {
+                       uint64_t        ep_handle;
+                       uint32_t        initial_cmdsn;
+                       uint16_t        cmds_max;
+                       uint16_t        queue_depth;
+               } c_bound_session;
+               struct msg_destroy_session {
+                       uint32_t        sid;
+               } d_session;
+               struct msg_create_conn {
+                       uint32_t        sid;
+                       uint32_t        cid;
+               } c_conn;
+               struct msg_bind_conn {
+                       uint32_t        sid;
+                       uint32_t        cid;
+                       uint64_t        transport_eph;
+                       uint32_t        is_leading;
+               } b_conn;
+               struct msg_destroy_conn {
+                       uint32_t        sid;
+                       uint32_t        cid;
+               } d_conn;
+               struct msg_send_pdu {
+                       uint32_t        sid;
+                       uint32_t        cid;
+                       uint32_t        hdr_size;
+                       uint32_t        data_size;
+               } send_pdu;
+               struct msg_set_param {
+                       uint32_t        sid;
+                       uint32_t        cid;
+                       uint32_t        param; /* enum iscsi_param */
+                       uint32_t        len;
+               } set_param;
+               struct msg_start_conn {
+                       uint32_t        sid;
+                       uint32_t        cid;
+               } start_conn;
+               struct msg_stop_conn {
+                       uint32_t        sid;
+                       uint32_t        cid;
+                       uint64_t        conn_handle;
+                       uint32_t        flag;
+               } stop_conn;
+               struct msg_get_stats {
+                       uint32_t        sid;
+                       uint32_t        cid;
+               } get_stats;
+               struct msg_transport_connect {
+                       uint32_t        non_blocking;
+               } ep_connect;
+               struct msg_transport_connect_through_host {
+                       uint32_t        host_no;
+                       uint32_t        non_blocking;
+               } ep_connect_through_host;
+               struct msg_transport_poll {
+                       uint64_t        ep_handle;
+                       uint32_t        timeout_ms;
+               } ep_poll;
+               struct msg_transport_disconnect {
+                       uint64_t        ep_handle;
+               } ep_disconnect;
+               struct msg_tgt_dscvr {
+                       enum iscsi_tgt_dscvr    type;
+                       uint32_t        host_no;
+                       /*
+                        * enable = 1 to establish a new connection
+                        * with the server. enable = 0 to disconnect
+                        * from the server. Used primarily to switch
+                        * from one iSNS server to another.
+                        */
+                       uint32_t        enable;
+               } tgt_dscvr;
+               struct msg_set_host_param {
+                       uint32_t        host_no;
+                       uint32_t        param; /* enum iscsi_host_param */
+                       uint32_t        len;
+               } set_host_param;
+               struct msg_set_path {
+                       uint32_t        host_no;
+               } set_path;
+               struct msg_set_iface_params {
+                       uint32_t        host_no;
+                       uint32_t        count;
+               } set_iface_params;
+               struct msg_iscsi_ping {
+                       uint32_t        host_no;
+                       uint32_t        iface_num;
+                       uint32_t        iface_type;
+                       uint32_t        payload_size;
+                       uint32_t        pid;    /* unique ping id associated
+                                                  with each ping request */
+               } iscsi_ping;
+               struct msg_get_chap {
+                       uint32_t        host_no;
+                       uint32_t        num_entries; /* number of CHAP entries
+                                                     * on request, number of
+                                                     * valid CHAP entries on
+                                                     * response */
+                       uint16_t        chap_tbl_idx;
+               } get_chap;
+               struct msg_delete_chap {
+                       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 */
+               int                     retcode;
+               struct msg_create_session_ret {
+                       uint32_t        sid;
+                       uint32_t        host_no;
+               } c_session_ret;
+               struct msg_create_conn_ret {
+                       uint32_t        sid;
+                       uint32_t        cid;
+               } c_conn_ret;
+               struct msg_unbind_session {
+                       uint32_t        sid;
+                       uint32_t        host_no;
+               } unbind_session;
+               struct msg_recv_req {
+                       uint32_t        sid;
+                       uint32_t        cid;
+                       uint64_t        recv_handle;
+               } recv_req;
+               struct msg_conn_login {
+                       uint32_t        sid;
+                       uint32_t        cid;
+                       uint32_t        state; /* enum iscsi_conn_state */
+               } conn_login;
+               struct msg_conn_error {
+                       uint32_t        sid;
+                       uint32_t        cid;
+                       uint32_t        error; /* enum iscsi_err */
+               } connerror;
+               struct msg_session_destroyed {
+                       uint32_t        host_no;
+                       uint32_t        sid;
+               } d_session;
+               struct msg_transport_connect_ret {
+                       uint64_t        handle;
+               } ep_connect_ret;
+               struct msg_req_path {
+                       uint32_t        host_no;
+               } req_path;
+               struct msg_notify_if_down {
+                       uint32_t        host_no;
+               } notify_if_down;
+               struct msg_host_event {
+                       uint32_t        host_no;
+                       uint32_t        data_size;
+                       enum iscsi_host_event_code code;
+               } host_event;
+               struct msg_ping_comp {
+                       uint32_t        host_no;
+                       uint32_t        status; /* enum
+                                                * iscsi_ping_status_code */
+                       uint32_t        pid;    /* unique ping id associated
+                                                  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))));
+
+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 */
+       uint16_t param;         /* iscsi param value */
+       uint8_t iface_type;     /* IPv4 or IPv6 */
+       uint8_t param_type;     /* iscsi_param_type */
+       uint8_t value[0];       /* length sized value follows */
+} __attribute__((__packed__));
+
+/*
+ * To keep the struct iscsi_uevent size the same for userspace code
+ * compatibility, the main structure for ISCSI_UEVENT_PATH_UPDATE and
+ * ISCSI_KEVENT_PATH_REQ is defined separately and comes after the
+ * struct iscsi_uevent in the NETLINK_ISCSI message.
+ */
+struct iscsi_path {
+       uint64_t        handle;
+       uint8_t         mac_addr[6];
+       uint8_t         mac_addr_old[6];
+       uint32_t        ip_addr_len;    /* 4 or 16 */
+       union {
+               struct in_addr  v4_addr;
+               struct in6_addr v6_addr;
+       } src;
+       union {
+               struct in_addr  v4_addr;
+               struct in6_addr v6_addr;
+       } dst;
+       uint16_t        vlan_id;
+       uint16_t        pmtu;
+} __attribute__ ((aligned (sizeof(uint64_t))));
+
+/* iscsi iface enabled/disabled setting */
+#define ISCSI_IFACE_DISABLE    0x01
+#define ISCSI_IFACE_ENABLE     0x02
+
+/* ipv4 bootproto */
+#define ISCSI_BOOTPROTO_STATIC         0x01
+#define ISCSI_BOOTPROTO_DHCP           0x02
+
+/* ipv6 addr autoconfig type */
+#define ISCSI_IPV6_AUTOCFG_DISABLE             0x01
+#define ISCSI_IPV6_AUTOCFG_ND_ENABLE           0x02
+#define ISCSI_IPV6_AUTOCFG_DHCPV6_ENABLE       0x03
+
+/* ipv6 link local addr type */
+#define ISCSI_IPV6_LINKLOCAL_AUTOCFG_ENABLE    0x01
+#define ISCSI_IPV6_LINKLOCAL_AUTOCFG_DISABLE   0x02
+
+/* ipv6 router addr type */
+#define ISCSI_IPV6_ROUTER_AUTOCFG_ENABLE       0x01
+#define ISCSI_IPV6_ROUTER_AUTOCFG_DISABLE      0x02
+
+/* Interface IP Type */
+enum iscsi_iface_type {
+       ISCSI_IFACE_TYPE_IPV4                   = 1,
+       ISCSI_IFACE_TYPE_IPV6,
+};
+
+#define ISCSI_MAX_VLAN_ID              4095
+#define ISCSI_MAX_VLAN_PRIORITY                7
+
+/* iscsi vlan enable/disabled setting */
+#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,
+       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 {
+       ISCSI_CONN_STATE_FREE,
+       ISCSI_CONN_STATE_XPT_WAIT,
+       ISCSI_CONN_STATE_IN_LOGIN,
+       ISCSI_CONN_STATE_LOGGED_IN,
+       ISCSI_CONN_STATE_IN_LOGOUT,
+       ISCSI_CONN_STATE_LOGOUT_REQUESTED,
+       ISCSI_CONN_STATE_CLEANUP_WAIT,
+};
+
+/*
+ * Common error codes
+ */
+enum iscsi_err {
+       ISCSI_OK                        = 0,
+
+       ISCSI_ERR_DATASN                = ISCSI_ERR_BASE + 1,
+       ISCSI_ERR_DATA_OFFSET           = ISCSI_ERR_BASE + 2,
+       ISCSI_ERR_MAX_CMDSN             = ISCSI_ERR_BASE + 3,
+       ISCSI_ERR_EXP_CMDSN             = ISCSI_ERR_BASE + 4,
+       ISCSI_ERR_BAD_OPCODE            = ISCSI_ERR_BASE + 5,
+       ISCSI_ERR_DATALEN               = ISCSI_ERR_BASE + 6,
+       ISCSI_ERR_AHSLEN                = ISCSI_ERR_BASE + 7,
+       ISCSI_ERR_PROTO                 = ISCSI_ERR_BASE + 8,
+       ISCSI_ERR_LUN                   = ISCSI_ERR_BASE + 9,
+       ISCSI_ERR_BAD_ITT               = ISCSI_ERR_BASE + 10,
+       ISCSI_ERR_CONN_FAILED           = ISCSI_ERR_BASE + 11,
+       ISCSI_ERR_R2TSN                 = ISCSI_ERR_BASE + 12,
+       ISCSI_ERR_SESSION_FAILED        = ISCSI_ERR_BASE + 13,
+       ISCSI_ERR_HDR_DGST              = ISCSI_ERR_BASE + 14,
+       ISCSI_ERR_DATA_DGST             = ISCSI_ERR_BASE + 15,
+       ISCSI_ERR_PARAM_NOT_FOUND       = ISCSI_ERR_BASE + 16,
+       ISCSI_ERR_NO_SCSI_CMD           = ISCSI_ERR_BASE + 17,
+       ISCSI_ERR_INVALID_HOST          = ISCSI_ERR_BASE + 18,
+       ISCSI_ERR_XMIT_FAILED           = ISCSI_ERR_BASE + 19,
+       ISCSI_ERR_TCP_CONN_CLOSE        = ISCSI_ERR_BASE + 20,
+       ISCSI_ERR_SCSI_EH_SESSION_RST   = ISCSI_ERR_BASE + 21,
+       ISCSI_ERR_NOP_TIMEDOUT          = ISCSI_ERR_BASE + 22,
+};
+
+/*
+ * iSCSI Parameters (RFC3720)
+ */
+enum iscsi_param {
+       /* passed in using netlink set param */
+       ISCSI_PARAM_MAX_RECV_DLENGTH,
+       ISCSI_PARAM_MAX_XMIT_DLENGTH,
+       ISCSI_PARAM_HDRDGST_EN,
+       ISCSI_PARAM_DATADGST_EN,
+       ISCSI_PARAM_INITIAL_R2T_EN,
+       ISCSI_PARAM_MAX_R2T,
+       ISCSI_PARAM_IMM_DATA_EN,
+       ISCSI_PARAM_FIRST_BURST,
+       ISCSI_PARAM_MAX_BURST,
+       ISCSI_PARAM_PDU_INORDER_EN,
+       ISCSI_PARAM_DATASEQ_INORDER_EN,
+       ISCSI_PARAM_ERL,
+       ISCSI_PARAM_IFMARKER_EN,
+       ISCSI_PARAM_OFMARKER_EN,
+       ISCSI_PARAM_EXP_STATSN,
+       ISCSI_PARAM_TARGET_NAME,
+       ISCSI_PARAM_TPGT,
+       ISCSI_PARAM_PERSISTENT_ADDRESS,
+       ISCSI_PARAM_PERSISTENT_PORT,
+       ISCSI_PARAM_SESS_RECOVERY_TMO,
+
+       /* passed in through bind conn using transport_fd */
+       ISCSI_PARAM_CONN_PORT,
+       ISCSI_PARAM_CONN_ADDRESS,
+
+       ISCSI_PARAM_USERNAME,
+       ISCSI_PARAM_USERNAME_IN,
+       ISCSI_PARAM_PASSWORD,
+       ISCSI_PARAM_PASSWORD_IN,
+
+       ISCSI_PARAM_FAST_ABORT,
+       ISCSI_PARAM_ABORT_TMO,
+       ISCSI_PARAM_LU_RESET_TMO,
+       ISCSI_PARAM_HOST_RESET_TMO,
+
+       ISCSI_PARAM_PING_TMO,
+       ISCSI_PARAM_RECV_TMO,
+
+       ISCSI_PARAM_IFACE_NAME,
+       ISCSI_PARAM_ISID,
+       ISCSI_PARAM_INITIATOR_NAME,
+
+       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,
+       ISCSI_PARAM_LOCAL_IPADDR,
+       /* must always be last */
+       ISCSI_PARAM_MAX,
+};
+
+/* 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,
+};
+
+/* 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_SPEED_25GBPS         = 0x20,
+       ISCSI_PORT_SPEED_40GBPS         = 0x40,
+};
+
+/* 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 {
+       ISCSI_PING_SUCCESS                      = 0,
+       ISCSI_PING_FW_DISABLED                  = 0x1,
+       ISCSI_PING_IPADDR_INVALID               = 0x2,
+       ISCSI_PING_LINKLOCAL_IPV6_ADDR_INVALID  = 0x3,
+       ISCSI_PING_TIMEOUT                      = 0x4,
+       ISCSI_PING_INVALID_DEST_ADDR            = 0x5,
+       ISCSI_PING_OVERSIZE_PACKET              = 0x6,
+       ISCSI_PING_ICMP_ERROR                   = 0x7,
+       ISCSI_PING_MAX_REQ_EXCEEDED             = 0x8,
+       ISCSI_PING_NO_ARP_RECEIVED              = 0x9,
+};
+
+#define iscsi_ptr(_handle) ((void*)(unsigned long)_handle)
+#define iscsi_handle(_ptr) ((uint64_t)(unsigned long)_ptr)
+
+/*
+ * These flags presents iSCSI Data-Path capabilities.
+ */
+#define CAP_RECOVERY_L0                0x1
+#define CAP_RECOVERY_L1                0x2
+#define CAP_RECOVERY_L2                0x4
+#define CAP_MULTI_R2T          0x8
+#define CAP_HDRDGST            0x10
+#define CAP_DATADGST           0x20
+#define CAP_MULTI_CONN         0x40
+#define CAP_TEXT_NEGO          0x80
+#define CAP_MARKERS            0x100
+#define CAP_FW_DB              0x200
+#define CAP_SENDTARGETS_OFFLOAD        0x400   /* offload discovery process */
+#define CAP_DATA_PATH_OFFLOAD  0x800   /* offload entire IO path */
+#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 session login */
+
+/*
+ * These flags describes reason of stop_conn() call
+ */
+#define STOP_CONN_TERM         0x1
+#define STOP_CONN_SUSPEND      0x2
+#define STOP_CONN_RECOVER      0x3
+
+#define ISCSI_STATS_CUSTOM_MAX         32
+#define ISCSI_STATS_CUSTOM_DESC_MAX    64
+struct iscsi_stats_custom {
+       char desc[ISCSI_STATS_CUSTOM_DESC_MAX];
+       uint64_t value;
+};
+
+/*
+ * struct iscsi_stats - iSCSI Statistics (iSCSI MIB)
+ *
+ * Note: this structure contains counters collected on per-connection basis.
+ */
+struct iscsi_stats {
+       /* octets */
+       uint64_t txdata_octets;
+       uint64_t rxdata_octets;
+
+       /* xmit pdus */
+       uint32_t noptx_pdus;
+       uint32_t scsicmd_pdus;
+       uint32_t tmfcmd_pdus;
+       uint32_t login_pdus;
+       uint32_t text_pdus;
+       uint32_t dataout_pdus;
+       uint32_t logout_pdus;
+       uint32_t snack_pdus;
+
+       /* recv pdus */
+       uint32_t noprx_pdus;
+       uint32_t scsirsp_pdus;
+       uint32_t tmfrsp_pdus;
+       uint32_t textrsp_pdus;
+       uint32_t datain_pdus;
+       uint32_t logoutrsp_pdus;
+       uint32_t r2t_pdus;
+       uint32_t async_pdus;
+       uint32_t rjt_pdus;
+
+       /* errors */
+       uint32_t digest_err;
+       uint32_t timeout_err;
+
+       /*
+        * iSCSI Custom Statistics support, i.e. Transport could
+        * extend existing MIB statistics with its own specific statistics
+        * up to ISCSI_STATS_CUSTOM_MAX
+        */
+       uint32_t custom_length;
+       struct iscsi_stats_custom custom[]
+               __attribute__ ((aligned (sizeof(uint64_t))));
+};
+
+enum chap_type_e {
+       CHAP_TYPE_OUT,
+       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;
+       char username[ISCSI_CHAP_AUTH_NAME_MAX_LEN];
+       uint8_t password[ISCSI_CHAP_AUTH_SECRET_MAX_LEN];
+       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[]
+                __attribute__ ((aligned (sizeof(uint64_t))));
+};
+
+#endif
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/include/iscsi_net_util.h b/pkgs/open-iscsi/open-iscsi-2.1.8/include/iscsi_net_util.h
new file mode 100644 (file)
index 0000000..a69af9d
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef __ISCSI_NET_UTIL_h__
+#define __ISCSI_NET_UTIL_h__
+
+#define ISCSI_HWADDRESS_BUF_SIZE 18
+
+#ifndef SBINDIR
+#define SBINDIR        "/sbin"
+#endif
+
+#define ISCSIUIO_PATH SBINDIR"/iscsiuio"
+
+extern int net_get_transport_name_from_netdev(char *netdev, char *transport);
+extern int net_get_netdev_from_hwaddress(char *hwaddress, char *netdev);
+extern int net_setup_netdev(char *netdev, char *local_ip, char *mask,
+                           char *gateway, char *vlan, char *remote_ip,
+                           int needs_bringup);
+extern int net_ifup_netdev(char *netdev);
+
+#endif
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/include/iscsi_proto.h b/pkgs/open-iscsi/open-iscsi-2.1.8/include/iscsi_proto.h
new file mode 100644 (file)
index 0000000..1d14b89
--- /dev/null
@@ -0,0 +1,642 @@
+/*
+ * RFC 3720 (iSCSI) protocol data types
+ *
+ * Copyright (C) 2005 Dmitry Yusupov
+ * Copyright (C) 2005 Alex Aizman
+ * 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 ISCSI_PROTO_H
+#define ISCSI_PROTO_H
+
+#ifndef __KERNEL__
+#include <stdint.h>
+#endif
+#include <linux/types.h>
+
+#define ISCSI_DRAFT20_VERSION  0x00
+
+/* default iSCSI listen port for incoming connections */
+#define ISCSI_LISTEN_PORT      3260
+
+/* Padding word length */
+#define ISCSI_PAD_LEN          4
+
+/*
+ * useful common(control and data pathes) macro
+ */
+#define ntoh24(p) (((p)[0] << 16) | ((p)[1] << 8) | ((p)[2]))
+#define hton24(p, v) { \
+        p[0] = (((v) >> 16) & 0xFF); \
+        p[1] = (((v) >> 8) & 0xFF); \
+        p[2] = ((v) & 0xFF); \
+}
+#define zero_data(p) {p[0]=0;p[1]=0;p[2]=0;}
+
+#if !defined(__bitwise)
+/*
+ * If running svn modules we may need to define these.
+ * This should not go upstream since this is already properly defined there
+ */
+#ifdef __CHECKER__
+#define __bitwise__ __attribute__((bitwise))
+#else
+#define __bitwise__
+#endif
+#ifdef __CHECK_ENDIAN__
+#define __bitwise __bitwise__
+#else
+#define __bitwise
+#endif
+#endif
+
+/* initiator tags; opaque for target */
+typedef uint32_t __bitwise__ itt_t;
+/* below makes sense only for initiator that created this tag */
+#define build_itt(itt, age) ((__force itt_t)\
+       ((itt) | ((age) << ISCSI_AGE_SHIFT)))
+#define get_itt(itt) ((__force uint32_t)(itt_t)(itt) & ISCSI_ITT_MASK)
+#define RESERVED_ITT ((__force itt_t)0xffffffff)
+
+/*
+ * iSCSI Template Message Header
+ */
+struct iscsi_hdr {
+       uint8_t         opcode;
+       uint8_t         flags;          /* Final bit */
+       uint8_t         rsvd2[2];
+       uint8_t         hlength;        /* AHSs total length */
+       uint8_t         dlength[3];     /* Data length */
+       uint8_t         lun[8];
+       itt_t           itt;            /* Initiator Task Tag, opaque for target */
+       __be32          ttt;            /* Target Task Tag */
+       __be32          statsn;
+       __be32          exp_statsn;
+       __be32          max_statsn;
+       uint8_t         other[12];
+};
+
+/************************* RFC 3720 Begin *****************************/
+
+#define ISCSI_RESERVED_TAG             0xffffffff
+
+/* Opcode encoding bits */
+#define ISCSI_OP_RETRY                 0x80
+#define ISCSI_OP_IMMEDIATE             0x40
+#define ISCSI_OPCODE_MASK              0x3F
+
+/* Initiator Opcode values */
+#define ISCSI_OP_NOOP_OUT              0x00
+#define ISCSI_OP_SCSI_CMD              0x01
+#define ISCSI_OP_SCSI_TMFUNC           0x02
+#define ISCSI_OP_LOGIN                 0x03
+#define ISCSI_OP_TEXT                  0x04
+#define ISCSI_OP_SCSI_DATA_OUT         0x05
+#define ISCSI_OP_LOGOUT                        0x06
+#define ISCSI_OP_SNACK                 0x10
+
+#define ISCSI_OP_VENDOR1_CMD           0x1c
+#define ISCSI_OP_VENDOR2_CMD           0x1d
+#define ISCSI_OP_VENDOR3_CMD           0x1e
+#define ISCSI_OP_VENDOR4_CMD           0x1f
+
+/* Target Opcode values */
+#define ISCSI_OP_NOOP_IN               0x20
+#define ISCSI_OP_SCSI_CMD_RSP          0x21
+#define ISCSI_OP_SCSI_TMFUNC_RSP       0x22
+#define ISCSI_OP_LOGIN_RSP             0x23
+#define ISCSI_OP_TEXT_RSP              0x24
+#define ISCSI_OP_SCSI_DATA_IN          0x25
+#define ISCSI_OP_LOGOUT_RSP            0x26
+#define ISCSI_OP_R2T                   0x31
+#define ISCSI_OP_ASYNC_EVENT           0x32
+#define ISCSI_OP_REJECT                        0x3f
+
+struct iscsi_ahs_hdr {
+       __be16 ahslength;
+       uint8_t ahstype;
+       uint8_t ahspec[5];
+};
+
+#define ISCSI_AHSTYPE_CDB              1
+#define ISCSI_AHSTYPE_RLENGTH          2
+#define ISCSI_CDB_SIZE                 16
+
+/* iSCSI PDU Header */
+struct iscsi_cmd {
+       uint8_t opcode;
+       uint8_t flags;
+       __be16 rsvd2;
+       uint8_t hlength;
+       uint8_t dlength[3];
+       uint8_t lun[8];
+       itt_t    itt;   /* Initiator Task Tag */
+       __be32 data_length;
+       __be32 cmdsn;
+       __be32 exp_statsn;
+       uint8_t cdb[ISCSI_CDB_SIZE];    /* SCSI Command Block */
+       /* Additional Data (Command Dependent) */
+};
+
+/* Command PDU flags */
+#define ISCSI_FLAG_CMD_FINAL           0x80
+#define ISCSI_FLAG_CMD_READ            0x40
+#define ISCSI_FLAG_CMD_WRITE           0x20
+#define ISCSI_FLAG_CMD_ATTR_MASK       0x07    /* 3 bits */
+
+/* SCSI Command Attribute values */
+#define ISCSI_ATTR_UNTAGGED            0
+#define ISCSI_ATTR_SIMPLE              1
+#define ISCSI_ATTR_ORDERED             2
+#define ISCSI_ATTR_HEAD_OF_QUEUE       3
+#define ISCSI_ATTR_ACA                 4
+
+struct iscsi_rlength_ahdr {
+       __be16 ahslength;
+       uint8_t ahstype;
+       uint8_t reserved;
+       __be32 read_length;
+};
+
+/* Extended CDB AHS */
+struct iscsi_ecdb_ahdr {
+       __be16 ahslength;       /* CDB length - 15, including reserved byte */
+       uint8_t ahstype;
+       uint8_t reserved;
+       /* 4-byte aligned extended CDB spillover */
+       uint8_t ecdb[260 - ISCSI_CDB_SIZE];
+};
+
+/* SCSI Response Header */
+struct iscsi_cmd_rsp {
+       uint8_t opcode;
+       uint8_t flags;
+       uint8_t response;
+       uint8_t cmd_status;
+       uint8_t hlength;
+       uint8_t dlength[3];
+       uint8_t rsvd[8];
+       itt_t    itt;   /* Initiator Task Tag */
+       __be32  rsvd1;
+       __be32  statsn;
+       __be32  exp_cmdsn;
+       __be32  max_cmdsn;
+       __be32  exp_datasn;
+       __be32  bi_residual_count;
+       __be32  residual_count;
+       /* Response or Sense Data (optional) */
+};
+
+/* Command Response PDU flags */
+#define ISCSI_FLAG_CMD_BIDI_OVERFLOW   0x10
+#define ISCSI_FLAG_CMD_BIDI_UNDERFLOW  0x08
+#define ISCSI_FLAG_CMD_OVERFLOW                0x04
+#define ISCSI_FLAG_CMD_UNDERFLOW       0x02
+
+/* iSCSI Status values. Valid if Rsp Selector bit is not set */
+#define ISCSI_STATUS_CMD_COMPLETED     0
+#define ISCSI_STATUS_TARGET_FAILURE    1
+#define ISCSI_STATUS_SUBSYS_FAILURE    2
+
+/* Asynchronous Event Header */
+struct iscsi_async {
+       uint8_t opcode;
+       uint8_t flags;
+       uint8_t rsvd2[2];
+       uint8_t rsvd3;
+       uint8_t dlength[3];
+       uint8_t lun[8];
+       uint8_t rsvd4[8];
+       __be32  statsn;
+       __be32  exp_cmdsn;
+       __be32  max_cmdsn;
+       uint8_t async_event;
+       uint8_t async_vcode;
+       __be16  param1;
+       __be16  param2;
+       __be16  param3;
+       uint8_t rsvd5[4];
+};
+
+/* iSCSI Event Codes */
+#define ISCSI_ASYNC_MSG_SCSI_EVENT                     0
+#define ISCSI_ASYNC_MSG_REQUEST_LOGOUT                 1
+#define ISCSI_ASYNC_MSG_DROPPING_CONNECTION            2
+#define ISCSI_ASYNC_MSG_DROPPING_ALL_CONNECTIONS       3
+#define ISCSI_ASYNC_MSG_PARAM_NEGOTIATION              4
+#define ISCSI_ASYNC_MSG_VENDOR_SPECIFIC                        255
+
+/* NOP-Out Message */
+struct iscsi_nopout {
+       uint8_t opcode;
+       uint8_t flags;
+       __be16  rsvd2;
+       uint8_t rsvd3;
+       uint8_t dlength[3];
+       uint8_t lun[8];
+       itt_t    itt;   /* Initiator Task Tag */
+       __be32  ttt;    /* Target Transfer Tag */
+       __be32  cmdsn;
+       __be32  exp_statsn;
+       uint8_t rsvd4[16];
+};
+
+/* NOP-In Message */
+struct iscsi_nopin {
+       uint8_t opcode;
+       uint8_t flags;
+       __be16  rsvd2;
+       uint8_t rsvd3;
+       uint8_t dlength[3];
+       uint8_t lun[8];
+       itt_t    itt;   /* Initiator Task Tag */
+       __be32  ttt;    /* Target Transfer Tag */
+       __be32  statsn;
+       __be32  exp_cmdsn;
+       __be32  max_cmdsn;
+       uint8_t rsvd4[12];
+};
+
+/* SCSI Task Management Message Header */
+struct iscsi_tm {
+       uint8_t opcode;
+       uint8_t flags;
+       uint8_t rsvd1[2];
+       uint8_t hlength;
+       uint8_t dlength[3];
+       uint8_t lun[8];
+       itt_t    itt;   /* Initiator Task Tag */
+       itt_t    rtt;   /* Reference Task Tag */
+       __be32  cmdsn;
+       __be32  exp_statsn;
+       __be32  refcmdsn;
+       __be32  exp_datasn;
+       uint8_t rsvd2[8];
+};
+
+#define ISCSI_FLAG_TM_FUNC_MASK                        0x7F
+
+/* Function values */
+#define ISCSI_TM_FUNC_ABORT_TASK               1
+#define ISCSI_TM_FUNC_ABORT_TASK_SET           2
+#define ISCSI_TM_FUNC_CLEAR_ACA                        3
+#define ISCSI_TM_FUNC_CLEAR_TASK_SET           4
+#define ISCSI_TM_FUNC_LOGICAL_UNIT_RESET       5
+#define ISCSI_TM_FUNC_TARGET_WARM_RESET                6
+#define ISCSI_TM_FUNC_TARGET_COLD_RESET                7
+#define ISCSI_TM_FUNC_TASK_REASSIGN            8
+
+#define ISCSI_TM_FUNC_VALUE(hdr) ((hdr)->flags & ISCSI_FLAG_TM_FUNC_MASK)
+
+/* SCSI Task Management Response Header */
+struct iscsi_tm_rsp {
+       uint8_t opcode;
+       uint8_t flags;
+       uint8_t response;       /* see Response values below */
+       uint8_t qualifier;
+       uint8_t hlength;
+       uint8_t dlength[3];
+       uint8_t rsvd2[8];
+       itt_t    itt;   /* Initiator Task Tag */
+       itt_t    rtt;   /* Reference Task Tag */
+       __be32  statsn;
+       __be32  exp_cmdsn;
+       __be32  max_cmdsn;
+       uint8_t rsvd3[12];
+};
+
+/* Response values */
+#define ISCSI_TMF_RSP_COMPLETE         0x00
+#define ISCSI_TMF_RSP_NO_TASK          0x01
+#define ISCSI_TMF_RSP_NO_LUN           0x02
+#define ISCSI_TMF_RSP_TASK_ALLEGIANT   0x03
+#define ISCSI_TMF_RSP_NO_FAILOVER      0x04
+#define ISCSI_TMF_RSP_NOT_SUPPORTED    0x05
+#define ISCSI_TMF_RSP_AUTH_FAILED      0x06
+#define ISCSI_TMF_RSP_REJECTED         0xff
+
+/* Ready To Transfer Header */
+struct iscsi_r2t_rsp {
+       uint8_t opcode;
+       uint8_t flags;
+       uint8_t rsvd2[2];
+       uint8_t hlength;
+       uint8_t dlength[3];
+       uint8_t lun[8];
+       itt_t    itt;   /* Initiator Task Tag */
+       __be32  ttt;    /* Target Transfer Tag */
+       __be32  statsn;
+       __be32  exp_cmdsn;
+       __be32  max_cmdsn;
+       __be32  r2tsn;
+       __be32  data_offset;
+       __be32  data_length;
+};
+
+/* SCSI Data Hdr */
+struct iscsi_data {
+       uint8_t opcode;
+       uint8_t flags;
+       uint8_t rsvd2[2];
+       uint8_t rsvd3;
+       uint8_t dlength[3];
+       uint8_t lun[8];
+       itt_t    itt;
+       __be32  ttt;
+       __be32  rsvd4;
+       __be32  exp_statsn;
+       __be32  rsvd5;
+       __be32  datasn;
+       __be32  offset;
+       __be32  rsvd6;
+       /* Payload */
+};
+
+/* SCSI Data Response Hdr */
+struct iscsi_data_rsp {
+       uint8_t opcode;
+       uint8_t flags;
+       uint8_t rsvd2;
+       uint8_t cmd_status;
+       uint8_t hlength;
+       uint8_t dlength[3];
+       uint8_t lun[8];
+       itt_t    itt;
+       __be32  ttt;
+       __be32  statsn;
+       __be32  exp_cmdsn;
+       __be32  max_cmdsn;
+       __be32  datasn;
+       __be32  offset;
+       __be32  residual_count;
+};
+
+/* Data Response PDU flags */
+#define ISCSI_FLAG_DATA_ACK            0x40
+#define ISCSI_FLAG_DATA_OVERFLOW       0x04
+#define ISCSI_FLAG_DATA_UNDERFLOW      0x02
+#define ISCSI_FLAG_DATA_STATUS         0x01
+
+/* Text Header */
+struct iscsi_text {
+       uint8_t opcode;
+       uint8_t flags;
+       uint8_t rsvd2[2];
+       uint8_t hlength;
+       uint8_t dlength[3];
+       uint8_t rsvd4[8];
+       itt_t    itt;
+       __be32  ttt;
+       __be32  cmdsn;
+       __be32  exp_statsn;
+       uint8_t rsvd5[16];
+       /* Text - key=value pairs */
+};
+
+#define ISCSI_FLAG_TEXT_CONTINUE       0x40
+
+/* Text Response Header */
+struct iscsi_text_rsp {
+       uint8_t opcode;
+       uint8_t flags;
+       uint8_t rsvd2[2];
+       uint8_t hlength;
+       uint8_t dlength[3];
+       uint8_t rsvd4[8];
+       itt_t    itt;
+       __be32  ttt;
+       __be32  statsn;
+       __be32  exp_cmdsn;
+       __be32  max_cmdsn;
+       uint8_t rsvd5[12];
+       /* Text Response - key:value pairs */
+};
+
+/* Login Header */
+struct iscsi_login {
+       uint8_t opcode;
+       uint8_t flags;
+       uint8_t max_version;    /* Max. version supported */
+       uint8_t min_version;    /* Min. version supported */
+       uint8_t hlength;
+       uint8_t dlength[3];
+       uint8_t isid[6];        /* Initiator Session ID */
+       __be16  tsih;   /* Target Session Handle */
+       itt_t    itt;   /* Initiator Task Tag */
+       __be16  cid;
+       __be16  rsvd3;
+       __be32  cmdsn;
+       __be32  exp_statsn;
+       uint8_t rsvd5[16];
+};
+
+/* Login PDU flags */
+#define ISCSI_FLAG_LOGIN_TRANSIT               0x80
+#define ISCSI_FLAG_LOGIN_CONTINUE              0x40
+#define ISCSI_FLAG_LOGIN_CURRENT_STAGE_MASK    0x0C    /* 2 bits */
+#define ISCSI_FLAG_LOGIN_NEXT_STAGE_MASK       0x03    /* 2 bits */
+
+#define ISCSI_LOGIN_CURRENT_STAGE(flags) \
+       ((flags & ISCSI_FLAG_LOGIN_CURRENT_STAGE_MASK) >> 2)
+#define ISCSI_LOGIN_NEXT_STAGE(flags) \
+       (flags & ISCSI_FLAG_LOGIN_NEXT_STAGE_MASK)
+
+/* Login Response Header */
+struct iscsi_login_rsp {
+       uint8_t opcode;
+       uint8_t flags;
+       uint8_t max_version;    /* Max. version supported */
+       uint8_t active_version; /* Active version */
+       uint8_t hlength;
+       uint8_t dlength[3];
+       uint8_t isid[6];        /* Initiator Session ID */
+       __be16  tsih;   /* Target Session Handle */
+       itt_t    itt;   /* Initiator Task Tag */
+       __be32  rsvd3;
+       __be32  statsn;
+       __be32  exp_cmdsn;
+       __be32  max_cmdsn;
+       uint8_t status_class;   /* see Login RSP ststus classes below */
+       uint8_t status_detail;  /* see Login RSP Status details below */
+       uint8_t rsvd4[10];
+};
+
+/* Login stage (phase) codes for CSG, NSG */
+#define ISCSI_INITIAL_LOGIN_STAGE              -1
+#define ISCSI_SECURITY_NEGOTIATION_STAGE       0
+#define ISCSI_OP_PARMS_NEGOTIATION_STAGE       1
+#define ISCSI_FULL_FEATURE_PHASE               3
+
+/* Login Status response classes */
+#define ISCSI_STATUS_CLS_SUCCESS               0x00
+#define ISCSI_STATUS_CLS_REDIRECT              0x01
+#define ISCSI_STATUS_CLS_INITIATOR_ERR         0x02
+#define ISCSI_STATUS_CLS_TARGET_ERR            0x03
+
+/* Login Status response detail codes */
+/* Class-0 (Success) */
+#define ISCSI_LOGIN_STATUS_ACCEPT              0x00
+
+/* Class-1 (Redirection) */
+#define ISCSI_LOGIN_STATUS_TGT_MOVED_TEMP      0x01
+#define ISCSI_LOGIN_STATUS_TGT_MOVED_PERM      0x02
+
+/* Class-2 (Initiator Error) */
+#define ISCSI_LOGIN_STATUS_INIT_ERR            0x00
+#define ISCSI_LOGIN_STATUS_AUTH_FAILED         0x01
+#define ISCSI_LOGIN_STATUS_TGT_FORBIDDEN       0x02
+#define ISCSI_LOGIN_STATUS_TGT_NOT_FOUND       0x03
+#define ISCSI_LOGIN_STATUS_TGT_REMOVED         0x04
+#define ISCSI_LOGIN_STATUS_NO_VERSION          0x05
+#define ISCSI_LOGIN_STATUS_ISID_ERROR          0x06
+#define ISCSI_LOGIN_STATUS_MISSING_FIELDS      0x07
+#define ISCSI_LOGIN_STATUS_CONN_ADD_FAILED     0x08
+#define ISCSI_LOGIN_STATUS_NO_SESSION_TYPE     0x09
+#define ISCSI_LOGIN_STATUS_NO_SESSION          0x0a
+#define ISCSI_LOGIN_STATUS_INVALID_REQUEST     0x0b
+
+/* Class-3 (Target Error) */
+#define ISCSI_LOGIN_STATUS_TARGET_ERROR                0x00
+#define ISCSI_LOGIN_STATUS_SVC_UNAVAILABLE     0x01
+#define ISCSI_LOGIN_STATUS_NO_RESOURCES                0x02
+
+/* Logout Header */
+struct iscsi_logout {
+       uint8_t opcode;
+       uint8_t flags;
+       uint8_t rsvd1[2];
+       uint8_t hlength;
+       uint8_t dlength[3];
+       uint8_t rsvd2[8];
+       itt_t    itt;   /* Initiator Task Tag */
+       __be16  cid;
+       uint8_t rsvd3[2];
+       __be32  cmdsn;
+       __be32  exp_statsn;
+       uint8_t rsvd4[16];
+};
+
+/* Logout PDU flags */
+#define ISCSI_FLAG_LOGOUT_REASON_MASK  0x7F
+
+/* logout reason_code values */
+
+#define ISCSI_LOGOUT_REASON_CLOSE_SESSION      0
+#define ISCSI_LOGOUT_REASON_CLOSE_CONNECTION   1
+#define ISCSI_LOGOUT_REASON_RECOVERY           2
+#define ISCSI_LOGOUT_REASON_AEN_REQUEST                3
+
+/* Logout Response Header */
+struct iscsi_logout_rsp {
+       uint8_t opcode;
+       uint8_t flags;
+       uint8_t response;       /* see Logout response values below */
+       uint8_t rsvd2;
+       uint8_t hlength;
+       uint8_t dlength[3];
+       uint8_t rsvd3[8];
+       itt_t    itt;   /* Initiator Task Tag */
+       __be32  rsvd4;
+       __be32  statsn;
+       __be32  exp_cmdsn;
+       __be32  max_cmdsn;
+       __be32  rsvd5;
+       __be16  t2wait;
+       __be16  t2retain;
+       __be32  rsvd6;
+};
+
+/* logout response status values */
+
+#define ISCSI_LOGOUT_SUCCESS                   0
+#define ISCSI_LOGOUT_CID_NOT_FOUND             1
+#define ISCSI_LOGOUT_RECOVERY_UNSUPPORTED      2
+#define ISCSI_LOGOUT_CLEANUP_FAILED            3
+
+/* SNACK Header */
+struct iscsi_snack {
+       uint8_t opcode;
+       uint8_t flags;
+       uint8_t rsvd2[14];
+       itt_t    itt;
+       __be32  begrun;
+       __be32  runlength;
+       __be32  exp_statsn;
+       __be32  rsvd3;
+       __be32  exp_datasn;
+       uint8_t rsvd6[8];
+};
+
+/* SNACK PDU flags */
+#define ISCSI_FLAG_SNACK_TYPE_MASK     0x0F    /* 4 bits */
+
+/* Reject Message Header */
+struct iscsi_reject {
+       uint8_t opcode;
+       uint8_t flags;
+       uint8_t reason;
+       uint8_t rsvd2;
+       uint8_t hlength;
+       uint8_t dlength[3];
+       uint8_t rsvd3[8];
+       __be32  ffffffff;
+       uint8_t rsvd4[4];
+       __be32  statsn;
+       __be32  exp_cmdsn;
+       __be32  max_cmdsn;
+       __be32  datasn;
+       uint8_t rsvd5[8];
+       /* Text - Rejected hdr */
+};
+
+/* Reason for Reject */
+#define ISCSI_REASON_CMD_BEFORE_LOGIN  1
+#define ISCSI_REASON_DATA_DIGEST_ERROR 2
+#define ISCSI_REASON_DATA_SNACK_REJECT 3
+#define ISCSI_REASON_PROTOCOL_ERROR    4
+#define ISCSI_REASON_CMD_NOT_SUPPORTED 5
+#define ISCSI_REASON_IMM_CMD_REJECT            6
+#define ISCSI_REASON_TASK_IN_PROGRESS  7
+#define ISCSI_REASON_INVALID_SNACK             8
+#define ISCSI_REASON_BOOKMARK_INVALID  9
+#define ISCSI_REASON_BOOKMARK_NO_RESOURCES     10
+#define ISCSI_REASON_NEGOTIATION_RESET 11
+
+/* Max. number of Key=Value pairs in a text message */
+#define MAX_KEY_VALUE_PAIRS    8192
+
+/* maximum length for text keys/values */
+#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
+#define ISCSI_MAX_MAX_RECV_SEG_LEN             16777215
+
+#define ISCSI_DEF_FIRST_BURST_LEN              65536
+#define ISCSI_MIN_FIRST_BURST_LEN              512
+#define ISCSI_MAX_FIRST_BURST_LEN              16777215
+
+#define ISCSI_DEF_MAX_BURST_LEN                        262144
+#define ISCSI_MIN_MAX_BURST_LEN                        512
+#define ISCSI_MAX_MAX_BURST_LEN                        16777215
+
+#define ISCSI_DEF_TIME2WAIT                    2
+
+/************************* RFC 3720 End *****************************/
+
+#endif /* ISCSI_PROTO_H */
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/include/list.h b/pkgs/open-iscsi/open-iscsi-2.1.8/include/list.h
new file mode 100644 (file)
index 0000000..94ad99b
--- /dev/null
@@ -0,0 +1,111 @@
+#ifndef __LIST_H__
+#define __LIST_H__
+
+#include <stddef.h>
+/* taken from linux kernel */
+
+#undef offsetof
+#ifdef __compiler_offsetof
+#define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER)
+#else
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+#endif
+
+#define list_container_of(ptr, type, member) ({                \
+        const typeof( ((type *)0)->member ) *__mptr = (ptr);   \
+        (type *)( (char *)__mptr - offsetof(type,member) );})
+
+struct list_head {
+       struct list_head *next, *prev;
+};
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+       struct list_head name = LIST_HEAD_INIT(name)
+
+static inline void INIT_LIST_HEAD(struct list_head *list)
+{
+       list->next = list;
+       list->prev = list;
+}
+
+static inline int list_empty(const struct list_head *head)
+{
+       return head->next == 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)
+
+#define list_for_each_entry(pos, head, member)                         \
+       for (pos = list_entry((head)->next, typeof(*pos), member);      \
+            &pos->member != (head);                                    \
+            pos = list_entry(pos->member.next, typeof(*pos), member))
+
+#define list_for_each_entry_safe(pos, n, head, member)                 \
+       for (pos = list_entry((head)->next, typeof(*pos), member),      \
+               n = list_entry(pos->member.next, typeof(*pos), member); \
+            &pos->member != (head);                                    \
+            pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+static inline void __list_add(struct list_head *new,
+                             struct list_head *prev,
+                             struct list_head *next)
+{
+       next->prev = new;
+       new->next = next;
+       new->prev = prev;
+       prev->next = new;
+}
+
+static inline void list_add(struct list_head *new, struct list_head *head)
+{
+       __list_add(new, head, head->next);
+}
+
+static inline void list_add_tail(struct list_head *new, struct list_head *head)
+{
+       __list_add(new, head->prev, head);
+}
+
+static inline void __list_del(struct list_head * prev, struct list_head * next)
+{
+       next->prev = prev;
+       prev->next = next;
+}
+
+static inline void list_del(struct list_head *entry)
+{
+       __list_del(entry->prev, entry->next);
+       entry->next = entry->prev = NULL;
+}
+
+static inline void list_del_init(struct list_head *entry)
+{
+       __list_del(entry->prev, entry->next);
+       INIT_LIST_HEAD(entry);
+}
+
+/**
+ * list_move_tail - delete from one list and add as another's tail
+ * @list: the entry to move
+ * @head: the head that will follow our entry
+ */
+static inline void list_move_tail(struct list_head *list,
+                                 struct list_head *head)
+{
+       __list_del(list->prev, list->next);
+       list_add_tail(list, head);
+}
+
+#endif
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/include/sysdeps.h b/pkgs/open-iscsi/open-iscsi-2.1.8/include/sysdeps.h
new file mode 100644 (file)
index 0000000..2f18e3b
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * wrapping of libc features and kernel interfaces
+ *
+ * Copyright (C) 2005-2006 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ *     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 version 2 of the License.
+ *
+ *     This program is distributed in the hope that it will be useful, but
+ *     WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *     General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License along
+ *     with this program; if not, write to the Free Software Foundation, Inc.,
+ *     51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ */
+
+#ifndef _SYSDEPS_H_
+#define _SYSDEPS_H_
+
+extern size_t strlcpy(char *dst, const char *src, size_t size);
+extern size_t strlcat(char *dst, const char *src, size_t size);
+
+#endif
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/.gitignore b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/.gitignore
new file mode 100644 (file)
index 0000000..a6c85d6
--- /dev/null
@@ -0,0 +1,24 @@
+# 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/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/AUTHORS b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/AUTHORS
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/ChangeLog b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/ChangeLog
new file mode 100644 (file)
index 0000000..a91b4d5
--- /dev/null
@@ -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/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/INSTALL b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/INSTALL
new file mode 100644 (file)
index 0000000..c9fd2c0
--- /dev/null
@@ -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/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/Makefile.am b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/Makefile.am
new file mode 100644 (file)
index 0000000..ef077a4
--- /dev/null
@@ -0,0 +1,34 @@
+SUBDIRS= src
+
+EXTRA_DIST = build_date
+
+build_date:
+       if [ -n "$$SOURCE_DATE_EPOCH" ] ; then \
+               echo 'char *build_date = "'`LC_ALL=C.UTF-8 date --date=@$$SOURCE_DATE_EPOCH -u`'";' > build_date.c ; \
+       else \
+               echo 'char *build_date = "'`date`'";' > build_date.c ; \
+       fi
+       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: $(DESTDIR)$(mandir)/man8/iscsiuio.8
+
+$(DESTDIR)$(mandir)/man8/iscsiuio.8: docs/iscsiuio.8
+       $(INSTALL) -d $(DESTDIR)$(mandir)/man8/
+       $(INSTALL_DATA) $? $(DESTDIR)$(mandir)/man8/
+
+install-log:
+       $(INSTALL) -d $(DESTDIR)$(logdir)/
+       $(INSTALL_DATA) iscsiuiolog $(DESTDIR)$(logdir)/
+
+install-brcm:
+       $(RM) $(DESTDIR)$(sbindir)/brcm_iscsiuio
+       (cd $(DESTDIR)/$(sbindir); \
+        $(RM) brcm_iscsiuio; \
+        $(LN_S) iscsiuio brcm_iscsiuio)
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/NEWS b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/NEWS
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/README b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/README
new file mode 100644 (file)
index 0000000..983b9d0
--- /dev/null
@@ -0,0 +1,225 @@
+Iscsiuio Userspace Tool
+Version 0.7.8.6
+Jun 27, 2019
+------------------------------------------------------
+
+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
+=======================================
+
+This gets built as part of open-iscsi, using meson, by default. The
+old (deprecated) autoconf build system is still in place, for now, and
+can be used with something like:
+
+       ./configure [--sbindir="/usr/sbin"]
+       make
+       make install
+
+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/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/RELEASE.TXT b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/RELEASE.TXT
new file mode 100644 (file)
index 0000000..28e681b
--- /dev/null
@@ -0,0 +1,2100 @@
+                              Release Notes
+                        QLogic uIP Linux Driver
+                            Version 0.7.8.6
+                               06/27/2019
+
+                          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.8.6 (Jun 27, 2019)
+=======================================================
+    Fixes:
+    -------
+      1. Problem: OS fails to boot after one path is
+                  disconnected from iSCSI MPIO config.
+         Change: In the event of DHCP failure, killing of enable_nic_thread did
+                 not process any iscsid requests leading to error,
+                 iscsistart: Could not broadcast to uIP after 5 tries
+                 and login failure of active path.
+                 Added fix to not kill enable_nic_thread and allow further
+                 processing of iscsid requests and performing login
+                 to next active path.
+         Impact: All
+
+uIP v0.7.8.5 (Nov 20, 2018)
+=======================================================
+    Fixes:
+    -------
+      1. Problem: CQ102578: observing ISCSI initiator IP ping drop
+         Change: 1. Do not flush tx queue on each uio interrupt
+                2. Use UIO BD index instead on buffer index.
+                3. Set buf_size in case of ICMP and ARP packet
+         Impact: QL41xxx adapters
+
+      2. Problem: CQ103034 - Unable to boot iSCSI BFS in IPv6 DHCP config
+         Change: Limit retries of performing dhcpv6 before declaring dhcp failure
+         Impact: All
+
+      3. Problem: CQ102438: I/O fails to resume on multipath LUN during port toggle.
+         Change: lib/cnic, lib/qedi, Release xmit_mutex in error code path and
+                 during clear tx queue.
+         Impact: QL84xx adapters
+
+      4. Problem: Netlink buffer corruption when more than one host
+                 try to xmit packet at the same time
+         Change: Add inter-host mutex while doing xmit
+         Impact: All
+
+uIP v0.7.8.4 (Feb 22, 2018)
+=======================================================
+    Fixes:
+    -------
+      1. Problem: CQ95605: iSCSI BFS in DHCP config intermittently fails to boot
+                  into the OS when source and destination addresses are in
+                  different networks.
+         Change: Allow ARP for non-matching source and destination addresses.
+                 For source and destination IP addresses in different networks,
+                 continue with the ARP retries and further login process
+                 instead of assuming abrupt failure. iSCSI offload adapters
+                 may not rely on netmask information for successful iSCSI
+                 target login.
+         Impact: All
+
+uIP v0.7.8.3 (May 18, 2017)
+=======================================================
+    Fixes:
+    -------
+      1. Problem: CQ93985: iscsiuio seg faults if discovery done to not
+                  reachable target
+         Change: Serialize xmit_mutex lock to prevent iscsiuio seg fault.
+         Impact: All
+
+      2. Problem: CQ91497 - Initiator fails to acquire IPv6 DHCP address
+                  from the DHCP server
+         Change: Initialize the transaction-id within the dhcpv6 packet with
+                 correct byte order, to fix the trans-id mismatch error.
+         Impact: All
+
+      3. Problem: Missing qedi ping transport hook
+         Change: Add qedi ping transport hook
+         Impact: 10/25/40/50GGbE Controller (iSCSI)
+
+uIP v0.7.8.3 (Sept 28, 2016)
+=======================================================
+   Enhancements
+   ------------
+   1. Change: Add support for the new qedi transport
+      Impact: 10/25/40/50GGbE Controller (iSCSI)
+
+uIP v0.7.8.2 (Dec 10, 2013)
+=======================================================
+   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/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/configure.ac b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/configure.ac
new file mode 100644 (file)
index 0000000..c53bd27
--- /dev/null
@@ -0,0 +1,104 @@
+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.6
+
+AC_INIT([iscsiuio], [0.7.8.6], [QLogic-Storage-Upstream@cavium.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])
+## check for systemd support, default on
+AC_ARG_WITH([systemd],
+           AS_HELP_STRING([--without-systemd], [Build without systemd]),
+    [case "${withval}" in
+     yes) with_libsystemd=yes ;;
+     no)  wth_libsystemd=no ;;
+     *)   AC_MSG_ERROR([bad value $withval for --with-systemd]) ;;
+     esac],[with_libsystemd=auto])
+AS_IF([test "$with_libsystemd" != no],[
+    PKG_CHECK_MODULES([LIBSYSTEMD],[libsystemd],[LIBS="${LIBS} $LIBSYSTEMD_LIBS"],[
+        if test "$with_libsystemd" = yes; then
+            AC_MSG_ERROR([could not find libsystemd using pkg-config])
+       else
+            CFLAGS="${CFLAGS} -DNO_SYSTEMD"
+       fi
+    ])
+],[
+    CFLAGS="${CFLAGS} -DNO_SYSTEMD"
+])
+
+AC_CONFIG_COMMANDS([default],[[
+    if [ -n "$SOURCE_DATE_EPOCH" ] ; then
+        echo 'char *build_date = "'`LC_ALL=C.UTF-8 date --date=@$SOURCE_DATE_EPOCH -u`'";' > src/unix/build_date.c
+    else
+        echo 'char *build_date = "'`date`'";' > src/unix/build_date.c
+    fi
+    echo 'extern 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/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/docs/iscsiuio.8 b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/docs/iscsiuio.8
new file mode 100644 (file)
index 0000000..ea2ae02
--- /dev/null
@@ -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 <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|--foreground
+This is to enable foreground mode so that this application doesn't get sent
+into the background.
+.PP
+.TP
+.BI -v|--version
+This is to print the version.
+.PP
+.TP
+.BI -p|--pid <pidfile>
+Use pidfile (default  /run/iscsiuio.pid )
+.PP
+.TP
+.BI -h|--help
+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/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/iscsiuiolog b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/iscsiuiolog
new file mode 100644 (file)
index 0000000..360947c
--- /dev/null
@@ -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/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/.gitignore b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/.gitignore
new file mode 100644 (file)
index 0000000..10301e2
--- /dev/null
@@ -0,0 +1 @@
+*.a
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/Makefile.am b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/Makefile.am
new file mode 100644 (file)
index 0000000..44b0085
--- /dev/null
@@ -0,0 +1 @@
+SUBDIRS = apps uip unix
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/README b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/README
new file mode 100644 (file)
index 0000000..9fca6fb
--- /dev/null
@@ -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/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/apps/Makefile.am b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/apps/Makefile.am
new file mode 100644 (file)
index 0000000..08ed18d
--- /dev/null
@@ -0,0 +1 @@
+SUBDIRS = dhcpc brcm-iscsi
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/apps/README b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/apps/README
new file mode 100644 (file)
index 0000000..0096c4e
--- /dev/null
@@ -0,0 +1,2 @@
+This directory contains a few example applications. They are not all
+heavily tested, however.
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/apps/brcm-iscsi/Makefile.am b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/apps/brcm-iscsi/Makefile.am
new file mode 100644 (file)
index 0000000..00cbd8e
--- /dev/null
@@ -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/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/apps/brcm-iscsi/Makefile.brcm-iscsi b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/apps/brcm-iscsi/Makefile.brcm-iscsi
new file mode 100644 (file)
index 0000000..732275f
--- /dev/null
@@ -0,0 +1 @@
+APP_SOURCES += brcm-iscsi.c
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/apps/brcm-iscsi/brcm_iscsi.c b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/apps/brcm-iscsi/brcm_iscsi.c
new file mode 100644 (file)
index 0000000..4223ca4
--- /dev/null
@@ -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/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/apps/brcm-iscsi/brcm_iscsi.h b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/apps/brcm-iscsi/brcm_iscsi.h
new file mode 100644 (file)
index 0000000..10bfc95
--- /dev/null
@@ -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/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/apps/dhcpc/Makefile.am b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/apps/dhcpc/Makefile.am
new file mode 100644 (file)
index 0000000..1c97993
--- /dev/null
@@ -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/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/apps/dhcpc/Makefile.dhcpc b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/apps/dhcpc/Makefile.dhcpc
new file mode 100644 (file)
index 0000000..f84c84f
--- /dev/null
@@ -0,0 +1 @@
+APP_SOURCES += dhcpc.c timer.c
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/apps/dhcpc/dhcpc.c b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/apps/dhcpc/dhcpc.c
new file mode 100644 (file)
index 0000000..f4a9994
--- /dev/null
@@ -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/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/apps/dhcpc/dhcpc.h b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/apps/dhcpc/dhcpc.h
new file mode 100644 (file)
index 0000000..89cf086
--- /dev/null
@@ -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/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/apps/dhcpc/dhcpv6.c b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/apps/dhcpc/dhcpv6.c
new file mode 100644 (file)
index 0000000..461af0e
--- /dev/null
@@ -0,0 +1,517 @@
+/*
+ * 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 = HOST_TO_NET16(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 !=
+           HOST_TO_NET16(context->dhcpv6_transaction_id)) {
+               LOG_ERR("DHCPv6 transaction-id error, sent %x, received %x",
+                       HOST_TO_NET16(context->dhcpv6_transaction_id),
+                       dhcpv6->dhcpv6_trans_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/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/apps/dhcpc/dhcpv6.h b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/apps/dhcpc/dhcpv6.h
new file mode 100644 (file)
index 0000000..d4ec4b9
--- /dev/null
@@ -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/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip-1.0-changelog.txt b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip-1.0-changelog.txt
new file mode 100644 (file)
index 0000000..800e444
--- /dev/null
@@ -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/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/Makefile.am b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/Makefile.am
new file mode 100644 (file)
index 0000000..16170d7
--- /dev/null
@@ -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/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/Makefile.include b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/Makefile.include
new file mode 100644 (file)
index 0000000..aa3ac63
--- /dev/null
@@ -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/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/clock.h b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/clock.h
new file mode 100644 (file)
index 0000000..d79326b
--- /dev/null
@@ -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/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/debug.h b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/debug.h
new file mode 100644 (file)
index 0000000..a58fa7a
--- /dev/null
@@ -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/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/icmpv6.h b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/icmpv6.h
new file mode 100644 (file)
index 0000000..cbf9aa8
--- /dev/null
@@ -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/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/ipv6.c b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/ipv6.c
new file mode 100644 (file)
index 0000000..11cb4e9
--- /dev/null
@@ -0,0 +1,1306 @@
+/*
+ * Copyright (c) 2011, Broadcom Corporation
+ * Copyright (c) 2014, QLogic Corporation
+ *
+ * Written by:  Eddie Wai  (eddie.wai@broadcom.com)
+ *              Based on Kevin Tran's iSCSI boot code
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed by Adam Dunkels.
+ * 4. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ipv6.c - This file contains simplifed IPv6 processing code.
+ *
+ */
+#include <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"
+#include "ping.h"
+
+static inline int best_match_bufcmp(u8_t *a, u8_t *b, int len)
+{
+       int i;
+
+       for (i = 0; i < len; i++) {
+               if (a[i] != b[i])
+                       break;
+       }
+       return i;
+}
+
+/* Local function prototypes */
+static int ipv6_is_it_our_address(struct ipv6_context *context,
+                                 struct ipv6_addr *ip_addr);
+static void ipv6_insert_protocol_chksum(struct ipv6_hdr *ipv6);
+static void ipv6_update_arp_table(struct ipv6_context *context,
+                                 struct ipv6_addr *ip_addr,
+                                 struct mac_address *mac_addr);
+static void ipv6_icmp_init_link_option(struct ipv6_context *context,
+                                      struct icmpv6_opt_link_addr *link_opt,
+                                      u8_t type);
+static void ipv6_icmp_rx(struct ipv6_context *context);
+static void ipv6_icmp_handle_nd_adv(struct ipv6_context *context);
+static void ipv6_icmp_handle_nd_sol(struct ipv6_context *context);
+static void ipv6_icmp_handle_echo_request(struct ipv6_context *context);
+static void ipv6_icmp_handle_router_adv(struct ipv6_context *context);
+static void ipv6_icmp_process_prefix(struct ipv6_context *context,
+                                    struct icmpv6_opt_prefix *icmp_prefix);
+static void ipv6_udp_rx(struct ipv6_context *context);
+
+int iscsiL2Send(struct ipv6_context *context, int pkt_len)
+{
+       LOG_DEBUG("IPv6: iscsiL2Send");
+       uip_send(context->ustack,
+                (void *)context->ustack->data_link_layer, pkt_len);
+
+       return pkt_len;
+}
+
+int iscsiL2AddMcAddr(struct ipv6_context *context,
+                    struct mac_address *new_mc_addr)
+{
+       int i;
+       struct mac_address *mc_addr;
+       const struct mac_address all_zeroes_mc = { { { 0, 0, 0, 0, 0, 0 } } };
+
+       mc_addr = context->mc_addr;
+       for (i = 0; i < MAX_MCADDR_TABLE; i++, mc_addr++)
+               if (!memcmp((char *)mc_addr,
+                           (char *)new_mc_addr, sizeof(struct mac_address)))
+                       return TRUE;    /* Already in the mc table */
+
+       mc_addr = context->mc_addr;
+       for (i = 0; i < MAX_MCADDR_TABLE; i++, mc_addr++) {
+               if (!memcmp((char *)mc_addr,
+                   (char *)&all_zeroes_mc, sizeof(struct mac_address))) {
+                       memcpy((char *)mc_addr,
+                              (char *)new_mc_addr, sizeof(struct mac_address));
+                       LOG_DEBUG("IPv6: mc_addr added "
+                                 "%02x:%02x:%02x:%02x:%02x:%02x",
+                                 *(u8_t *)new_mc_addr,
+                                 *((u8_t *)new_mc_addr + 1),
+                                 *((u8_t *)new_mc_addr + 2),
+                                 *((u8_t *)new_mc_addr + 3),
+                                 *((u8_t *)new_mc_addr + 4),
+                                 *((u8_t *)new_mc_addr + 5));
+                       return TRUE;
+               }
+       }
+       return FALSE;
+}
+
+int iscsiL2IsOurMcAddr(struct ipv6_context *context,
+                      struct mac_address *dest_mac)
+{
+       int i;
+       struct mac_address *mc_addr;
+
+       mc_addr = context->mc_addr;
+       for (i = 0; i < MAX_MCADDR_TABLE; i++, mc_addr++)
+               if (!memcmp((char *)mc_addr,
+                           (char *)dest_mac->addr, sizeof(struct mac_address)))
+                       return TRUE;
+       return FALSE;
+}
+
+void ipv6_init(struct ndpc_state *ndp, int cfg)
+{
+       int i;
+       struct ipv6_context *context = (struct ipv6_context *)ndp->ipv6_context;
+       struct mac_address *mac_addr = (struct mac_address *)ndp->mac_addr;
+       struct ipv6_arp_entry *ipv6_arp_table;
+       struct ipv6_prefix_entry *ipv6_prefix_table;
+       struct mac_address mc_addr;
+
+       if (context == NULL) {
+               LOG_ERR("IPV6: INIT ipv6_context is NULL");
+               return;
+       }
+
+       memset((char *)context, 0, sizeof(struct ipv6_context));
+
+       /* Associate the nic_iface's ustack to this ipv6_context */
+       context->ustack = ndp->ustack;
+
+       ipv6_arp_table = &context->ipv6_arp_table[0];
+       ipv6_prefix_table = &context->ipv6_prefix_table[0];
+
+       memset((char *)ipv6_arp_table, 0, sizeof(*ipv6_arp_table));
+       memset((char *)ipv6_prefix_table, 0, sizeof(*ipv6_prefix_table));
+       memcpy((char *)&context->mac_addr,
+              (char *)mac_addr, sizeof(struct mac_address));
+       /*
+        * Per RFC 2373.
+        * There are two types of local-use unicast addresses defined.  These
+        * are Link-Local and Site-Local.  The Link-Local is for use on a single
+        * link and the Site-Local is for use in a single site.  Link-Local
+        * addresses have the following format:
+        *
+        * |   10     |
+        * |  bits    |        54 bits          |          64 bits           |
+        * +----------+-------------------------+----------------------------+
+        * |1111111010|           0             |       interface ID         |
+        * +----------+-------------------------+----------------------------+
+        */
+       if (context->ustack->linklocal_autocfg != IPV6_LL_AUTOCFG_OFF) {
+               context->link_local_addr.addr8[0] = 0xfe;
+               context->link_local_addr.addr8[1] = 0x80;
+               /* Bit 1 is 1 to indicate universal scope. */
+               context->link_local_addr.addr8[8] = mac_addr->addr[0] | 0x2;
+               context->link_local_addr.addr8[9] = mac_addr->addr[1];
+               context->link_local_addr.addr8[10] = mac_addr->addr[2];
+               context->link_local_addr.addr8[11] = 0xff;
+               context->link_local_addr.addr8[12] = 0xfe;
+               context->link_local_addr.addr8[13] = mac_addr->addr[3];
+               context->link_local_addr.addr8[14] = mac_addr->addr[4];
+               context->link_local_addr.addr8[15] = mac_addr->addr[5];
+
+               context->link_local_multi.addr8[0] = 0xff;
+               context->link_local_multi.addr8[1] = 0x02;
+               context->link_local_multi.addr8[11] = 0x01;
+               context->link_local_multi.addr8[12] = 0xff;
+               context->link_local_multi.addr8[13] |=
+                   context->link_local_addr.addr8[13];
+               context->link_local_multi.addr16[7] =
+                   context->link_local_addr.addr16[7];
+
+               /* Default Prefix length is 64 */
+               /* Add Link local address to the head of the ipv6 address
+                  list */
+               ipv6_add_prefix_entry(context,
+                                     &context->link_local_addr, 64);
+       }
+       /*
+        * Convert Multicast IP address to Multicast MAC adress per
+        * RFC 2464: Transmission of IPv6 Packets over Ethernet Networks
+        *
+        * An IPv6 packet with a multicast destination address DST, consisting
+        * of the sixteen octets DST[1] through DST[16], is transmitted to the
+        * Ethernet multicast address whose first two octets are the value 3333
+        * hexadecimal and whose last four octets are the last four octets of
+        * DST.
+        *
+        *          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+        *          |0 0 1 1 0 0 1 1|0 0 1 1 0 0 1 1|
+        *          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+        *          |   DST[13]     |   DST[14]     |
+        *          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+        *          |   DST[15]     |   DST[16]     |
+        *          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+        *
+        * IPv6 requires the following Multicast IP addresses setup per node.
+        */
+       for (i = 0; i < 3; i++) {
+               mc_addr.addr[0] = 0x33;
+               mc_addr.addr[1] = 0x33;
+               mc_addr.addr[2] = 0x0;
+               mc_addr.addr[3] = 0x0;
+               mc_addr.addr[4] = 0x0;
+
+               switch (i) {
+               case 0:
+                       /* All Nodes Multicast IPv6 address : ff02::1 */
+                       mc_addr.addr[5] = 0x1;
+                       break;
+
+               case 1:
+                       /* All Host Multicast IPv6 address : ff02::3 */
+                       mc_addr.addr[5] = 0x3;
+                       break;
+
+               case 2:
+                       /* Solicited Node Multicast Address: ff02::01:ffxx:yyzz
+                        */
+                       mc_addr.addr[2] = 0xff;
+                       mc_addr.addr[3] = mac_addr->addr[3];
+                       mc_addr.addr[4] = mac_addr->addr[4];
+                       mc_addr.addr[5] = mac_addr->addr[5];
+                       break;
+
+               default:
+                       break;
+               }
+               iscsiL2AddMcAddr(context, &mc_addr);
+       }
+
+       /* Default HOP number */
+       context->hop_limit = IPV6_HOP_LIMIT;
+}
+
+int ipv6_add_prefix_entry(struct ipv6_context *context,
+                         struct ipv6_addr *ip_addr, u8_t prefix_len)
+{
+       int i;
+       struct ipv6_prefix_entry *prefix_entry;
+       struct ipv6_prefix_entry *ipv6_prefix_table =
+                                 context->ipv6_prefix_table;
+       char addr_str[INET6_ADDRSTRLEN];
+
+       /* Check if there is an valid entry already. */
+       for (i = 0; i < IPV6_NUM_OF_ADDRESS_ENTRY; i++) {
+               prefix_entry = &ipv6_prefix_table[i];
+
+               if (prefix_entry->prefix_len != 0) {
+                       if (memcmp((char *)&prefix_entry->ip_addr,
+                                  (char *)ip_addr,
+                                  sizeof(struct ipv6_addr)) == 0) {
+                               /* We already initialize on this interface.
+                                  There is nothing to do */
+                               return 0;
+                       }
+               }
+       }
+
+       /* Find an unused entry */
+       for (i = 0; i < IPV6_NUM_OF_ADDRESS_ENTRY; i++) {
+               prefix_entry = &ipv6_prefix_table[i];
+
+               if (prefix_entry->prefix_len == 0)
+                       break;
+       }
+
+       if (prefix_entry->prefix_len != 0)
+               return -1;
+
+       prefix_entry->prefix_len = prefix_len / 8;
+
+       memcpy((char *)&prefix_entry->ip_addr,
+              (char *)ip_addr, sizeof(struct ipv6_addr));
+
+       inet_ntop(AF_INET6, &prefix_entry->ip_addr.addr8, addr_str,
+                 sizeof(addr_str));
+
+       LOG_DEBUG("IPv6: add prefix IP addr %s", addr_str);
+
+       /* Put it on the list on head of the list. */
+       if (context->addr_list != NULL)
+               prefix_entry->next = context->addr_list;
+       else
+               prefix_entry->next = NULL;
+
+       context->addr_list = prefix_entry;
+
+       return 0;
+}
+
+void ipv6_rx_packet(struct ipv6_context *context, u16_t len)
+{
+       struct ipv6_hdr *ipv6;
+       u16_t protocol;
+
+       if (!context->ustack) {
+               LOG_WARN("ipv6 rx pkt ipv6_context = %p ustack = %p", context,
+                        context->ustack);
+               return;
+       }
+       ipv6 = (struct ipv6_hdr *)context->ustack->network_layer;
+       /* Make sure it's an IPv6 packet */
+       if ((ipv6->ipv6_version_fc & 0xf0) != IPV6_VERSION) {
+               /* It's not an IPv6 packet. Drop it. */
+               LOG_WARN("IPv6 version 0x%x not IPv6", ipv6->ipv6_version_fc);
+               return;
+       }
+       protocol = ipv6_process_rx(ipv6);
+
+       switch (protocol) {
+       case IPPROTO_ICMPV6:
+               ipv6_icmp_rx(context);
+               break;
+
+       case IPPROTO_UDP:
+               /* Indicate to UDP processing code */
+               ipv6_udp_rx(context);
+               break;
+
+       default:
+               break;
+       }
+}
+
+void ipv6_mc_init_dest_mac(struct eth_hdr *eth, struct ipv6_hdr *ipv6)
+{
+       int i;
+       /*
+        * Initialize address mapping of IPV6 Multicast to multicast MAC
+        * address per RFC 2464.
+        *
+        * An IPv6 packet with a multicast destination address DST, consisting
+        * of the sixteen octets DST[1] through DST[16], is transmitted to the
+        * Ethernet multicast address whose first two octets are the value 3333
+        * hexadecimal and whose last four octets are the last four octets of
+        * DST.
+        *
+        *              +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+        *              |0 0 1 1 0 0 1 1|0 0 1 1 0 0 1 1|
+        *              +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+        *              |   DST[13]     |   DST[14]     |
+        *              +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+        *              |   DST[15]     |   DST[16]     |
+        *              +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+        */
+       eth->dest_mac.addr[0] = 0x33;
+       eth->dest_mac.addr[1] = 0x33;
+       for (i = 0; i < 4; i++)
+               eth->dest_mac.addr[2 + i] = ipv6->ipv6_dst.addr8[12 + i];
+}
+
+int ipv6_autoconfig(struct ipv6_context *context)
+{
+       return ipv6_discover_address(context);
+}
+
+int ipv6_discover_address(struct ipv6_context *context)
+{
+       struct eth_hdr *eth =
+                       (struct eth_hdr *)context->ustack->data_link_layer;
+       struct ipv6_hdr *ipv6 =
+                       (struct ipv6_hdr *)context->ustack->network_layer;
+       struct icmpv6_hdr *icmp = (struct icmpv6_hdr *)((u8_t *)ipv6 +
+                                               sizeof(struct ipv6_hdr));
+       int rc = 0;
+
+       /* Retrieve tx buffer */
+       if (eth == NULL || ipv6 == NULL)
+               return -EAGAIN;
+
+       /* Setup IPv6 All Routers Multicast address : ff02::2 */
+       memset((char *)&ipv6->ipv6_dst, 0, sizeof(struct ipv6_addr));
+       ipv6->ipv6_dst.addr8[0] = 0xff;
+       ipv6->ipv6_dst.addr8[1] = 0x02;
+       ipv6->ipv6_dst.addr8[15] = 0x02;
+       ipv6->ipv6_hop_limit = 255;
+
+       /* Initialize MAC header based on destination MAC address */
+       ipv6_mc_init_dest_mac(eth, ipv6);
+       ipv6->ipv6_nxt_hdr = IPPROTO_ICMPV6;
+
+       icmp->icmpv6_type = ICMPV6_RTR_SOL;
+       icmp->icmpv6_code = 0;
+       icmp->icmpv6_data = 0;
+       icmp->icmpv6_cksum = 0;
+       ipv6_icmp_init_link_option(context,
+                                  (struct icmpv6_opt_link_addr *)((u8_t *)icmp
+                                       + sizeof(struct icmpv6_hdr)),
+                                       IPV6_ICMP_OPTION_SRC_ADDR);
+       ipv6->ipv6_plen = HOST_TO_NET16((sizeof(struct icmpv6_hdr) +
+                                        sizeof(struct icmpv6_opt_link_addr)));
+       memcpy((char *)&ipv6->ipv6_src,
+              (char *)&context->link_local_addr,
+              sizeof(struct ipv6_addr));
+
+       icmp->icmpv6_cksum = 0;
+       LOG_DEBUG("IPv6: Send rtr sol");
+       ipv6_send(context, (u8_t *) icmp - (u8_t *) eth +
+                 sizeof(struct icmpv6_hdr) +
+                 sizeof(struct icmpv6_opt_link_addr));
+       return rc;
+}
+
+u16_t ipv6_process_rx(struct ipv6_hdr *ipv6)
+{
+       return ipv6->ipv6_nxt_hdr;
+}
+
+int ipv6_send(struct ipv6_context *context, u16_t packet_len)
+{
+       struct eth_hdr *eth =
+                       (struct eth_hdr *)context->ustack->data_link_layer;
+       struct ipv6_hdr *ipv6 =
+                       (struct ipv6_hdr *)context->ustack->network_layer;
+
+       ipv6_setup_hdrs(context, eth, ipv6, packet_len);
+
+       return iscsiL2Send(context, packet_len);
+}
+
+void ipv6_send_udp_packet(struct ipv6_context *context, u16_t packet_len)
+{
+       struct eth_hdr *eth =
+                       (struct eth_hdr *)context->ustack->data_link_layer;
+       struct ipv6_hdr *ipv6 =
+                       (struct ipv6_hdr *)context->ustack->network_layer;
+       struct udp_hdr *udp = (struct udp_hdr *)((u8_t *)ipv6 +
+                                                sizeof(struct ipv6_hdr));
+
+       ipv6->ipv6_nxt_hdr = IPPROTO_UDP;
+       ipv6->ipv6_plen =
+           HOST_TO_NET16(packet_len - ((u8_t *)udp - (u8_t *)eth));
+
+       udp->chksum = 0;
+
+       /*
+        * We only use UDP packet for DHCPv6.  The source address is always
+        * link-local address.
+        */
+       ipv6->ipv6_src.addr[0] = 0;
+
+       /* Hop limit is always 1 for DHCPv6 packet. */
+       ipv6->ipv6_hop_limit = 1;
+
+       ipv6_send(context, packet_len);
+}
+
+void ipv6_setup_hdrs(struct ipv6_context *context, struct eth_hdr *eth,
+                    struct ipv6_hdr *ipv6, u16_t packet_len)
+{
+       struct ipv6_addr *our_address;
+
+       /* VLAN will be taken cared of in the nic layer */
+       eth->len_type = HOST_TO_NET16(LAYER2_TYPE_IPV6);
+       memcpy((char *)&eth->src_mac,
+              (char *)&context->mac_addr, sizeof(struct mac_address));
+
+       /* Put the traffic class into the packet. */
+       memset(&ipv6->ipv6_version_fc, 0, sizeof(u32_t));
+       ipv6->ipv6_version_fc = IPV6_VERSION;
+       if (ipv6->ipv6_hop_limit == 0)
+               ipv6->ipv6_hop_limit = context->hop_limit;
+
+       if (ipv6->ipv6_src.addr[0] == 0) {
+               /* Need to initialize source IP address. */
+               our_address = ipv6_our_address(context);
+               if (our_address != NULL) {
+                       /* Assume that caller has filled in the destination
+                          IP address */
+                       memcpy((char *)&ipv6->ipv6_src,
+                              (char *)our_address, sizeof(struct ipv6_addr));
+               }
+       }
+
+       ipv6_insert_protocol_chksum(ipv6);
+}
+
+static void ipv6_insert_protocol_chksum(struct ipv6_hdr *ipv6)
+{
+       u32_t sum;
+       u16_t *ptr;
+       u16_t *protocol_data_ptr;
+       int i;
+       u16_t protocol_data_len;
+       u16_t checksum;
+
+       /*
+        * This routine assumes that there is no extension header. This driver
+        * doesn't user extension header to keep driver small and simple.
+        *
+        * Pseudo check consists of the following:
+        * SRC IP, DST IP, Protocol Data Length, and Next Header.
+        */
+       sum = 0;
+       ptr = (u16_t *)&ipv6->ipv6_src.addr16[0];
+
+       for (i = 0; i < sizeof(struct ipv6_addr); i++) {
+               sum += HOST_TO_NET16(*ptr);
+               ptr++;
+       }
+
+       /* Keep track where the layer header is */
+       protocol_data_ptr = ptr;
+
+       protocol_data_len = HOST_TO_NET16(ipv6->ipv6_plen);
+       sum += protocol_data_len;
+       sum += ipv6->ipv6_nxt_hdr;
+       /* Sum now contains sum of IPv6 pseudo header.  Let's add the data
+          streams. */
+       if (protocol_data_len & 1) {
+               /* Length of data is odd */
+               *((u8_t *) ptr + protocol_data_len) = 0;
+               protocol_data_len++;
+       }
+
+       for (i = 0; i < protocol_data_len / 2; i++) {
+               sum += HOST_TO_NET16(*ptr);
+               ptr++;
+       }
+
+       sum = (sum >> 16) + (sum & 0xffff);
+       sum += (sum >> 16);
+       sum &= 0xffff;
+       checksum = (u16_t) (~sum);
+       checksum = HOST_TO_NET16(checksum);
+
+       switch (ipv6->ipv6_nxt_hdr) {
+       case IPPROTO_ICMPV6:
+               /* Insert correct ICMPv6 checksum */
+               ((struct icmpv6_hdr *)(protocol_data_ptr))->icmpv6_cksum =
+                       checksum;
+               break;
+       case IPPROTO_UDP:
+               /* Insert correct UDP checksum */
+               ((struct udp_hdr *)protocol_data_ptr)->chksum = checksum;
+               break;
+       default:
+               break;
+       }
+}
+
+int ipv6_is_it_our_link_local_address(struct ipv6_context *context,
+                                     struct ipv6_addr *ip_addr)
+{
+       u8_t *test_addr = (u8_t *) ip_addr->addr8;
+       u8_t test_remainder;
+
+       if (test_addr[0] != context->link_local_addr.addr8[0])
+               return FALSE;
+
+       test_remainder = (test_addr[1] & 0xC0) >> 6;
+       if (test_remainder != 2)
+               return FALSE;
+
+       return TRUE;
+}
+
+static int ipv6_is_it_our_address(struct ipv6_context *context,
+                                 struct ipv6_addr *ipv6_addr)
+{
+       struct ipv6_prefix_entry *ipv6_prefix;
+
+       for (ipv6_prefix = context->addr_list; ipv6_prefix != NULL;
+            ipv6_prefix = ipv6_prefix->next) {
+               if (IPV6_ARE_ADDR_EQUAL(&ipv6_prefix->ip_addr, ipv6_addr))
+                       return TRUE;
+       }
+
+       return FALSE;
+}
+
+struct ipv6_addr *ipv6_our_address(struct ipv6_context *context)
+{
+       return &context->link_local_addr;
+}
+
+int ipv6_ip_in_arp_table(struct ipv6_context *context,
+                        struct ipv6_addr *ip_addr,
+                        struct mac_address *mac_addr)
+{
+       struct ipv6_arp_entry *arp_entry;
+       int i;
+
+       for (i = 0; i < UIP_ARPTAB_SIZE; i++) {
+               arp_entry = &context->ipv6_arp_table[i];
+
+               if (IPV6_ARE_ADDR_EQUAL(&arp_entry->ip_addr, ip_addr)) {
+                       memcpy((char *)mac_addr, &arp_entry->mac_addr,
+                              sizeof(struct mac_address));
+                       return 1;
+               }
+       }
+       return 0;
+}
+
+struct ipv6_addr *ipv6_find_longest_match(struct ipv6_context *context,
+                                  struct ipv6_addr *ip_addr)
+{
+       struct ipv6_prefix_entry *ipv6_prefix;
+       struct ipv6_prefix_entry *best_match = NULL;
+       int longest_len = -1;
+       int len;
+
+       for (ipv6_prefix = context->addr_list; ipv6_prefix != NULL;
+            ipv6_prefix = ipv6_prefix->next) {
+               if (!IPV6_IS_ADDR_LINKLOCAL(&ipv6_prefix->ip_addr)) {
+                       len = best_match_bufcmp((u8_t *)&ipv6_prefix->ip_addr,
+                                               (u8_t *)ip_addr,
+                                               sizeof(struct ipv6_addr));
+                       if (len > longest_len) {
+                               best_match = ipv6_prefix;
+                               longest_len = len;
+                       }
+               }
+       }
+
+       if (best_match)
+               return &best_match->ip_addr;
+
+       return NULL;
+}
+
+void ipv6_arp_out(struct ipv6_context *context, int *uip_len)
+{
+       /* Empty routine */
+}
+
+
+static void ipv6_update_arp_table(struct ipv6_context *context,
+                                 struct ipv6_addr *ip_addr,
+                                 struct mac_address *mac_addr)
+{
+       struct ipv6_arp_entry *arp_entry;
+       int i;
+       struct ipv6_arp_entry *ipv6_arp_table = context->ipv6_arp_table;
+
+       LOG_DEBUG("IPv6: Neighbor update");
+       /*
+        * Walk through the ARP mapping table and try to find an entry to
+        * update. If none is found, the IP -> MAC address mapping is
+        * inserted in the ARP table.
+        */
+       for (i = 0; i < UIP_ARPTAB_SIZE; i++) {
+               arp_entry = &ipv6_arp_table[i];
+
+               /* Only check those entries that are actually in use. */
+               if (arp_entry->ip_addr.addr[0] != 0) {
+                       /*
+                        * Check if the source IP address of the incoming
+                        * packet matches the IP address in this ARP table
+                        * entry.
+                        */
+                       if (IPV6_ARE_ADDR_EQUAL(&arp_entry->ip_addr, ip_addr)) {
+                               /* An old entry found, update this and return */
+                               memcpy((char *)&arp_entry->mac_addr,
+                                      (char *)mac_addr,
+                                      sizeof(struct mac_address));
+                               arp_entry->time = context->arptime;
+                               return;
+                       }
+               }
+       }
+
+       /*
+        * If we get here, no existing ARP table entry was found, so we
+        * create one.
+        *
+        * First, we try to find an unused entry in the ARP table.
+        */
+       for (i = 0; i < UIP_ARPTAB_SIZE; i++) {
+               arp_entry = &ipv6_arp_table[i];
+
+               if (arp_entry->ip_addr.addr[0] == 0)
+                       break;
+       }
+
+       if (i == UIP_ARPTAB_SIZE)
+               return;
+
+       /* Index j is the entry that is least used */
+       arp_entry = &ipv6_arp_table[i];
+       memcpy((char *)&arp_entry->ip_addr, (char *)ip_addr,
+              sizeof(struct ipv6_addr));
+       memcpy((char *)&arp_entry->mac_addr,
+              (char *)mac_addr, sizeof(struct mac_address));
+
+       arp_entry->time = context->arptime;
+}
+
+/* DestIP is intact */
+int ipv6_send_nd_solicited_packet(struct ipv6_context *context,
+                                 struct eth_hdr *eth, struct ipv6_hdr *ipv6)
+{
+       struct icmpv6_hdr *icmp;
+       int pkt_len = 0;
+       struct ipv6_addr *longest_match_addr;
+       char addr_str[INET6_ADDRSTRLEN];
+
+       ipv6->ipv6_nxt_hdr = IPPROTO_ICMPV6;
+
+       /* Depending on the IPv6 address of the target, we'll need to determine
+          whether we use the assigned IPv6 address/RA or the link local address
+       */
+       /* Use Link-local as source address */
+       if (ipv6_is_it_our_link_local_address(context, &ipv6->ipv6_dst) ==
+           TRUE) {
+               LOG_DEBUG("IPv6: NS using link local");
+               memcpy((char *)&ipv6->ipv6_src,
+                      (char *)&context->link_local_addr,
+                      sizeof(struct ipv6_addr));
+       } else {
+               longest_match_addr =
+                   ipv6_find_longest_match(context, &ipv6->ipv6_dst);
+               if (longest_match_addr) {
+                       LOG_DEBUG("IPv6: NS using longest match addr");
+                       memcpy((char *)&ipv6->ipv6_src,
+                              (char *)longest_match_addr,
+                              sizeof(struct ipv6_addr));
+               } else {
+                       LOG_DEBUG("IPv6: NS using link local instead");
+                       memcpy((char *)&ipv6->ipv6_src,
+                              (char *)&context->link_local_addr,
+                              sizeof(struct ipv6_addr));
+               }
+       }
+       icmp = (struct icmpv6_hdr *)((u8_t *)ipv6 + sizeof(struct ipv6_hdr));
+
+       inet_ntop(AF_INET6, &ipv6->ipv6_src.addr8, addr_str, sizeof(addr_str));
+       LOG_DEBUG("IPv6: NS host IP addr: %s", addr_str);
+       /*
+        * Destination IP address to be resolved is after the ICMPv6
+        * header.
+        */
+       memcpy((char *)((u8_t *)icmp + sizeof(struct icmpv6_hdr)),
+              (char *)&ipv6->ipv6_dst, sizeof(struct ipv6_addr));
+
+       /*
+        * Destination IP in the IPv6 header contains solicited-node multicast
+        * address corresponding to the target address.
+        *
+        * ff02::01:ffxx:yyzz. Where xyz are least
+        * significant of 24-bit MAC address.
+        */
+       memset((char *)&ipv6->ipv6_dst, 0, sizeof(struct ipv6_addr) - 3);
+       ipv6->ipv6_dst.addr8[0] = 0xff;
+       ipv6->ipv6_dst.addr8[1] = 0x02;
+       ipv6->ipv6_dst.addr8[11] = 0x01;
+       ipv6->ipv6_dst.addr8[12] = 0xff;
+       ipv6_mc_init_dest_mac(eth, ipv6);
+       ipv6->ipv6_hop_limit = 255;
+
+       icmp->icmpv6_type = ICMPV6_NEIGH_SOL;
+       icmp->icmpv6_code = 0;
+       icmp->icmpv6_data = 0;
+       icmp->icmpv6_cksum = 0;
+       ipv6_icmp_init_link_option(context,
+                                  (struct icmpv6_opt_link_addr *)((u8_t *)icmp
+                                               + sizeof(struct icmpv6_hdr)
+                                               + sizeof(struct ipv6_addr)),
+                                               IPV6_ICMP_OPTION_SRC_ADDR);
+       ipv6->ipv6_plen = HOST_TO_NET16((sizeof(struct icmpv6_hdr) +
+                         sizeof(struct icmpv6_opt_link_addr) +
+                         sizeof(struct ipv6_addr)));
+       /* Total packet size */
+       pkt_len = (u8_t *) icmp - (u8_t *) eth +
+           sizeof(struct icmpv6_hdr) +
+           sizeof(struct icmpv6_opt_link_addr) + sizeof(struct ipv6_addr);
+       ipv6_setup_hdrs(context, eth, ipv6, pkt_len);
+       return pkt_len;
+}
+
+static void ipv6_icmp_init_link_option(struct ipv6_context *context,
+                                      struct icmpv6_opt_link_addr *link_opt,
+                                      u8_t type)
+{
+       link_opt->hdr.type = type;
+       link_opt->hdr.len = sizeof(struct icmpv6_opt_link_addr) / 8;
+       memcpy((char *)&link_opt->link_addr,
+              (char *)&context->mac_addr, sizeof(struct mac_address));
+}
+
+static void ipv6_icmp_rx(struct ipv6_context *context)
+{
+       struct ipv6_hdr *ipv6 =
+                       (struct ipv6_hdr *)context->ustack->network_layer;
+       struct icmpv6_hdr *icmp = (struct icmpv6_hdr *)((u8_t *)ipv6 +
+                                               sizeof(struct ipv6_hdr));
+       uip_icmp_echo_hdr_t *icmp_echo_hdr =
+                               (uip_icmp_echo_hdr_t *)((u8_t *)ipv6 +
+                                               sizeof(struct ipv6_hdr));
+
+       switch (icmp->icmpv6_type) {
+       case ICMPV6_RTR_ADV:
+               ipv6_icmp_handle_router_adv(context);
+               break;
+
+       case ICMPV6_NEIGH_SOL:
+               ipv6_icmp_handle_nd_sol(context);
+               break;
+
+       case ICMPV6_NEIGH_ADV:
+               ipv6_icmp_handle_nd_adv(context);
+               break;
+
+       case ICMPV6_ECHO_REQUEST:
+               /* Response with ICMP reply */
+               ipv6_icmp_handle_echo_request(context);
+               break;
+
+       case ICMPV6_ECHO_REPLY:
+               /* Handle ICMP reply */
+               process_icmp_packet(icmp_echo_hdr, context->ustack);
+               break;
+
+       default:
+               break;
+       }
+}
+
+static void ipv6_icmp_handle_router_adv(struct ipv6_context *context)
+{
+       struct ipv6_hdr *ipv6 =
+                       (struct ipv6_hdr *)context->ustack->network_layer;
+       struct icmpv6_router_advert *icmp =
+       (struct icmpv6_router_advert *)((u8_t *)ipv6 + sizeof(struct ipv6_hdr));
+       struct icmpv6_opt_hdr *icmp_opt;
+       u16_t opt_len;
+       u16_t len;
+       char addr_str[INET6_ADDRSTRLEN];
+
+       if (context->flags & IPV6_FLAGS_ROUTER_ADV_RECEIVED)
+               return;
+
+       opt_len = HOST_TO_NET16(ipv6->ipv6_plen) -
+                 sizeof(struct icmpv6_router_advert);
+
+       icmp_opt = (struct icmpv6_opt_hdr *)((u8_t *)icmp +
+                                     sizeof(struct icmpv6_router_advert));
+       len = 0;
+       while (len < opt_len) {
+               icmp_opt = (struct icmpv6_opt_hdr *)((u8_t *)icmp +
+                                       sizeof(struct icmpv6_router_advert) +
+                                       len);
+
+               switch (icmp_opt->type) {
+               case IPV6_ICMP_OPTION_PREFIX:
+                       ipv6_icmp_process_prefix(context,
+                                       (struct icmpv6_opt_prefix *)icmp_opt);
+                       context->flags |= IPV6_FLAGS_ROUTER_ADV_RECEIVED;
+                       break;
+
+               default:
+                       break;
+               }
+
+               len += icmp_opt->len * 8;
+       }
+
+       if (context->flags & IPV6_FLAGS_ROUTER_ADV_RECEIVED) {
+               LOG_DEBUG("IPv6: RTR ADV nd_ra_flags = 0x%x",
+                         icmp->nd_ra_flags_reserved);
+               if (icmp->nd_ra_curhoplimit > 0)
+                       context->hop_limit = icmp->nd_ra_curhoplimit;
+
+               if (icmp->nd_ra_flags_reserved & IPV6_RA_MANAGED_FLAG)
+                       context->flags |= IPV6_FLAGS_MANAGED_ADDR_CONFIG;
+
+               if (icmp->nd_ra_flags_reserved & IPV6_RA_CONFIG_FLAG)
+                       context->flags |= IPV6_FLAGS_OTHER_STATEFUL_CONFIG;
+
+               if (icmp->nd_ra_router_lifetime != 0) {
+                       /* There is a default router. */
+                       if (context->ustack->router_autocfg !=
+                           IPV6_RTR_AUTOCFG_OFF)
+                               memcpy(
+                                  (char *)&context->default_router,
+                                      (char *)&ipv6->ipv6_src,
+                                      sizeof(struct ipv6_addr));
+                       inet_ntop(AF_INET6, &context->default_router,
+                                 addr_str, sizeof(addr_str));
+                       LOG_DEBUG("IPv6: Got default router IP addr: %s",
+                                 addr_str);
+               }
+       }
+}
+
+static void ipv6_icmp_process_prefix(struct ipv6_context *context,
+                                    struct icmpv6_opt_prefix *icmp_prefix)
+{
+       struct ipv6_addr addr;
+       char addr_str[INET6_ADDRSTRLEN];
+
+       /* we only process on-link address info */
+       if (!(icmp_prefix->flags & ICMPV6_OPT_PREFIX_FLAG_ON_LINK))
+               return;
+
+       /*
+        * We only process prefix length of 64 since our Identifier is 64-bit
+        */
+       if (icmp_prefix->prefix_len == 64) {
+               /* Copy 64-bit from the local-link address to create
+                  IPv6 address */
+               memcpy((char *)&addr,
+                      (char *)&icmp_prefix->prefix, 8);
+               memcpy((char *)&addr.addr8[8],
+                      &context->link_local_addr.addr8[8], 8);
+               inet_ntop(AF_INET6, &addr, addr_str, sizeof(addr_str));
+               LOG_DEBUG("IPv6: Got RA ICMP option IP addr: %s", addr_str);
+               ipv6_add_prefix_entry(context, &addr, 64);
+       }
+}
+
+static void ipv6_icmp_handle_nd_adv(struct ipv6_context *context)
+{
+       struct eth_hdr *eth =
+                       (struct eth_hdr *)context->ustack->data_link_layer;
+       struct ipv6_hdr *ipv6 =
+                       (struct ipv6_hdr *)context->ustack->network_layer;
+       struct icmpv6_hdr *icmp = (struct icmpv6_hdr *)((u8_t *)ipv6 +
+                                               sizeof(struct ipv6_hdr));
+       struct icmpv6_opt_link_addr *link_opt =
+                       (struct icmpv6_opt_link_addr *)((u8_t *)icmp +
+                       sizeof(struct icmpv6_hdr) + sizeof(struct ipv6_addr));
+       struct ipv6_addr *tar_addr6;
+       char addr_str[INET6_ADDRSTRLEN];
+
+       /* Added the multicast check for ARP table update */
+       /* Should we qualify for only our host's multicast and our
+          link_local_multicast?? */
+       LOG_DEBUG("IPv6: Handle nd adv");
+       if ((ipv6_is_it_our_address(context, &ipv6->ipv6_dst) == TRUE) ||
+           (memcmp((char *)&context->link_local_multi,
+                   (char *)&ipv6->ipv6_dst, sizeof(struct ipv6_addr)) == 0) ||
+           (memcmp((char *)&context->multi,
+                   (char *)&ipv6->ipv6_dst, sizeof(struct ipv6_addr)) == 0)) {
+               /*
+                * This is an ARP reply for our addresses. Let's update the
+                * ARP table.
+                */
+               ipv6_update_arp_table(context, &ipv6->ipv6_src,
+                                     &eth->src_mac);
+
+               /* Now check for the target address option and update that as
+                  well */
+               if (link_opt->hdr.type == IPV6_ICMP_OPTION_TAR_ADDR) {
+                       tar_addr6 = (struct ipv6_addr *)((u8_t *)icmp +
+                                   sizeof(struct icmpv6_hdr));
+                       LOG_DEBUG("IPV6: Target MAC "
+                                 "%02x:%02x:%02x:%02x:%02x:%02x",
+                               link_opt->link_addr[0], link_opt->link_addr[1],
+                               link_opt->link_addr[2], link_opt->link_addr[3],
+                               link_opt->link_addr[4], link_opt->link_addr[5]);
+                       inet_ntop(AF_INET6, &tar_addr6->addr8, addr_str,
+                                 sizeof(addr_str));
+                       LOG_DEBUG("IPv6: Target IP addr %s", addr_str);
+                       ipv6_update_arp_table(context, tar_addr6,
+                             (struct mac_address *)link_opt->link_addr);
+               }
+
+       }
+}
+
+static void ipv6_icmp_handle_nd_sol(struct ipv6_context *context)
+{
+       struct eth_hdr *eth =
+                       (struct eth_hdr *)context->ustack->data_link_layer;
+       struct ipv6_hdr *ipv6 =
+                       (struct ipv6_hdr *)context->ustack->network_layer;
+       struct icmpv6_hdr *icmp = (struct icmpv6_hdr *)((u8_t *)ipv6 +
+                                               sizeof(struct ipv6_hdr));
+       struct icmpv6_opt_link_addr *link_opt =
+                       (struct icmpv6_opt_link_addr *)((u8_t *)icmp +
+                       sizeof(struct icmpv6_hdr) + sizeof(struct ipv6_addr));
+       int icmpv6_opt_len = 0;
+       struct ipv6_addr tmp;
+       struct ipv6_addr *longest_match_addr, *tar_addr6;
+
+       LOG_DEBUG("IPv6: Handle nd sol");
+
+       if ((memcmp((char *)&context->mac_addr,
+                   (char *)&eth->dest_mac, sizeof(struct mac_address)) != 0) &&
+           (iscsiL2IsOurMcAddr(context, (struct mac_address *)&eth->dest_mac)
+            == FALSE)) {
+               /* This packet is not for us to handle */
+               LOG_DEBUG("IPv6: MAC not addressed to us "
+                         "%02x:%02x:%02x:%02x:%02x:%02x",
+                         eth->dest_mac.addr[0], eth->dest_mac.addr[1],
+                         eth->dest_mac.addr[2], eth->dest_mac.addr[3],
+                         eth->dest_mac.addr[4], eth->dest_mac.addr[5]);
+               return;
+       }
+
+       /* Also check for the icmpv6_data before generating the reply */
+       if (ipv6_is_it_our_address(context,
+                                  (struct ipv6_addr *) ((u8_t *) icmp +
+                                                 sizeof(struct icmpv6_hdr)))
+           == FALSE) {
+               /* This packet is not for us to handle */
+               LOG_DEBUG("IPv6: IP not addressed to us");
+               return;
+       }
+
+       /* Copy source MAC to Destination MAC */
+       memcpy((char *)&eth->dest_mac,
+              (char *)&eth->src_mac, sizeof(struct mac_address));
+
+       /* Dest IP contains source IP */
+       memcpy((char *)&tmp,
+              (char *)&ipv6->ipv6_dst, sizeof(struct ipv6_addr));
+       memcpy((char *)&ipv6->ipv6_dst,
+              (char *)&ipv6->ipv6_src, sizeof(struct ipv6_addr));
+
+       /* Examine the Neighbor Solicitation ICMPv6 target address field.
+          If target address exist, use that to find best match src address
+          for the reply */
+       if (link_opt->hdr.type == IPV6_ICMP_OPTION_SRC_ADDR) {
+               tar_addr6 = (struct ipv6_addr *)((u8_t *)icmp +
+                                                sizeof(struct icmpv6_hdr));
+               if (ipv6_is_it_our_link_local_address(context, tar_addr6)
+                   == TRUE) {
+                       LOG_DEBUG("IPv6: NA using link local");
+                       memcpy((char *)&ipv6->ipv6_src,
+                              (char *)&context->link_local_addr,
+                              sizeof(struct ipv6_addr));
+               } else {
+                       longest_match_addr =
+                             ipv6_find_longest_match(context, tar_addr6);
+                       if (longest_match_addr) {
+                               LOG_DEBUG("IPv6: NA using longest match addr");
+                               memcpy((char *)&ipv6->ipv6_src,
+                                      (char *)longest_match_addr,
+                                      sizeof(struct ipv6_addr));
+                       } else {
+                               LOG_DEBUG("IPv6: NA using link local instead");
+                               memcpy((char *)&ipv6->ipv6_src,
+                               (char *)&context->link_local_addr,
+                                      sizeof(struct ipv6_addr));
+                       }
+               }
+       } else {
+               /* No target link address, just use whatever it sent to us */
+               LOG_DEBUG("IPv6: NA use dst addr");
+               memcpy((char *)&ipv6->ipv6_src,
+                      (char *)&tmp,
+                      sizeof(struct ipv6_addr));
+       }
+       ipv6->ipv6_hop_limit = 255;
+       icmp->icmpv6_type = ICMPV6_NEIGH_ADV;
+       icmp->icmpv6_code = 0;
+       icmp->icmpv6_data = 0;
+       icmp->icmpv6_cksum = 0;
+       icmp->data.icmpv6_un_data8[0] =
+           IPV6_NA_FLAG_SOLICITED | IPV6_NA_FLAG_OVERRIDE;
+       memcpy((char *)((u8_t *)icmp + sizeof(struct icmpv6_hdr)),
+              (char *)&ipv6->ipv6_src,
+              sizeof(struct ipv6_addr));
+
+       /* Add the target link address option only for all solicitation */
+       ipv6_icmp_init_link_option(context,
+                       (struct icmpv6_opt_link_addr *)((u8_t *)icmp +
+                                       sizeof(struct icmpv6_hdr) +
+                                       sizeof(struct ipv6_addr)),
+                       IPV6_ICMP_OPTION_TAR_ADDR);
+       icmpv6_opt_len = sizeof(struct icmpv6_opt_link_addr);
+       ipv6->ipv6_plen = HOST_TO_NET16((sizeof(struct icmpv6_hdr) +
+                                icmpv6_opt_len + sizeof(struct ipv6_addr)));
+       LOG_DEBUG("IPv6: Send nd adv");
+       ipv6_send(context,
+                 (u8_t *) icmp - (u8_t *) eth +
+                 sizeof(struct icmpv6_hdr) +
+                 sizeof(struct icmpv6_opt_link_addr) +
+                 sizeof(struct ipv6_addr));
+       return;
+}
+
+static void ipv6_icmp_handle_echo_request(struct ipv6_context *context)
+{
+       struct eth_hdr *eth =
+                       (struct eth_hdr *)context->ustack->data_link_layer;
+       struct ipv6_hdr *ipv6 =
+                       (struct ipv6_hdr *)context->ustack->network_layer;
+       struct icmpv6_hdr *icmp = (struct icmpv6_hdr *)((u8_t *)ipv6 +
+                                               sizeof(struct ipv6_hdr));
+       struct ipv6_addr temp;
+
+       /* Copy source MAC to Destination MAC */
+       memcpy((char *)&eth->dest_mac,
+              (char *)&eth->src_mac, sizeof(struct mac_address));
+
+       memcpy((char *)&temp,
+              (char *)&ipv6->ipv6_dst, sizeof(struct ipv6_addr));
+
+       /* Dest IP contains source IP */
+       memcpy((char *)&ipv6->ipv6_dst,
+              (char *)&ipv6->ipv6_src, sizeof(struct ipv6_addr));
+       /* Use Link-local as source address */
+       memcpy((char *)&ipv6->ipv6_src,
+              (char *)&temp, sizeof(struct ipv6_addr));
+
+       ipv6->ipv6_hop_limit = context->hop_limit;
+       icmp->icmpv6_type = ICMPV6_ECHO_REPLY;
+       icmp->icmpv6_code = 0;
+       icmp->icmpv6_cksum = 0;
+       LOG_DEBUG("IPv6: Send echo reply");
+       ipv6_send(context, (u8_t *) icmp - (u8_t *) eth +
+                 sizeof(struct ipv6_hdr) + HOST_TO_NET16(ipv6->ipv6_plen));
+       return;
+}
+
+void ipv6_set_ip_params(struct ipv6_context *context,
+                       struct ipv6_addr *src_ip, u8_t prefix_len,
+                       struct ipv6_addr *default_gateway,
+                       struct ipv6_addr *linklocal)
+{
+       if (!(IPV6_IS_ADDR_UNSPECIFIED(src_ip))) {
+               ipv6_add_prefix_entry(context, src_ip, prefix_len);
+               /* Create the multi_dest address */
+               memset(&context->multi_dest, 0, sizeof(struct ipv6_addr));
+               context->multi_dest.addr8[0] = 0xff;
+               context->multi_dest.addr8[1] = 0x02;
+               context->multi_dest.addr8[11] = 0x01;
+               context->multi_dest.addr8[12] = 0xff;
+               context->multi_dest.addr8[13] = src_ip->addr8[13];
+               context->multi_dest.addr16[7] = src_ip->addr16[7];
+               /* Create the multi address */
+               memset(&context->multi, 0, sizeof(struct ipv6_addr));
+               context->multi.addr8[0] = 0xfc;
+               context->multi.addr8[2] = 0x02;
+               context->multi.addr16[7] = src_ip->addr16[7];
+       }
+
+       if (!(IPV6_IS_ADDR_UNSPECIFIED(default_gateway))) {
+               /* Override the default gateway addr */
+               memcpy((char *)&context->default_router,
+                      (char *)default_gateway, sizeof(struct ipv6_addr));
+               ipv6_add_prefix_entry(context, default_gateway,
+                                     prefix_len);
+       }
+       if (!(IPV6_IS_ADDR_UNSPECIFIED(linklocal))) {
+               /* Override the linklocal addr */
+               memcpy((char *)&context->link_local_addr,
+                      (char *)linklocal, sizeof(struct ipv6_addr));
+               context->link_local_multi.addr8[0] = 0xff;
+               context->link_local_multi.addr8[1] = 0x02;
+               context->link_local_multi.addr8[11] = 0x01;
+               context->link_local_multi.addr8[12] = 0xff;
+               context->link_local_multi.addr8[13] |=
+                   context->link_local_addr.addr8[13];
+               context->link_local_multi.addr16[7] =
+                   context->link_local_addr.addr16[7];
+
+               /* Default Prefix length is 64 */
+               /* Add Link local address to the head of the ipv6 address
+                  list */
+               ipv6_add_prefix_entry(context,
+                                     &context->link_local_addr, 64);
+       }
+}
+
+int ipv6_get_source_ip_addrs(struct ipv6_context *context,
+                            struct ipv6_addr_entry *addr_list)
+{
+       struct ipv6_prefix_entry *ipv6_prefix;
+       int i;
+
+       for (i = 0, ipv6_prefix = context->addr_list; ipv6_prefix != NULL;
+            ipv6_prefix = ipv6_prefix->next) {
+               memcpy((char *)&addr_list->ip_addr,
+                      (char *)&ipv6_prefix->ip_addr,
+                      sizeof(struct ipv6_addr));
+               addr_list->prefix_len = ipv6_prefix->prefix_len * 8;
+
+               i++;
+               addr_list++;
+       }
+
+       return i;
+}
+
+int ipv6_get_default_router_ip_addrs(struct ipv6_context *context,
+                                    struct ipv6_addr *ip_addr)
+{
+       /* This is a default router. */
+       memcpy((char *)ip_addr,
+              (char *)&context->default_router,
+              sizeof(struct ipv6_addr));
+
+       return 1;
+}
+
+static void ipv6_udp_rx(struct ipv6_context *context)
+{
+       struct eth_hdr *eth =
+                       (struct eth_hdr *)context->ustack->data_link_layer;
+       struct ipv6_hdr *ipv6 =
+                       (struct ipv6_hdr *)context->ustack->network_layer;
+       struct udp_hdr *udp = (struct udp_hdr *)((u8_t *)ipv6 +
+                                               sizeof(struct ipv6_hdr));
+       struct dhcpv6_context *dhcpv6c;
+
+       /*
+        * We only care about DHCPv6 packets from the DHCPv6 server.  We drop
+        * all others.
+        */
+       if (!(context->flags & IPV6_FLAGS_DISABLE_DHCPV6)) {
+               if ((udp->src_port == HOST_TO_NET16(DHCPV6_SERVER_PORT)) &&
+                   (udp->dest_port == HOST_TO_NET16(DHCPV6_CLIENT_PORT))) {
+                       dhcpv6c = context->dhcpv6_context;
+                       dhcpv6c->eth = eth;
+                       dhcpv6c->ipv6 = ipv6;
+                       dhcpv6c->udp = udp;
+                       ipv6_udp_handle_dhcp(dhcpv6c);
+               }
+       }
+}
+
+struct mac_address *ipv6_get_link_addr(struct ipv6_context *context)
+{
+       return &context->mac_addr;
+}
+
+u16_t ipv6_do_stateful_dhcpv6(struct ipv6_context *context, u32_t flags)
+{
+       u16_t task = 0;
+       u16_t ra_flags;
+
+       ra_flags = context->flags &
+           (IPV6_FLAGS_MANAGED_ADDR_CONFIG | IPV6_FLAGS_OTHER_STATEFUL_CONFIG);
+
+       if (!(context->flags & IPV6_FLAGS_ROUTER_ADV_RECEIVED)) {
+               LOG_DEBUG("IPv6: There is no IPv6 router on the network");
+               ra_flags |=
+                   (IPV6_FLAGS_MANAGED_ADDR_CONFIG |
+                    IPV6_FLAGS_OTHER_STATEFUL_CONFIG);
+       }
+
+       if ((flags & ISCSI_FLAGS_DHCP_TCPIP_CONFIG) &&
+           (ra_flags & IPV6_FLAGS_MANAGED_ADDR_CONFIG))
+               task |= DHCPV6_TASK_GET_IP_ADDRESS;
+
+       if ((flags & ISCSI_FLAGS_DHCP_ISCSI_CONFIG) &&
+           (ra_flags & IPV6_FLAGS_OTHER_STATEFUL_CONFIG))
+               task |= DHCPV6_TASK_GET_OTHER_PARAMS;
+
+       LOG_DEBUG("IPv6: Stateful flags = 0x%x, ra_flags = 0x%x, task = 0x%x",
+                 flags, ra_flags, task);
+
+       return task;
+}
+
+void ipv6_add_solit_node_address(struct ipv6_context *context,
+                                struct ipv6_addr *ip_addr)
+{
+       struct mac_address mac_addr;
+
+       /*
+        * Add Solicited Node Multicast Address for statically configured IPv6
+        * address.
+        */
+       mac_addr.addr[0] = 0x33;
+       mac_addr.addr[1] = 0x33;
+       mac_addr.addr[2] = 0xff;
+       mac_addr.addr[3] = ip_addr->addr8[13];
+       mac_addr.addr[4] = ip_addr->addr8[14];
+       mac_addr.addr[5] = ip_addr->addr8[15];
+       iscsiL2AddMcAddr(context, (struct mac_address *)&mac_addr);
+}
+
+void ipv6_cfg_link_local_addr(struct ipv6_context *context,
+                             struct ipv6_addr *ip_addr)
+{
+       memcpy((char *)&context->link_local_addr,
+              (char *)ip_addr, sizeof(struct ipv6_addr));
+}
+
+void ipv6_disable_dhcpv6(struct ipv6_context *context)
+{
+       context->flags |= IPV6_FLAGS_DISABLE_DHCPV6;
+}
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/ipv6.h b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/ipv6.h
new file mode 100644 (file)
index 0000000..3586437
--- /dev/null
@@ -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 16
+
+       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/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/ipv6_ndpc.c b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/ipv6_ndpc.c
new file mode 100644 (file)
index 0000000..bb07c1d
--- /dev/null
@@ -0,0 +1,432 @@
+/*
+ * 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);
+       s->retry_count = 0;
+
+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) {
+                       s->retry_count++;
+                       if (s->retry_count > DHCPV6_NUM_OF_RETRY) {
+                               LOG_DEBUG("%s: ndpc_handle DHCP failed",
+                                         s->nic->log_name);
+                       } else {
+                               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/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/ipv6_ndpc.h b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/ipv6_ndpc.h
new file mode 100644 (file)
index 0000000..709a050
--- /dev/null
@@ -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/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/ipv6_pkt.h b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/ipv6_pkt.h
new file mode 100644 (file)
index 0000000..b42f1aa
--- /dev/null
@@ -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/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/lc-addrlabels.h b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/lc-addrlabels.h
new file mode 100644 (file)
index 0000000..c394b22
--- /dev/null
@@ -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/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/lc-switch.h b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/lc-switch.h
new file mode 100644 (file)
index 0000000..1839b36
--- /dev/null
@@ -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/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/lc.h b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/lc.h
new file mode 100644 (file)
index 0000000..2e4a7bb
--- /dev/null
@@ -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/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/psock.c b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/psock.c
new file mode 100644 (file)
index 0000000..fcffbe7
--- /dev/null
@@ -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/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/psock.h b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/psock.h
new file mode 100644 (file)
index 0000000..ea86ef5
--- /dev/null
@@ -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/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/pt.h b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/pt.h
new file mode 100644 (file)
index 0000000..ffb1d15
--- /dev/null
@@ -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/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/timer.c b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/timer.c
new file mode 100644 (file)
index 0000000..da77148
--- /dev/null
@@ -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/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/timer.h b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/timer.h
new file mode 100644 (file)
index 0000000..12739fd
--- /dev/null
@@ -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/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/uip-neighbor.c b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/uip-neighbor.c
new file mode 100644 (file)
index 0000000..4c80c32
--- /dev/null
@@ -0,0 +1,219 @@
+/*
+ * Copyright (c) 2006, Swedish Institute of Computer Science.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the Institute nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This file is part of the uIP TCP/IP stack
+ *
+ */
+
+/**
+ * \file
+ *         Database of link-local neighbors, used by IPv6 code and
+ *         to be used by a future ARP code rewrite.
+ * \author
+ *         Adam Dunkels <adam@sics.se>
+ */
+
+#include "logger.h"
+#include "uip.h"
+#include "uip-neighbor.h"
+
+#include <errno.h>
+#include <string.h>
+#include <arpa/inet.h>
+
+/*******************************************************************************
+ * Constants
+ ******************************************************************************/
+#define PFX "uip-neigh "
+
+#define MAX_TIME 128
+
+/*---------------------------------------------------------------------------*/
+void uip_neighbor_init(struct uip_stack *ustack)
+{
+       int i;
+
+       pthread_mutex_lock(&ustack->lock);
+       for (i = 0; i < UIP_NEIGHBOR_ENTRIES; ++i) {
+               memset(&(ustack->neighbor_entries[i].ipaddr), 0,
+                      sizeof(ustack->neighbor_entries[i].ipaddr));
+               memset(&(ustack->neighbor_entries[i].mac_addr), 0,
+                      sizeof(ustack->neighbor_entries[i].mac_addr));
+               ustack->neighbor_entries[i].time = MAX_TIME;
+       }
+       pthread_mutex_unlock(&ustack->lock);
+}
+
+void uip_neighbor_add(struct uip_stack *ustack,
+                     struct in6_addr *addr6, struct uip_eth_addr *addr)
+{
+       int i, oldest;
+       u8_t oldest_time;
+       char buf[INET6_ADDRSTRLEN];
+
+       inet_ntop(AF_INET6, addr6, buf, sizeof(buf));
+
+       pthread_mutex_lock(&ustack->lock);
+
+       /* Find the first unused entry or the oldest used entry. */
+       oldest_time = 0;
+       oldest = 0;
+       for (i = 0; i < UIP_NEIGHBOR_ENTRIES; ++i) {
+               if (ustack->neighbor_entries[i].time == MAX_TIME) {
+                       oldest = i;
+                       break;
+               }
+               if (uip_ip6addr_cmp
+                   (ustack->neighbor_entries[i].ipaddr.s6_addr, addr6)) {
+                       oldest = i;
+                       break;
+               }
+               if (ustack->neighbor_entries[i].time > oldest_time) {
+                       oldest = i;
+                       oldest_time = ustack->neighbor_entries[i].time;
+               }
+       }
+
+       /* Use the oldest or first free entry (either pointed to by the
+          "oldest" variable). */
+       ustack->neighbor_entries[oldest].time = 0;
+       uip_ip6addr_copy(ustack->neighbor_entries[oldest].ipaddr.s6_addr,
+                        addr6);
+       memcpy(&ustack->neighbor_entries[oldest].mac_addr, addr,
+              sizeof(struct uip_eth_addr));
+
+       LOG_DEBUG("Adding neighbor %s with "
+                 "mac address %02x:%02x:%02x:%02x:%02x:%02x at %d",
+                 buf, addr->addr[0], addr->addr[1], addr->addr[2],
+                 addr->addr[3], addr->addr[4], addr->addr[5], oldest);
+
+       pthread_mutex_unlock(&ustack->lock);
+}
+
+/*---------------------------------------------------------------------------*/
+static struct neighbor_entry *find_entry(struct uip_stack *ustack,
+                                        struct in6_addr *addr6)
+{
+       int i;
+
+       for (i = 0; i < UIP_NEIGHBOR_ENTRIES; ++i) {
+               if (uip_ip6addr_cmp
+                   (ustack->neighbor_entries[i].ipaddr.s6_addr,
+                    addr6->s6_addr)) {
+                       return &ustack->neighbor_entries[i];
+               }
+       }
+
+       return NULL;
+}
+
+/*---------------------------------------------------------------------------*/
+void uip_neighbor_update(struct uip_stack *ustack, struct in6_addr *addr6)
+{
+       struct neighbor_entry *e;
+
+       pthread_mutex_lock(&ustack->lock);
+
+       e = find_entry(ustack, addr6);
+       if (e != NULL)
+               e->time = 0;
+
+       pthread_mutex_unlock(&ustack->lock);
+}
+
+/*---------------------------------------------------------------------------*/
+int uip_neighbor_lookup(struct uip_stack *ustack,
+                       struct in6_addr *addr6, uint8_t *mac_addr)
+{
+       struct neighbor_entry *e;
+
+       pthread_mutex_lock(&ustack->lock);
+       e = find_entry(ustack, addr6);
+       if (e != NULL) {
+               char addr6_str[INET6_ADDRSTRLEN];
+               uint8_t *entry_mac_addr;
+
+               addr6_str[0] = '\0';
+               inet_ntop(AF_INET6, addr6->s6_addr, addr6_str,
+                         sizeof(addr6_str));
+               entry_mac_addr = (uint8_t *)&e->mac_addr.addr;
+
+               LOG_DEBUG(PFX
+                         "Found %s at %02x:%02x:%02x:%02x:%02x:%02x",
+                         addr6_str,
+                         entry_mac_addr[0], entry_mac_addr[1],
+                         entry_mac_addr[2], entry_mac_addr[3],
+                         entry_mac_addr[4], entry_mac_addr[5]);
+
+               memcpy(mac_addr, entry_mac_addr, sizeof(e->mac_addr));
+               pthread_mutex_unlock(&ustack->lock);
+               return 0;
+       }
+
+       pthread_mutex_unlock(&ustack->lock);
+       return -ENOENT;
+}
+
+void uip_neighbor_out(struct uip_stack *ustack)
+{
+       struct neighbor_entry *e;
+       struct uip_eth_hdr *eth_hdr =
+           (struct uip_eth_hdr *)ustack->data_link_layer;
+       struct uip_ipv6_hdr *ipv6_hdr =
+           (struct uip_ipv6_hdr *)ustack->network_layer;
+
+       pthread_mutex_lock(&ustack->lock);
+
+       /* Find the destination IP address in the neighbor table and construct
+          the Ethernet header. If the destination IP addres isn't on the
+          local network, we use the default router's IP address instead.
+
+          If not ARP table entry is found, we overwrite the original IP
+          packet with an ARP request for the IP address. */
+       e = find_entry(ustack, (struct in6_addr *)ipv6_hdr->destipaddr);
+       if (e == NULL) {
+               struct uip_eth_addr eth_addr_tmp;
+
+               memcpy(&eth_addr_tmp, eth_hdr->src.addr, sizeof(eth_addr_tmp));
+               memcpy(eth_hdr->src.addr, ustack->uip_ethaddr.addr,
+                      sizeof(eth_hdr->src.addr));
+               memcpy(eth_hdr->dest.addr, &eth_addr_tmp,
+                      sizeof(eth_hdr->dest.addr));
+
+               pthread_mutex_unlock(&ustack->lock);
+               return;
+       }
+
+       memcpy(eth_hdr->dest.addr, &e->mac_addr, sizeof(eth_hdr->dest.addr));
+       memcpy(eth_hdr->src.addr, ustack->uip_ethaddr.addr,
+              sizeof(eth_hdr->src.addr));
+
+       pthread_mutex_unlock(&ustack->lock);
+}
+
+/*---------------------------------------------------------------------------*/
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/uip-neighbor.h b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/uip-neighbor.h
new file mode 100644 (file)
index 0000000..d10c57b
--- /dev/null
@@ -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/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/uip.c b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/uip.c
new file mode 100644 (file)
index 0000000..e0a7221
--- /dev/null
@@ -0,0 +1,2434 @@
+#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"
+#include "ping.h"
+
+/**
+ * \defgroup uip The uIP TCP/IP stack
+ * @{
+ *
+ * uIP is an implementation of the TCP/IP protocol stack intended for
+ * small 8-bit and 16-bit microcontrollers.
+ *
+ * uIP provides the necessary protocols for Internet communication,
+ * with a very small code footprint and RAM requirements - the uIP
+ * code size is on the order of a few kilobytes and RAM usage is on
+ * the order of a few hundred bytes.
+ */
+
+/**
+ * \file
+ * The uIP TCP/IP stack code.
+ * \author Adam Dunkels <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_ip4addr_t all_ones_addr4 = { 0xffff, 0xffff };
+
+const uip_ip6addr_t all_zeroes_addr6 = {
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
+};
+const uip_ip4addr_t all_zeroes_addr4 = { 0x0000, 0x0000 };
+
+const uint8_t mutlicast_ipv6_prefix[16] = {
+       0xfc, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+const uint8_t link_local_addres_prefix[16] = {
+       0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+const uint32_t link_local_address_prefix_length = 10;
+
+/* Structures and definitions. */
+#define TCP_FIN 0x01
+#define TCP_SYN 0x02
+#define TCP_RST 0x04
+#define TCP_PSH 0x08
+#define TCP_ACK 0x10
+#define TCP_URG 0x20
+#define TCP_CTL 0x3f
+
+#define TCP_OPT_END     0      /* End of TCP options list */
+#define TCP_OPT_NOOP    1      /* "No-operation" TCP option */
+#define TCP_OPT_MSS     2      /* Maximum segment size TCP option */
+
+#define TCP_OPT_MSS_LEN 4      /* Length of TCP MSS option. */
+
+#define ICMP_ECHO_REPLY 0
+#define ICMP_ECHO       8
+
+#define ICMP6_ECHO_REPLY             129
+#define ICMP6_ECHO                   128
+#define ICMP6_NEIGHBOR_SOLICITATION  135
+#define ICMP6_NEIGHBOR_ADVERTISEMENT 136
+
+#define ICMP6_FLAG_S (1 << 6)
+
+#define ICMP6_OPTION_SOURCE_LINK_ADDRESS 1
+#define ICMP6_OPTION_TARGET_LINK_ADDRESS 2
+
+/* Macros. */
+#define FBUF ((struct uip_tcpip_hdr *)&uip_reassbuf[0])
+#define UDPBUF(ustack) ((struct uip_udpip_hdr *)ustack->network_layer)
+
+/******************************************************************************
+ * Utility Functions
+ *****************************************************************************/
+static int is_ipv6(struct uip_stack *ustack)
+{
+       u16_t type;
+
+       type = ETH_BUF(ustack->uip_buf)->type;
+       type = ntohs(type);
+       if (type == UIP_ETHTYPE_8021Q)
+               type = ntohs(VLAN_ETH_BUF(ustack->uip_buf)->type);
+       else
+               type = ntohs(ETH_BUF(ustack->uip_buf)->type);
+
+       return (type == UIP_ETHTYPE_IPv6);
+}
+
+int is_ipv6_link_local_address(uip_ip6addr_t *addr)
+{
+       u8_t *test_adddr = (u8_t *) addr;
+       u8_t test_remainder;
+
+       if (test_adddr[0] != link_local_addres_prefix[0])
+               return 0;
+
+       test_remainder = (test_adddr[1] & 0xC0) >> 6;
+       if (test_remainder != 2)
+               return 0;
+
+       return 1;
+}
+
+void uip_sethostaddr4(struct uip_stack *ustack, uip_ip4addr_t *addr)
+{
+       pthread_mutex_lock(&ustack->lock);
+       uip_ip4addr_copy(ustack->hostaddr, (addr));
+       pthread_mutex_unlock(&ustack->lock);
+}
+
+void uip_setdraddr4(struct uip_stack *ustack, uip_ip4addr_t *addr)
+{
+       pthread_mutex_lock(&ustack->lock);
+       uip_ip4addr_copy(ustack->default_route_addr, (addr));
+       pthread_mutex_unlock(&ustack->lock);
+}
+
+void uip_setnetmask4(struct uip_stack *ustack, uip_ip4addr_t *addr)
+{
+       pthread_mutex_lock(&ustack->lock);
+       uip_ip4addr_copy(ustack->netmask, (addr));
+       pthread_mutex_unlock(&ustack->lock);
+}
+
+void uip_setethernetmac(struct uip_stack *ustack, uint8_t *mac)
+{
+       pthread_mutex_lock(&ustack->lock);
+       memcpy(ustack->uip_ethaddr.addr, (mac), 6);
+       pthread_mutex_unlock(&ustack->lock);
+}
+
+void set_uip_stack(struct uip_stack *ustack,
+                  uip_ip4addr_t *ip,
+                  uip_ip4addr_t *netmask,
+                  uip_ip4addr_t *default_route, uint8_t *mac_addr)
+{
+       if (ip)
+               uip_sethostaddr4(ustack, ip);
+       if (netmask)
+               uip_setnetmask4(ustack, netmask);
+       if (default_route)
+               uip_setdraddr4(ustack, default_route);
+       if (mac_addr)
+               uip_setethernetmac(ustack, mac_addr);
+}
+
+#if !UIP_ARCH_ADD32
+void uip_add32(u8_t *op32, u16_t op16, u8_t *uip_acc32)
+{
+       uip_acc32[3] = op32[3] + (op16 & 0xff);
+       uip_acc32[2] = op32[2] + (op16 >> 8);
+       uip_acc32[1] = op32[1];
+       uip_acc32[0] = op32[0];
+
+       if (uip_acc32[2] < (op16 >> 8)) {
+               ++uip_acc32[1];
+               if (uip_acc32[1] == 0)
+                       ++uip_acc32[0];
+       }
+
+       if (uip_acc32[3] < (op16 & 0xff)) {
+               ++uip_acc32[2];
+               if (uip_acc32[2] == 0) {
+                       ++uip_acc32[1];
+                       if (uip_acc32[1] == 0)
+                               ++uip_acc32[0];
+               }
+       }
+}
+
+#endif /* UIP_ARCH_ADD32 */
+
+#if !UIP_ARCH_CHKSUM
+/*---------------------------------------------------------------------------*/
+static u16_t chksum(u16_t sum, const u8_t *data, u16_t len)
+{
+       u16_t t;
+       const u8_t *dataptr;
+       const u8_t *last_byte;
+
+       dataptr = data;
+       last_byte = data + len - 1;
+
+       while (dataptr < last_byte) {   /* At least two more bytes */
+               t = (dataptr[0] << 8) + dataptr[1];
+               sum += t;
+               if (sum < t)
+                       sum++;  /* carry */
+               dataptr += 2;
+       }
+
+       if (dataptr == last_byte) {
+               t = (dataptr[0] << 8) + 0;
+               sum += t;
+               if (sum < t)
+                       sum++;  /* carry */
+       }
+
+       /* Return sum in host byte order. */
+       return sum;
+}
+
+/*---------------------------------------------------------------------------*/
+u16_t uip_chksum(u16_t *data, u16_t len)
+{
+       return htons(chksum(0, (u8_t *)data, len));
+}
+
+/*---------------------------------------------------------------------------*/
+#ifndef UIP_ARCH_IPCHKSUM
+u16_t uip_ipchksum(struct uip_stack *ustack)
+{
+       u16_t sum;
+       u16_t uip_iph_len;
+
+       if (is_ipv6(ustack))
+               uip_iph_len = UIP_IPv6_H_LEN;
+       else
+               uip_iph_len = UIP_IPv4_H_LEN;
+
+       sum = chksum(0, ustack->network_layer, uip_iph_len);
+       return (sum == 0) ? 0xffff : htons(sum);
+}
+#endif
+
+/*---------------------------------------------------------------------------*/
+static u16_t upper_layer_chksum_ipv4(struct uip_stack *ustack, u8_t proto)
+{
+       u16_t upper_layer_len;
+       u16_t sum;
+       struct uip_tcp_ipv4_hdr *tcp_ipv4_hdr = NULL;
+
+       tcp_ipv4_hdr = (struct uip_tcp_ipv4_hdr *)ustack->network_layer;
+
+       upper_layer_len = (((u16_t) (tcp_ipv4_hdr->len[0]) << 8) +
+                          tcp_ipv4_hdr->len[1]);
+       /* check for underflow from an invalid length field */
+       if (upper_layer_len < UIP_IPv4_H_LEN) {
+               /* return 0 as an invalid checksum */
+               return 0;
+       }
+       upper_layer_len -= UIP_IPv4_H_LEN;
+
+       /* First sum pseudoheader. */
+       /* IP protocol and length fields. This addition cannot carry. */
+       sum = upper_layer_len + proto;
+
+       sum =
+           chksum(sum, (u8_t *)&tcp_ipv4_hdr->srcipaddr[0],
+                  2 * sizeof(uip_ip4addr_t));
+       /* Sum TCP header and data. */
+       sum = chksum(sum, ustack->network_layer + UIP_IPv4_H_LEN,
+                    upper_layer_len);
+
+       return (sum == 0) ? 0xffff : htons(sum);
+}
+
+/*---------------------------------------------------------------------------*/
+static uint16_t upper_layer_checksum_ipv6(uint8_t *data, uint8_t proto)
+{
+       uint16_t upper_layer_len;
+       uint16_t sum;
+       struct ip6_hdr *ipv6_hdr;
+       uint8_t *upper_layer;
+       uint32_t val;
+
+       ipv6_hdr = (struct ip6_hdr *)data;
+
+       upper_layer_len = ntohs(ipv6_hdr->ip6_plen);
+
+       /* First sum pseudoheader. */
+       sum = 0;
+       sum = chksum(sum, (const u8_t *)ipv6_hdr->ip6_src.s6_addr,
+                    sizeof(ipv6_hdr->ip6_src));
+       sum = chksum(sum, (const u8_t *)ipv6_hdr->ip6_dst.s6_addr,
+                    sizeof(ipv6_hdr->ip6_dst));
+
+       val = htons(upper_layer_len);
+       sum = chksum(sum, (u8_t *)&val, sizeof(val));
+
+       val = htons(proto);
+       sum = chksum(sum, (u8_t *)&val, sizeof(val));
+
+       upper_layer = (uint8_t *)(ipv6_hdr + 1);
+       sum = chksum(sum, upper_layer, upper_layer_len);
+
+       return (sum == 0) ? 0xffff : htons(sum);
+}
+
+/*---------------------------------------------------------------------------*/
+
+u16_t uip_icmp6chksum(struct uip_stack *ustack)
+{
+       uint8_t *data = ustack->network_layer;
+
+       return upper_layer_checksum_ipv6(data, UIP_PROTO_ICMP6);
+}
+
+uint16_t icmpv6_checksum(uint8_t *data)
+{
+       return upper_layer_checksum_ipv6(data, IPPROTO_ICMPV6);
+}
+
+/*---------------------------------------------------------------------------*/
+u16_t uip_tcpchksum(struct uip_stack *ustack)
+{
+       return upper_layer_chksum_ipv4(ustack, UIP_PROTO_TCP);
+}
+
+/*---------------------------------------------------------------------------*/
+#if UIP_UDP_CHECKSUMS
+static u16_t uip_udpchksum_ipv4(struct uip_stack *ustack)
+{
+       return upper_layer_chksum_ipv4(ustack, UIP_PROTO_UDP);
+}
+
+static u16_t uip_udpchksum_ipv6(struct uip_stack *ustack)
+{
+       uint8_t *data = ustack->network_layer;
+
+       return upper_layer_checksum_ipv6(data, UIP_PROTO_UDP);
+}
+
+u16_t uip_udpchksum(struct uip_stack *ustack)
+{
+       if (is_ipv6(ustack))
+               return uip_udpchksum_ipv6(ustack);
+       else
+               return uip_udpchksum_ipv4(ustack);
+}
+#endif /* UIP_UDP_CHECKSUMS */
+#endif /* UIP_ARCH_CHKSUM */
+/*---------------------------------------------------------------------------*/
+void uip_init(struct uip_stack *ustack, uint8_t ipv6_enabled)
+{
+       u8_t c;
+
+       for (c = 0; c < UIP_LISTENPORTS; ++c)
+               ustack->uip_listenports[c] = 0;
+       for (c = 0; c < UIP_CONNS; ++c)
+               ustack->uip_conns[c].tcpstateflags = UIP_CLOSED;
+#if UIP_ACTIVE_OPEN
+       ustack->lastport = 1024;
+#endif /* UIP_ACTIVE_OPEN */
+
+#if UIP_UDP
+       for (c = 0; c < UIP_UDP_CONNS; ++c)
+               ustack->uip_udp_conns[c].lport = 0;
+#endif /* UIP_UDP */
+
+       /* IPv4 initialization. */
+#if UIP_FIXEDADDR == 0
+       /*  uip_hostaddr[0] = uip_hostaddr[1] = 0; */
+#endif /* UIP_FIXEDADDR */
+
+       /*  zero out the uIP statistics */
+       memset(&ustack->stats, 0, sizeof(ustack->stats));
+
+       /*  prepare the uIP lock */
+       pthread_mutex_init(&ustack->lock, NULL);
+
+       if (ipv6_enabled)
+               ustack->enable_IPv6 = UIP_SUPPORT_IPv6_ENABLED;
+       else
+               ustack->enable_IPv6 = UIP_SUPPORT_IPv6_DISABLED;
+
+       ustack->dhcpc = NULL;
+       ustack->ndpc = NULL;
+       ustack->ping_conf = NULL;
+}
+void uip_reset(struct uip_stack *ustack)
+{
+       /*  There was an associated DHCP object, this memory needs to be
+        *  freed */
+       if (ustack->dhcpc)
+               free(ustack->dhcpc);
+
+       ndpc_exit(ustack->ndpc);
+
+       memset(ustack, 0, sizeof(*ustack));
+}
+
+/*---------------------------------------------------------------------------*/
+#if UIP_ACTIVE_OPEN
+struct uip_conn *uip_connect(struct uip_stack *ustack, uip_ip4addr_t *ripaddr,
+                            u16_t rport)
+{
+       u8_t c;
+       register struct uip_conn *conn, *cconn;
+
+       /* Find an unused local port. */
+again:
+       ++ustack->lastport;
+
+       if (ustack->lastport >= 32000)
+               ustack->lastport = 4096;
+
+       /* Check if this port is already in use, and if so try to find
+          another one. */
+       for (c = 0; c < UIP_CONNS; ++c) {
+               conn = &ustack->uip_conns[c];
+               if (conn->tcpstateflags != UIP_CLOSED &&
+                   conn->lport == htons(ustack->lastport)) {
+                       goto again;
+               }
+       }
+
+       conn = 0;
+       for (c = 0; c < UIP_CONNS; ++c) {
+               cconn = &ustack->uip_conns[c];
+               if (cconn->tcpstateflags == UIP_CLOSED) {
+                       conn = cconn;
+                       break;
+               }
+               if (cconn->tcpstateflags == UIP_TIME_WAIT) {
+                       if (conn == 0 || cconn->timer > conn->timer)
+                               conn = cconn;
+               }
+       }
+
+       if (conn == 0)
+               return 0;
+
+       conn->tcpstateflags = UIP_SYN_SENT;
+
+       conn->snd_nxt[0] = ustack->iss[0];
+       conn->snd_nxt[1] = ustack->iss[1];
+       conn->snd_nxt[2] = ustack->iss[2];
+       conn->snd_nxt[3] = ustack->iss[3];
+
+       conn->initialmss = conn->mss = UIP_TCP_MSS;
+
+       conn->len = 1;          /* TCP length of the SYN is one. */
+       conn->nrtx = 0;
+       conn->timer = 1;        /* Send the SYN next time around. */
+       conn->rto = UIP_RTO;
+       conn->sa = 0;
+       conn->sv = 16;          /* Initial value of the RTT variance. */
+       conn->lport = htons(ustack->lastport);
+       conn->rport = rport;
+       uip_ip4addr_copy(&conn->ripaddr, ripaddr);
+
+       return conn;
+}
+#endif /* UIP_ACTIVE_OPEN */
+/*---------------------------------------------------------------------------*/
+#if UIP_UDP
+struct uip_udp_conn *uip_udp_new(struct uip_stack *ustack,
+                                uip_ip4addr_t *ripaddr, u16_t rport)
+{
+       u8_t c;
+       register struct uip_udp_conn *conn;
+
+       /* Find an unused local port. */
+again:
+       ++ustack->lastport;
+
+       if (ustack->lastport >= 32000)
+               ustack->lastport = 4096;
+
+       for (c = 0; c < UIP_UDP_CONNS; ++c) {
+               if (ustack->uip_udp_conns[c].lport == htons(ustack->lastport))
+                       goto again;
+       }
+
+       conn = 0;
+       for (c = 0; c < UIP_UDP_CONNS; ++c) {
+               if (ustack->uip_udp_conns[c].lport == 0) {
+                       conn = &ustack->uip_udp_conns[c];
+                       break;
+               }
+       }
+
+       if (conn == 0)
+               return 0;
+
+       conn->lport = htons(ustack->lastport);
+       conn->rport = rport;
+       if (ripaddr == NULL)
+               memset(conn->ripaddr, 0, sizeof(uip_ip4addr_t));
+       else
+               uip_ip4addr_copy(&conn->ripaddr, ripaddr);
+       conn->ttl = UIP_TTL;
+
+       return conn;
+}
+#endif /* UIP_UDP */
+/*---------------------------------------------------------------------------*/
+void uip_unlisten(struct uip_stack *ustack, u16_t port)
+{
+       u8_t c;
+
+       for (c = 0; c < UIP_LISTENPORTS; ++c) {
+               if (ustack->uip_listenports[c] == port) {
+                       ustack->uip_listenports[c] = 0;
+                       return;
+               }
+       }
+}
+
+/*---------------------------------------------------------------------------*/
+void uip_listen(struct uip_stack *ustack, u16_t port)
+{
+       u8_t c;
+
+       for (c = 0; c < UIP_LISTENPORTS; ++c) {
+               if (ustack->uip_listenports[c] == 0) {
+                       ustack->uip_listenports[c] = port;
+                       return;
+               }
+       }
+}
+
+/**
+ * Is new incoming data available?
+ *
+ * Will reduce to non-zero if there is new data for the application
+ * present at the uip_appdata pointer. The size of the data is
+ * avaliable through the uip_len variable.
+ *
+ * \hideinitializer
+ */
+int uip_newdata(struct uip_stack *ustack)
+{
+       return ustack->uip_flags & UIP_NEWDATA;
+}
+
+/**
+ * Has previously sent data been acknowledged?
+ *
+ * Will reduce to non-zero if the previously sent data has been
+ * acknowledged by the remote host. This means that the application
+ * can send new data.
+ *
+ * \hideinitializer
+ */
+#define uip_acked()   (uip_flags & UIP_ACKDATA)
+
+/**
+ * Has the connection just been connected?
+ *
+ * Reduces to non-zero if the current connection has been connected to
+ * a remote host. This will happen both if the connection has been
+ * actively opened (with uip_connect()) or passively opened (with
+ * uip_listen()).
+ *
+ * \hideinitializer
+ */
+int uip_connected(struct uip_stack *ustack)
+{
+       return ustack->uip_flags & UIP_CONNECTED;
+}
+
+/**
+ * Has the connection been closed by the other end?
+ *
+ * Is non-zero if the connection has been closed by the remote
+ * host. The application may then do the necessary clean-ups.
+ *
+ * \hideinitializer
+ */
+int uip_closed(struct uip_stack *ustack)
+{
+       return ustack->uip_flags & UIP_CLOSE;
+}
+
+/**
+ * Has the connection been aborted by the other end?
+ *
+ * Non-zero if the current connection has been aborted (reset) by the
+ * remote host.
+ *
+ * \hideinitializer
+ */
+int uip_aborted(struct uip_stack *ustack)
+{
+       return ustack->uip_flags & UIP_ABORT;
+}
+
+/**
+ * Has the connection timed out?
+ *
+ * Non-zero if the current connection has been aborted due to too many
+ * retransmissions.
+ *
+ * \hideinitializer
+ */
+int uip_timedout(struct uip_stack *ustack)
+{
+       return ustack->uip_flags & UIP_TIMEDOUT;
+}
+
+/**
+ * Do we need to retransmit previously data?
+ *
+ * Reduces to non-zero if the previously sent data has been lost in
+ * the network, and the application should retransmit it. The
+ * application should send the exact same data as it did the last
+ * time, using the uip_send() function.
+ *
+ * \hideinitializer
+ */
+int uip_rexmit(struct uip_stack *ustack)
+{
+       return ustack->uip_flags & UIP_REXMIT;
+}
+
+/**
+ * Is the connection being polled by uIP?
+ *
+ * Is non-zero if the reason the application is invoked is that the
+ * current connection has been idle for a while and should be
+ * polled.
+ *
+ * The polling event can be used for sending data without having to
+ * wait for the remote host to send data.
+ *
+ * \hideinitializer
+ */
+int uip_poll(struct uip_stack *ustack)
+{
+       return ustack->uip_flags & UIP_POLL;
+}
+
+int uip_initialmss(struct uip_stack *ustack)
+{
+       return ustack->uip_conn->initialmss;
+}
+
+int uip_mss(struct uip_stack *ustack)
+{
+       return ustack->uip_conn->mss;
+}
+
+/*---------------------------------------------------------------------------*/
+/* XXX: IP fragment reassembly: not well-tested. */
+
+#if UIP_REASSEMBLY && !UIP_CONF_IPV6
+#define UIP_REASS_BUFSIZE (UIP_BUFSIZE - UIP_LLH_LEN)
+static u8_t uip_reassbuf[UIP_REASS_BUFSIZE];
+static u8_t uip_reassbitmap[UIP_REASS_BUFSIZE / (8 * 8)];
+static const u8_t bitmap_bits[8] = { 0xff, 0x7f, 0x3f, 0x1f,
+       0x0f, 0x07, 0x03, 0x01
+};
+static u16_t uip_reasslen;
+static u8_t uip_reassflags;
+#define UIP_REASS_FLAG_LASTFRAG 0x01
+static u8_t uip_reasstmr;
+
+#define IP_MF   0x20
+
+static u8_t uip_reass(void)
+{
+       u16_t offset, len;
+       u16_t i;
+
+       /* If ip_reasstmr is zero, no packet is present in the buffer, so we
+          write the IP header of the fragment into the reassembly
+          buffer. The timer is updated with the maximum age. */
+       if (uip_reasstmr == 0) {
+               memcpy(uip_reassbuf, &BUF(ustack)->vhl, uip_iph_len);
+               uip_reasstmr = UIP_REASS_MAXAGE;
+               uip_reassflags = 0;
+               /* Clear the bitmap. */
+               memset(uip_reassbitmap, 0, sizeof(uip_reassbitmap));
+       }
+
+       /* Check if the incoming fragment matches the one currently present
+          in the reasembly buffer. If so, we proceed with copying the
+          fragment into the buffer. */
+       if (BUF(ustack)->srcipaddr[0] == FBUF(ustack)->srcipaddr[0] &&
+           BUF(ustack)->srcipaddr[1] == FBUF(ustack)->srcipaddr[1] &&
+           BUF(ustack)->destipaddr[0] == FBUF(ustack)->destipaddr[0] &&
+           BUF(ustack)->destipaddr[1] == FBUF(ustack)->destipaddr[1] &&
+           BUF(ustack)->ipid[0] == FBUF(ustack)->ipid[0] &&
+           BUF(ustack)->ipid[1] == FBUF(ustack)->ipid[1]) {
+
+               len =
+                   (BUF(ustack)->len[0] << 8) + BUF(ustack)->len[1] -
+                   (BUF(ustack)->vhl & 0x0f) * 4;
+               offset =
+                   (((BUF(ustack)->ipoffset[0] & 0x3f) << 8) +
+                    BUF(ustack)->ipoffset[1]) * 8;
+
+               /* If the offset or the offset + fragment length overflows the
+                  reassembly buffer, we discard the entire packet. */
+               if (offset > UIP_REASS_BUFSIZE ||
+                   offset + len > UIP_REASS_BUFSIZE) {
+                       uip_reasstmr = 0;
+                       goto nullreturn;
+               }
+
+               /* Copy the fragment into the reassembly buffer, at the right
+                  offset. */
+               memcpy(&uip_reassbuf[uip_iph_len + offset],
+                      (char *)BUF + (int)((BUF(ustack)->vhl & 0x0f) * 4), len);
+
+               /* Update the bitmap. */
+               if (offset / (8 * 8) == (offset + len) / (8 * 8)) {
+                       /* If the two endpoints are in the same byte, we only
+                          update that byte. */
+
+                       uip_reassbitmap[offset / (8 * 8)] |=
+                           bitmap_bits[(offset / 8) & 7] &
+                           ~bitmap_bits[((offset + len) / 8) & 7];
+               } else {
+                       /* If the two endpoints are in different bytes, we
+                          update the bytes in the endpoints and fill the
+                          stuff inbetween with 0xff. */
+                       uip_reassbitmap[offset / (8 * 8)] |=
+                           bitmap_bits[(offset / 8) & 7];
+                       for (i = 1 + offset / (8 * 8);
+                            i < (offset + len) / (8 * 8); ++i) {
+                               uip_reassbitmap[i] = 0xff;
+                       }
+                       uip_reassbitmap[(offset + len) / (8 * 8)] |=
+                           ~bitmap_bits[((offset + len) / 8) & 7];
+               }
+
+               /* If this fragment has the More Fragments flag set to zero, we
+                  know that this is the last fragment, so we can calculate the
+                  size of the entire packet. We also set the
+                  IP_REASS_FLAG_LASTFRAG flag to indicate that we have received
+                  the final fragment. */
+
+               if ((BUF(ustack)->ipoffset[0] & IP_MF) == 0) {
+                       uip_reassflags |= UIP_REASS_FLAG_LASTFRAG;
+                       uip_reasslen = offset + len;
+               }
+
+               /* Finally, we check if we have a full packet in the buffer.
+                  We do this by checking if we have the last fragment and if
+                  all bits in the bitmap are set. */
+               if (uip_reassflags & UIP_REASS_FLAG_LASTFRAG) {
+                       /* Check all bytes up to and including all but the last
+                          byte in the bitmap. */
+                       for (i = 0; i < uip_reasslen / (8 * 8) - 1; ++i) {
+                               if (uip_reassbitmap[i] != 0xff)
+                                       goto nullreturn;
+                       }
+                       /* Check the last byte in the bitmap. It should contain
+                          just the right amount of bits. */
+                       if (uip_reassbitmap[uip_reasslen / (8 * 8)] !=
+                           (u8_t) ~bitmap_bits[uip_reasslen / 8 & 7])
+                               goto nullreturn;
+
+                       /* If we have come this far, we have a full packet in
+                          the buffer, so we allocate a pbuf and copy the
+                          packet into it. We also reset the timer. */
+                       uip_reasstmr = 0;
+                       memcpy(BUF, FBUF, uip_reasslen);
+
+                       /* Pretend to be a "normal" (i.e., not fragmented) IP
+                          packet from now on. */
+                       BUF(ustack)->ipoffset[0] = BUF(ustack)->ipoffset[1] = 0;
+                       BUF(ustack)->len[0] = uip_reasslen >> 8;
+                       BUF(ustack)->len[1] = uip_reasslen & 0xff;
+                       BUF(ustack)->ipchksum = 0;
+                       BUF(ustack)->ipchksum = ~(uip_ipchksum());
+
+                       return uip_reasslen;
+               }
+       }
+
+nullreturn:
+       return 0;
+}
+#endif /* UIP_REASSEMBLY */
+/*---------------------------------------------------------------------------*/
+static void uip_add_rcv_nxt(struct uip_stack *ustack, u16_t n)
+{
+       u8_t uip_acc32[4];
+
+       uip_add32(ustack->uip_conn->rcv_nxt, n, uip_acc32);
+       ustack->uip_conn->rcv_nxt[0] = uip_acc32[0];
+       ustack->uip_conn->rcv_nxt[1] = uip_acc32[1];
+       ustack->uip_conn->rcv_nxt[2] = uip_acc32[2];
+       ustack->uip_conn->rcv_nxt[3] = uip_acc32[3];
+}
+
+/*---------------------------------------------------------------------------*/
+
+/** @} */
+
+/**
+ * \defgroup uipdevfunc uIP device driver functions
+ * @{
+ *
+ * These functions are used by a network device driver for interacting
+ * with uIP.
+ */
+
+/**
+ * Process an incoming packet.
+ *
+ * This function should be called when the device driver has received
+ * a packet from the network. The packet from the device driver must
+ * be present in the uip_buf buffer, and the length of the packet
+ * should be placed in the uip_len variable.
+ *
+ * When the function returns, there may be an outbound packet placed
+ * in the uip_buf packet buffer. If so, the uip_len variable is set to
+ * the length of the packet. If no packet is to be sent out, the
+ * uip_len variable is set to 0.
+ *
+ * The usual way of calling the function is presented by the source
+ * code below.
+ \code
+       uip_len = devicedriver_poll();
+       if(uip_len > 0) {
+               uip_input();
+               if(uip_len > 0) {
+                       devicedriver_send();
+               }
+       }
+ \endcode
+ *
+ * \note If you are writing a uIP device driver that needs ARP
+ * (Address Resolution Protocol), e.g., when running uIP over
+ * Ethernet, you will need to call the uIP ARP code before calling
+ * this function:
+ \code
+  #define BUF ((struct uip_eth_hdr *)&uip_buf[0])
+  uip_len = ethernet_devicedrver_poll();
+  if(uip_len > 0) {
+       if (BUF(ustack)->type == HTONS(UIP_ETHTYPE_IP)) {
+               uip_arp_ipin();
+               uip_input();
+               if (uip_len > 0) {
+                       uip_arp_out();
+                       ethernet_devicedriver_send();
+               }
+       } else if (BUF(ustack)->type == HTONS(UIP_ETHTYPE_ARP)) {
+               uip_arp_arpin();
+               if (uip_len > 0)
+                       ethernet_devicedriver_send();
+       }
+ \endcode
+ *
+ * \hideinitializer
+ */
+void uip_input(struct uip_stack *ustack)
+{
+       uip_process(ustack, UIP_DATA);
+}
+
+/**
+ * Periodic processing for a connection identified by its number.
+ *
+ * This function does the necessary periodic processing (timers,
+ * polling) for a uIP TCP conneciton, and should be called when the
+ * periodic uIP timer goes off. It should be called for every
+ * connection, regardless of whether they are open of closed.
+ *
+ * When the function returns, it may have an outbound packet waiting
+ * for service in the uIP packet buffer, and if so the uip_len
+ * variable is set to a value larger than zero. The device driver
+ * should be called to send out the packet.
+ *
+ * The ususal way of calling the function is through a for() loop like
+ * this:
+ \code
+       for(i = 0; i < UIP_CONNS; ++i) {
+               uip_periodic(i);
+               if(uip_len > 0) {
+                       devicedriver_send();
+               }
+       }
+ \endcode
+ *
+ * \note If you are writing a uIP device driver that needs ARP
+ * (Address Resolution Protocol), e.g., when running uIP over
+ * Ethernet, you will need to call the uip_arp_out() function before
+ * calling the device driver:
+ \code
+       for(i = 0; i < UIP_CONNS; ++i) {
+               uip_periodic(i);
+               if(uip_len > 0) {
+                       uip_arp_out();
+                       ethernet_devicedriver_send();
+               }
+       }
+ \endcode
+ *
+ * \param conn The number of the connection which is to be periodically polled.
+ *
+ * \hideinitializer
+ */
+void uip_periodic(struct uip_stack *ustack, int conn)
+{
+       ustack->uip_conn = &ustack->uip_conns[conn];
+       uip_process(ustack, UIP_TIMER);
+}
+
+#if UIP_UDP
+/**
+ * Periodic processing for a UDP connection identified by its number.
+ *
+ * This function is essentially the same as uip_periodic(), but for
+ * UDP connections. It is called in a similar fashion as the
+ * uip_periodic() function:
+ \code
+  for(i = 0; i < UIP_UDP_CONNS; i++) {
+    uip_udp_periodic(i);
+    if(uip_len > 0) {
+      devicedriver_send();
+    }
+  }
+ \endcode
+ *
+ * \note As for the uip_periodic() function, special care has to be
+ * taken when using uIP together with ARP and Ethernet:
+ \code
+  for(i = 0; i < UIP_UDP_CONNS; i++) {
+    uip_udp_periodic(i);
+    if(uip_len > 0) {
+      uip_arp_out();
+      ethernet_devicedriver_send();
+    }
+  }
+ \endcode
+ *
+ * \param conn The number of the UDP connection to be processed.
+ *
+ * \hideinitializer
+ */
+void uip_udp_periodic(struct uip_stack *ustack, int conn)
+{
+       ustack->uip_udp_conn = &ustack->uip_udp_conns[conn];
+       uip_process(ustack, UIP_UDP_TIMER);
+}
+#endif
+
+void uip_ndp_periodic(struct uip_stack *ustack)
+{
+       uip_process(ustack, UIP_NDP_TIMER);
+}
+
+void uip_process(struct uip_stack *ustack, u8_t flag)
+{
+       u8_t c;
+       u16_t tmp16;
+       register struct uip_conn *uip_connr = ustack->uip_conn;
+
+       u16_t uip_iph_len = 0;
+       u16_t uip_ip_udph_len = 0;
+       u16_t uip_ip_tcph_len = 0;
+       struct ip6_hdr *ipv6_hdr = NULL;
+       struct uip_tcp_ipv4_hdr *tcp_ipv4_hdr = NULL;
+       struct uip_tcp_hdr *tcp_hdr = NULL;
+       struct uip_icmpv4_hdr *icmpv4_hdr = NULL;
+       struct uip_icmpv6_hdr *icmpv6_hdr __attribute__((__unused__)) = NULL;
+       struct uip_udp_hdr *udp_hdr = NULL;
+
+       /*  Drop invalid packets */
+       if (ustack->uip_buf == NULL) {
+               LOG_ERR(PFX "ustack->uip_buf == NULL.");
+               return;
+       }
+
+       if (is_ipv6(ustack)) {
+               uint8_t *buf;
+               uip_iph_len = UIP_IPv6_H_LEN;
+               uip_ip_udph_len = UIP_IPv6_UDPH_LEN;
+               uip_ip_tcph_len = UIP_IPv6_TCPH_LEN;
+
+               ipv6_hdr = (struct ip6_hdr *)ustack->network_layer;
+
+               buf = ustack->network_layer;
+               buf += sizeof(struct uip_ipv6_hdr);
+               tcp_hdr = (struct uip_tcp_hdr *)buf;
+
+               buf = ustack->network_layer;
+               buf += sizeof(struct uip_ipv6_hdr);
+               udp_hdr = (struct uip_udp_hdr *)buf;
+
+               buf = ustack->network_layer;
+               buf += sizeof(struct uip_ipv6_hdr);
+               icmpv6_hdr = (struct uip_icmpv6_hdr *)buf;
+       } else {
+               uint8_t *buf;
+
+               uip_iph_len = UIP_IPv4_H_LEN;
+               uip_ip_udph_len = UIP_IPv4_UDPH_LEN;
+               uip_ip_tcph_len = UIP_IPv4_TCPH_LEN;
+
+               tcp_ipv4_hdr = (struct uip_tcp_ipv4_hdr *)ustack->network_layer;
+
+               buf = ustack->network_layer;
+               buf += sizeof(struct uip_ipv4_hdr);
+               tcp_hdr = (struct uip_tcp_hdr *)buf;
+
+               buf = ustack->network_layer;
+               buf += sizeof(struct uip_ipv4_hdr);
+               icmpv4_hdr = (struct uip_icmpv4_hdr *)buf;
+
+               buf = ustack->network_layer;
+               buf += sizeof(struct uip_ipv4_hdr);
+               udp_hdr = (struct uip_udp_hdr *)buf;
+       }                       /* End of ipv6 */
+
+#if UIP_UDP
+       if (flag == UIP_UDP_SEND_CONN)
+               goto udp_send;
+#endif /* UIP_UDP */
+       ustack->uip_sappdata = ustack->uip_appdata = ustack->network_layer +
+           uip_ip_tcph_len;
+
+       /* Check if we were invoked because of a poll request for a
+          particular connection. */
+       if (flag == UIP_POLL_REQUEST) {
+               if ((uip_connr->tcpstateflags & UIP_TS_MASK) == UIP_ESTABLISHED
+                   && !uip_outstanding(uip_connr)) {
+                       ustack->uip_flags = UIP_POLL;
+                       UIP_APPCALL(ustack);
+                       goto appsend;
+               }
+               goto drop;
+
+               /* Check if we were invoked because of the perodic timer
+                  firing. */
+       } else if (flag == UIP_TIMER) {
+#if UIP_REASSEMBLY
+               if (uip_reasstmr != 0)
+                       --uip_reasstmr;
+#endif /* UIP_REASSEMBLY */
+               /* Increase the initial sequence number. */
+               if (++ustack->iss[3] == 0) {
+                       if (++ustack->iss[2] == 0) {
+                               if (++ustack->iss[1] == 0)
+                                       ++ustack->iss[0];
+                       }
+               }
+
+               /* Reset the length variables. */
+               ustack->uip_len = 0;
+               ustack->uip_slen = 0;
+
+               /* Check if the connection is in a state in which we simply wait
+                  for the connection to time out. If so, we increase the
+                  connection's timer and remove the connection if it times
+                  out. */
+               if (uip_connr->tcpstateflags == UIP_TIME_WAIT ||
+                   uip_connr->tcpstateflags == UIP_FIN_WAIT_2) {
+                       ++(uip_connr->timer);
+                       if (uip_connr->timer == UIP_TIME_WAIT_TIMEOUT)
+                               uip_connr->tcpstateflags = UIP_CLOSED;
+               } else if (uip_connr->tcpstateflags != UIP_CLOSED) {
+                       /* If the connection has outstanding data, we increase
+                          the connection's timer and see if it has reached the
+                          RTO value in which case we retransmit. */
+                       if (uip_outstanding(uip_connr)) {
+                               if (uip_connr->timer-- == 0) {
+                                       if (uip_connr->nrtx == UIP_MAXRTX ||
+                                           ((uip_connr->tcpstateflags ==
+                                             UIP_SYN_SENT
+                                             || uip_connr->tcpstateflags ==
+                                             UIP_SYN_RCVD)
+                                            && uip_connr->nrtx ==
+                                            UIP_MAXSYNRTX)) {
+                                               uip_connr->tcpstateflags =
+                                                   UIP_CLOSED;
+
+                                               /* We call UIP_APPCALL() with
+                                                  uip_flags set to UIP_TIMEDOUT
+                                                  to inform the application
+                                                  that the connection has timed
+                                                  out. */
+                                               ustack->uip_flags =
+                                                   UIP_TIMEDOUT;
+                                               UIP_APPCALL(ustack);
+
+                                               /* We also send a reset packet
+                                                  to the remote host. */
+                                               tcp_hdr->flags =
+                                                   TCP_RST | TCP_ACK;
+                                               goto tcp_send_nodata;
+                                       }
+
+                                       /* Exponential backoff. */
+                                       uip_connr->timer =
+                                           UIP_RTO << (uip_connr->nrtx >
+                                                       4 ? 4 : uip_connr->
+                                                       nrtx);
+                                       ++(uip_connr->nrtx);
+
+                                       /* Ok, so we need to retransmit.
+                                          We do this differently depending on
+                                          which state we are in.
+                                          In ESTABLISHED, we call upon the
+                                          application so that it may prepare
+                                          the data for the retransmit.
+                                          In SYN_RCVD, we resend the SYNACK
+                                          that we sent earlier and in LAST_ACK
+                                          we have to retransmit our FINACK. */
+                                       ++ustack->stats.tcp.rexmit;
+                                       switch (uip_connr->
+                                               tcpstateflags & UIP_TS_MASK) {
+                                       case UIP_SYN_RCVD:
+                                               /* In the SYN_RCVD state, we
+                                                  should retransmit our SYNACK
+                                                */
+                                               goto tcp_send_synack;
+#if UIP_ACTIVE_OPEN
+                                       case UIP_SYN_SENT:
+                                               /* In the SYN_SENT state,
+                                                  we retransmit out SYN. */
+                                               tcp_hdr->flags = 0;
+                                               goto tcp_send_syn;
+#endif /* UIP_ACTIVE_OPEN */
+
+                                       case UIP_ESTABLISHED:
+                                               /* In the ESTABLISHED state,
+                                                  we call upon the application
+                                                  to do the actual retransmit
+                                                  after which we jump into
+                                                  the code for sending out the
+                                                  packet (the apprexmit
+                                                  label). */
+                                               ustack->uip_flags = UIP_REXMIT;
+                                               UIP_APPCALL(ustack);
+                                               goto apprexmit;
+
+                                       case UIP_FIN_WAIT_1:
+                                       case UIP_CLOSING:
+                                       case UIP_LAST_ACK:
+                                               /* In all these states we should
+                                                  retransmit a FINACK. */
+                                               goto tcp_send_finack;
+
+                                       }
+                               }
+                       } else if ((uip_connr->tcpstateflags & UIP_TS_MASK) ==
+                                  UIP_ESTABLISHED) {
+                               /* If there was no need for a retransmission,
+                                  we poll the application for new data. */
+                               ustack->uip_flags = UIP_POLL;
+                               UIP_APPCALL(ustack);
+                               goto appsend;
+                       }
+               }
+               goto drop;
+       }                       /* End of UIP_TIMER */
+#if UIP_UDP
+       if (flag == UIP_UDP_TIMER) {
+               /* This is for IPv4 DHCP only! */
+               if (ustack->uip_udp_conn->lport != 0) {
+                       ustack->uip_conn = NULL;
+                       ustack->uip_sappdata = ustack->uip_appdata =
+                           ustack->network_layer + uip_ip_udph_len;
+                       ustack->uip_len = ustack->uip_slen = 0;
+                       ustack->uip_flags = UIP_POLL;
+                       UIP_UDP_APPCALL(ustack);
+                       goto udp_send;
+               } else {
+                       goto drop;
+               }
+       }
+#endif
+       if (flag == UIP_NDP_TIMER) {
+               /* This is for IPv6 NDP Only! */
+               if (1) {        /* If NDP engine active */
+                       ustack->uip_len = ustack->uip_slen = 0;
+                       ustack->uip_flags = UIP_POLL;
+                       goto ndp_send;
+               }
+       }
+
+       /* This is where the input processing starts. */
+       ++ustack->stats.ip.recv;
+
+       /* Start of IP input header processing code. */
+
+       if (is_ipv6(ustack)) {
+               u8_t version = ((ipv6_hdr->ip6_vfc) & 0xf0) >> 4;
+
+               /* Check validity of the IP header. */
+               if (version != 0x6) {   /* IP version and header length. */
+                       ++ustack->stats.ip.drop;
+                       ++ustack->stats.ip.vhlerr;
+                       LOG_DEBUG(PFX "ipv6: invalid version(0x%x).", version);
+                       goto drop;
+               }
+       } else {
+               /* Check validity of the IP header. */
+               if (tcp_ipv4_hdr->vhl != 0x45) {
+                       /* IP version and header length. */
+                       ++ustack->stats.ip.drop;
+                       ++ustack->stats.ip.vhlerr;
+                       LOG_DEBUG(PFX
+                                 "ipv4: invalid version or header length: "
+                                 "0x%x.",
+                                 tcp_ipv4_hdr->vhl);
+                       goto drop;
+               }
+       }
+
+       /* Check the size of the packet. If the size reported to us in
+          uip_len is smaller the size reported in the IP header, we assume
+          that the packet has been corrupted in transit. If the size of
+          uip_len is larger than the size reported in the IP packet header,
+          the packet has been padded and we set uip_len to the correct
+          value.. */
+
+       if (is_ipv6(ustack)) {
+               u16_t len = ntohs(ipv6_hdr->ip6_plen);
+               if (len > ustack->uip_len) {
+                       LOG_DEBUG(PFX
+                                "ip: packet shorter than reported in IP header"
+                                ":IPv6_BUF(ustack)->len: %d ustack->uip_len: "
+                                "%d", len, ustack->uip_len);
+                       goto drop;
+               }
+       } else {
+               if ((tcp_ipv4_hdr->len[0] << 8) +
+                   tcp_ipv4_hdr->len[1] <= ustack->uip_len) {
+                       ustack->uip_len = (tcp_ipv4_hdr->len[0] << 8) +
+                           tcp_ipv4_hdr->len[1];
+               } else {
+                       LOG_DEBUG(PFX
+                                "ip: packet shorter than reported in IP header"
+                                ":tcp_ipv4_hdr->len: %d ustack->uip_len:%d.",
+                                (tcp_ipv4_hdr->len[0] << 8) +
+                                tcp_ipv4_hdr->len[1], ustack->uip_len);
+                       goto drop;
+               }
+       }
+
+       if (!is_ipv6(ustack)) {
+               /* Check the fragment flag. */
+               if ((tcp_ipv4_hdr->ipoffset[0] & 0x3f) != 0 ||
+                   tcp_ipv4_hdr->ipoffset[1] != 0) {
+#if UIP_REASSEMBLY
+                       uip_len = uip_reass();
+                       if (uip_len == 0)
+                               goto drop;
+#else /* UIP_REASSEMBLY */
+                       ++ustack->stats.ip.drop;
+                       ++ustack->stats.ip.fragerr;
+                       LOG_WARN(PFX "ip: fragment dropped.");
+                       goto drop;
+#endif /* UIP_REASSEMBLY */
+               }
+       }
+
+       if (!is_ipv6(ustack)) {
+               /* ipv4 */
+               if (uip_ip4addr_cmp(ustack->hostaddr, all_zeroes_addr4)) {
+                       /* If we are configured to use ping IP address
+                          configuration and hasn't been assigned an IP
+                          address yet, we accept all ICMP packets. */
+#if UIP_PINGADDRCONF && !UIP_CONF_IPV6
+                       if (tcp_ipv4_hdr->proto == UIP_PROTO_ICMP) {
+                               LOG_WARN(PFX
+                                        "ip: possible ping config packet "
+                                        "received.");
+                               goto icmp_input;
+                       } else {
+                               LOG_WARN(PFX
+                                        "ip: packet dropped since no "
+                                        "address assigned.");
+                               goto drop;
+                       }
+#endif /* UIP_PINGADDRCONF */
+               } else {
+                       int broadcast_addr = 0xFFFFFFFF;
+                       /* If IP broadcast support is configured, we check for
+                          a broadcast UDP packet, which may be destined to us
+                        */
+                       if ((tcp_ipv4_hdr->proto == UIP_PROTO_UDP) &&
+                           (uip_ip4addr_cmp
+                            (tcp_ipv4_hdr->destipaddr, &broadcast_addr))
+                           /*&&
+                              uip_ipchksum() == 0xffff */
+                           ) {
+                               goto udp_input;
+                       }
+
+                       /* Check if the packet is destined for our IP address
+                        */
+                       if (!uip_ip4addr_cmp(tcp_ipv4_hdr->destipaddr,
+                                            ustack->hostaddr)) {
+                               ++ustack->stats.ip.drop;
+                               goto drop;
+                       }
+               }
+               if (uip_ipchksum(ustack) != 0xffff) {
+                       /* Compute and check the IP header checksum. */
+                       ++ustack->stats.ip.drop;
+                       ++ustack->stats.ip.chkerr;
+                       LOG_ERR(PFX "ip: bad checksum.");
+                       goto drop;
+               }
+       }  /* End of ipv4 */
+
+       if (is_ipv6(ustack)) {
+               if (ipv6_hdr->ip6_nxt == UIP_PROTO_TCP) {
+                       /* Check for TCP packet. If so, proceed with TCP input
+                          processing. */
+                       goto ndp_newdata;
+               }
+#if UIP_UDP
+               if (ipv6_hdr->ip6_nxt == UIP_PROTO_UDP)
+                       goto ndp_newdata;
+#endif /* UIP_UDP */
+
+               /* This is IPv6 ICMPv6 processing code. */
+               if (ipv6_hdr->ip6_nxt != UIP_PROTO_ICMP6) {
+                       /* We only allow ICMPv6 packets from here. */
+                       ++ustack->stats.ip.drop;
+                       ++ustack->stats.ip.protoerr;
+                       goto drop;
+               }
+
+               ++ustack->stats.icmp.recv;
+
+ndp_newdata:
+               /* This call is to handle the IPv6 Network Discovery Protocol */
+               ustack->uip_flags = UIP_NEWDATA;
+               ustack->uip_slen = 0;
+ndp_send:
+               UIP_NDP_CALL(ustack);
+               if (ustack->uip_slen != 0) {
+                       ustack->uip_len = ustack->uip_slen;
+                       goto send;
+               } else {
+                       goto drop;
+               }
+       } else {
+               /* IPv4 Processing */
+               if (tcp_ipv4_hdr->proto == UIP_PROTO_TCP) {
+                       /* Check for TCP packet. If so, proceed with TCP input
+                          processing. */
+                       goto tcp_input;
+               }
+#if UIP_UDP
+               if (tcp_ipv4_hdr->proto == UIP_PROTO_UDP)
+                       goto udp_input;
+#endif /* UIP_UDP */
+
+               /* ICMPv4 processing code follows. */
+               if (tcp_ipv4_hdr->proto != UIP_PROTO_ICMP) {
+                       /* We only allow ICMP packets from here. */
+                       ++ustack->stats.ip.drop;
+                       ++ustack->stats.ip.protoerr;
+                       LOG_DEBUG(PFX "ip: neither tcp nor icmp.");
+                       goto drop;
+               }
+#if UIP_PINGADDRCONF
+icmp_input:
+#endif /* UIP_PINGADDRCONF */
+               ++ustack->stats.icmp.recv;
+
+               if (icmpv4_hdr->type == ICMP_ECHO_REPLY) {
+                       if (process_icmp_packet(icmpv4_hdr, ustack) == 0)
+                               goto drop;
+               }
+
+               /* ICMP echo (i.e., ping) processing. This is simple, we only
+                  change the ICMP type from ECHO to ECHO_REPLY and adjust the
+                  ICMP checksum before we return the packet. */
+               if (icmpv4_hdr->type != ICMP_ECHO) {
+                       ++ustack->stats.icmp.drop;
+                       ++ustack->stats.icmp.typeerr;
+                       LOG_DEBUG(PFX "icmp: not icmp echo.");
+                       goto drop;
+               }
+
+               /* If we are configured to use ping IP address assignment, we
+                  use the destination IP address of this ping packet and assign
+                  it to ourself. */
+#if UIP_PINGADDRCONF
+               if ((ustack->hostaddr[0] | ustack->hostaddr[1]) == 0) {
+                       ustack->hostaddr[0] = tcp_ipv4_hdr->destipaddr[0];
+                       ustack->hostaddr[1] = tcp_ipv4_hdr->destipaddr[1];
+               }
+#endif /* UIP_PINGADDRCONF */
+
+               icmpv4_hdr->type = ICMP_ECHO_REPLY;
+
+               if (icmpv4_hdr->icmpchksum >= htons(0xffff -
+                                                   (ICMP_ECHO << 8))) {
+                       icmpv4_hdr->icmpchksum += htons(ICMP_ECHO << 8) + 1;
+               } else {
+                       icmpv4_hdr->icmpchksum += htons(ICMP_ECHO << 8);
+               }
+
+               /* Swap IP addresses. */
+               uip_ip4addr_copy(tcp_ipv4_hdr->destipaddr,
+                                tcp_ipv4_hdr->srcipaddr);
+               uip_ip4addr_copy(tcp_ipv4_hdr->srcipaddr, ustack->hostaddr);
+
+               ++ustack->stats.icmp.sent;
+               goto send;
+
+               /* End of IPv4 input header processing code. */
+       }
+
+#if UIP_UDP
+       /* UDP input processing. */
+udp_input:
+       /* UDP processing is really just a hack. We don't do anything to the
+          UDP/IP headers, but let the UDP application do all the hard
+          work. If the application sets uip_slen, it has a packet to
+          send. */
+#if UIP_UDP_CHECKSUMS
+       ustack->uip_len = ustack->uip_len - uip_ip_udph_len;
+       ustack->uip_appdata = ustack->network_layer + uip_ip_udph_len;
+       if (UDPBUF(ustack)->udpchksum != 0 && uip_udpchksum(ustack) != 0xffff) {
+               ++ustack->stats.udp.drop;
+               ++ustack->stats.udp.chkerr;
+               LOG_DEBUG(PFX "udp: bad checksum.");
+               goto drop;
+       }
+#else /* UIP_UDP_CHECKSUMS */
+       uip_len = uip_len - uip_ip_udph_len;
+#endif /* UIP_UDP_CHECKSUMS */
+
+       if (is_ipv6(ustack))
+               goto udp_found;
+
+       /* Demultiplex this UDP packet between the UDP "connections". */
+       for (ustack->uip_udp_conn = &ustack->uip_udp_conns[0];
+            ustack->uip_udp_conn < &ustack->uip_udp_conns[UIP_UDP_CONNS];
+            ++ustack->uip_udp_conn) {
+               /* If the local UDP port is non-zero, the connection is
+                  considered to be used. If so, the local port number is
+                  checked against the destination port number in the
+                  received packet. If the two port
+                  numbers match, the remote port number is checked if the
+                  connection is bound to a remote port. Finally, if the
+                  connection is bound to a remote IP address, the source IP
+                  address of the packet is checked. */
+
+               if (ustack->uip_udp_conn->lport != 0 &&
+                   UDPBUF(ustack)->destport == ustack->uip_udp_conn->lport &&
+                   (ustack->uip_udp_conn->rport == 0 ||
+                    UDPBUF(ustack)->srcport == ustack->uip_udp_conn->rport) &&
+                   (uip_ip4addr_cmp(ustack->uip_udp_conn->ripaddr,
+                                    all_zeroes_addr4) ||
+                    uip_ip4addr_cmp(ustack->uip_udp_conn->ripaddr,
+                                    all_ones_addr4) ||
+                    uip_ip4addr_cmp(tcp_ipv4_hdr->srcipaddr,
+                                    ustack->uip_udp_conn->ripaddr))) {
+                       goto udp_found;
+               }
+       }
+       LOG_DEBUG(PFX
+                 "udp: no matching connection found: dest port: %d src port: "
+                 "%d", udp_hdr->destport, udp_hdr->srcport);
+       goto drop;
+
+udp_found:
+       ustack->uip_conn = NULL;
+       ustack->uip_flags = UIP_NEWDATA;
+       ustack->uip_sappdata = ustack->uip_appdata = ustack->network_layer +
+           uip_ip_udph_len;
+       ustack->uip_slen = 0;
+       if (is_ipv6(ustack))
+               UIP_NDP_CALL(ustack);
+       else
+               UIP_UDP_APPCALL(ustack);
+udp_send:
+       if (ustack->uip_slen == 0)
+               goto drop;
+
+       ustack->uip_len = ustack->uip_slen + uip_ip_udph_len;
+
+       if (is_ipv6(ustack)) {
+               goto ip_send_nolen;
+       } else {
+               tcp_ipv4_hdr->len[0] = (ustack->uip_len >> 8);
+               tcp_ipv4_hdr->len[1] = (ustack->uip_len & 0xff);
+               tcp_ipv4_hdr->ttl = ustack->uip_udp_conn->ttl;
+               tcp_ipv4_hdr->proto = UIP_PROTO_UDP;
+       }
+
+       udp_hdr->udplen = htons(ustack->uip_slen + UIP_UDPH_LEN);
+       udp_hdr->udpchksum = 0;
+
+       udp_hdr->srcport = ustack->uip_udp_conn->lport;
+       udp_hdr->destport = ustack->uip_udp_conn->rport;
+
+       uip_ip4addr_copy(tcp_ipv4_hdr->srcipaddr, ustack->hostaddr);
+       uip_ip4addr_copy(tcp_ipv4_hdr->destipaddr,
+                        ustack->uip_udp_conn->ripaddr);
+
+       ustack->uip_appdata = ustack->network_layer + uip_ip_tcph_len;
+
+       if (ustack->uip_buf == NULL) {
+               LOG_WARN(PFX "uip_buf == NULL on udp send");
+               goto drop;
+       }
+#if UIP_UDP_CHECKSUMS
+       /* Calculate UDP checksum. */
+       udp_hdr->udpchksum = ~(uip_udpchksum(ustack));
+       if (udp_hdr->udpchksum == 0)
+               udp_hdr->udpchksum = 0xffff;
+#endif /* UIP_UDP_CHECKSUMS */
+
+       goto ip_send_nolen;
+#endif /* UIP_UDP */
+
+       /* TCP input processing. */
+tcp_input:
+       ++ustack->stats.tcp.recv;
+
+       /* Start of TCP input header processing code. */
+
+       if (uip_tcpchksum(ustack) != 0xffff) {  /* Compute and check the TCP
+                                                  checksum. */
+               ++ustack->stats.tcp.drop;
+               ++ustack->stats.tcp.chkerr;
+               LOG_WARN(PFX "tcp: bad checksum.");
+               goto drop;
+       }
+
+       if (is_ipv6(ustack)) {
+               /* Demultiplex this segment. */
+               /* First check any active connections. */
+               for (uip_connr = &ustack->uip_conns[0];
+                    uip_connr <= &ustack->uip_conns[UIP_CONNS - 1];
+                    ++uip_connr) {
+                       if (uip_connr->tcpstateflags != UIP_CLOSED &&
+                           tcp_hdr->destport == uip_connr->lport &&
+                           tcp_hdr->srcport == uip_connr->rport &&
+                           uip_ip6addr_cmp(IPv6_BUF(ustack)->srcipaddr,
+                                           uip_connr->ripaddr)) {
+                               goto found;
+                       }
+               }
+       } else {
+               /* Demultiplex this segment. */
+               /* First check any active connections. */
+               for (uip_connr = &ustack->uip_conns[0];
+                    uip_connr <= &ustack->uip_conns[UIP_CONNS - 1];
+                    ++uip_connr) {
+                       if (uip_connr->tcpstateflags != UIP_CLOSED &&
+                           tcp_hdr->destport == uip_connr->lport &&
+                           tcp_hdr->srcport == uip_connr->rport &&
+                           uip_ip4addr_cmp(tcp_ipv4_hdr->srcipaddr,
+                                           uip_connr->ripaddr)) {
+                               goto found;
+                       }
+               }
+       }
+
+       /* If we didn't find and active connection that expected the packet,
+          either this packet is an old duplicate, or this is a SYN packet
+          destined for a connection in LISTEN. If the SYN flag isn't set,
+          it is an old packet and we send a RST. */
+       if ((tcp_hdr->flags & TCP_CTL) != TCP_SYN)
+               goto reset;
+
+       tmp16 = tcp_hdr->destport;
+       /* Next, check listening connections. */
+       for (c = 0; c < UIP_LISTENPORTS; ++c) {
+               if (tmp16 == ustack->uip_listenports[c])
+                       goto found_listen;
+       }
+
+       /* No matching connection found, so we send a RST packet. */
+       ++ustack->stats.tcp.synrst;
+reset:
+
+       /* We do not send resets in response to resets. */
+       if (tcp_hdr->flags & TCP_RST)
+               goto drop;
+
+       ++ustack->stats.tcp.rst;
+
+       tcp_hdr->flags = TCP_RST | TCP_ACK;
+       ustack->uip_len = uip_ip_tcph_len;
+       tcp_hdr->tcpoffset = 5 << 4;
+
+       /* Flip the seqno and ackno fields in the TCP header. */
+       c = tcp_hdr->seqno[3];
+       tcp_hdr->seqno[3] = tcp_hdr->ackno[3];
+       tcp_hdr->ackno[3] = c;
+
+       c = tcp_hdr->seqno[2];
+       tcp_hdr->seqno[2] = tcp_hdr->ackno[2];
+       tcp_hdr->ackno[2] = c;
+
+       c = tcp_hdr->seqno[1];
+       tcp_hdr->seqno[1] = tcp_hdr->ackno[1];
+       tcp_hdr->ackno[1] = c;
+
+       c = tcp_hdr->seqno[0];
+       tcp_hdr->seqno[0] = tcp_hdr->ackno[0];
+       tcp_hdr->ackno[0] = c;
+
+       /* We also have to increase the sequence number we are
+          acknowledging. If the least significant byte overflowed, we need
+          to propagate the carry to the other bytes as well. */
+       if (++tcp_hdr->ackno[3] == 0) {
+               if (++tcp_hdr->ackno[2] == 0) {
+                       if (++tcp_hdr->ackno[1] == 0)
+                               ++tcp_hdr->ackno[0];
+               }
+       }
+
+       /* Swap port numbers. */
+       tmp16 = tcp_hdr->srcport;
+       tcp_hdr->srcport = tcp_hdr->destport;
+       tcp_hdr->destport = tmp16;
+
+       /* Swap IP addresses. */
+       if (is_ipv6(ustack)) {
+               uip_ip6addr_copy(IPv6_BUF(ustack)->destipaddr,
+                                IPv6_BUF(ustack)->srcipaddr);
+               uip_ip6addr_copy(IPv6_BUF(ustack)->srcipaddr,
+                                ustack->hostaddr6);
+       } else {
+               uip_ip4addr_copy(tcp_ipv4_hdr->destipaddr,
+                                tcp_ipv4_hdr->srcipaddr);
+               uip_ip4addr_copy(tcp_ipv4_hdr->srcipaddr, ustack->hostaddr);
+       }
+
+       /* And send out the RST packet! */
+       goto tcp_send_noconn;
+
+       /* This label will be jumped to if we matched the incoming packet
+          with a connection in LISTEN. In that case, we should create a new
+          connection and send a SYNACK in return. */
+found_listen:
+       /* First we check if there are any connections avaliable. Unused
+          connections are kept in the same table as used connections, but
+          unused ones have the tcpstate set to CLOSED. Also, connections in
+          TIME_WAIT are kept track of and we'll use the oldest one if no
+          CLOSED connections are found. Thanks to Eddie C. Dost for a very
+          nice algorithm for the TIME_WAIT search. */
+       uip_connr = 0;
+       for (c = 0; c < UIP_CONNS; ++c) {
+               if (ustack->uip_conns[c].tcpstateflags == UIP_CLOSED) {
+                       uip_connr = &ustack->uip_conns[c];
+                       break;
+               }
+               if (ustack->uip_conns[c].tcpstateflags == UIP_TIME_WAIT) {
+                       if (uip_connr == 0 ||
+                           ustack->uip_conns[c].timer > uip_connr->timer) {
+                               uip_connr = &ustack->uip_conns[c];
+                       }
+               }
+       }
+
+       if (uip_connr == 0) {
+               /* All connections are used already, we drop packet and hope
+                  that the remote end will retransmit the packet at a time when
+                  we have more spare connections. */
+               ++ustack->stats.tcp.syndrop;
+               LOG_WARN(PFX "tcp: found no unused connections.");
+               goto drop;
+       }
+       ustack->uip_conn = uip_connr;
+
+       /* Fill in the necessary fields for the new connection. */
+       uip_connr->rto = uip_connr->timer = UIP_RTO;
+       uip_connr->sa = 0;
+       uip_connr->sv = 4;
+       uip_connr->nrtx = 0;
+       uip_connr->lport = tcp_hdr->destport;
+       uip_connr->rport = tcp_hdr->srcport;
+       if (is_ipv6(ustack)) {
+               uip_ip6addr_copy(uip_connr->ripaddr,
+                                IPv6_BUF(ustack)->srcipaddr);
+       } else {
+               uip_ip4addr_copy(uip_connr->ripaddr, tcp_ipv4_hdr->srcipaddr);
+       }
+       uip_connr->tcpstateflags = UIP_SYN_RCVD;
+
+       uip_connr->snd_nxt[0] = ustack->iss[0];
+       uip_connr->snd_nxt[1] = ustack->iss[1];
+       uip_connr->snd_nxt[2] = ustack->iss[2];
+       uip_connr->snd_nxt[3] = ustack->iss[3];
+       uip_connr->len = 1;
+
+       /* rcv_nxt should be the seqno from the incoming packet + 1. */
+       uip_connr->rcv_nxt[3] = tcp_hdr->seqno[3];
+       uip_connr->rcv_nxt[2] = tcp_hdr->seqno[2];
+       uip_connr->rcv_nxt[1] = tcp_hdr->seqno[1];
+       uip_connr->rcv_nxt[0] = tcp_hdr->seqno[0];
+       uip_add_rcv_nxt(ustack, 1);
+
+       /* Parse the TCP MSS option, if present. */
+       if ((tcp_hdr->tcpoffset & 0xf0) > 0x50) {
+               for (c = 0; c < ((tcp_hdr->tcpoffset >> 4) - 5) << 2;) {
+                       ustack->opt =
+                           ustack->uip_buf[uip_ip_tcph_len + UIP_LLH_LEN + c];
+                       if (ustack->opt == TCP_OPT_END) {
+                               /* End of options. */
+                               break;
+                       } else if (ustack->opt == TCP_OPT_NOOP) {
+                               ++c;
+                               /* NOP option. */
+                       } else if (ustack->opt == TCP_OPT_MSS &&
+                                  ustack->uip_buf[uip_ip_tcph_len +
+                                                  UIP_LLH_LEN + 1 + c] ==
+                                  TCP_OPT_MSS_LEN) {
+                               /* An MSS option with the right option length.*/
+                               tmp16 =
+                                   ((u16_t) ustack->
+                                    uip_buf[uip_ip_tcph_len + UIP_LLH_LEN + 2 +
+                                            c] << 8) | (u16_t) ustack->
+                                   uip_buf[uip_ip_tcph_len + UIP_LLH_LEN + 3 +
+                                           c];
+                               uip_connr->initialmss = uip_connr->mss =
+                                   tmp16 > UIP_TCP_MSS ? UIP_TCP_MSS : tmp16;
+
+                               /* And we are done processing options. */
+                               break;
+                       } else {
+                               /* All other options have a length field, so
+                                  that we easily can skip past them. */
+                               if (ustack->uip_buf[uip_ip_tcph_len + UIP_LLH_LEN + 1 + c] == 0) {
+                                       /* If the length field is zero, the
+                                          options are malformed
+                                          and we don't process them further. */
+                                       break;
+                               }
+                               if ((ustack->uip_buf[uip_ip_tcph_len + UIP_LLH_LEN + 1 + c]) > (256 - c)) {
+                                       /* u8 overflow, actually there should
+                                        * never be more than 40 bytes of options */
+                                       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;
+                                               }
+                                               if ((ustack->uip_buf[uip_ip_tcph_len
+                                                         + UIP_LLH_LEN + 1 +
+                                                         c]) > (256 - c)) {
+                                                       /* u8 overflow, actually there should
+                                                        * never be more than 40 bytes of
+                                                        * options */
+                                                       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 */
+                       tmp16 = (tcp_hdr->urgp[0] << 8) | tcp_hdr->urgp[1];
+                       if (tmp16 <= ustack->uip_len) {
+                               ustack->uip_appdata = ((char *)ustack->uip_appdata) + tmp16;
+                               ustack->uip_len -= tmp16;
+                       } else {
+                               /* invalid urgent pointer length greater than frame */
+                               /* we're discarding urgent data anyway, throw it all out */
+                               ustack->uip_appdata = ((char *)ustack->uip_appdata) + ustack->uip_len;
+                               ustack->uip_len = 0;
+                       }
+#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/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/uip.h b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/uip.h
new file mode 100644 (file)
index 0000000..9d9428a
--- /dev/null
@@ -0,0 +1,1574 @@
+
+/**
+ * \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];
+
+extern const uip_ip6addr_t all_zeroes_addr6;
+extern const uip_ip4addr_t all_zeroes_addr4;
+
+#define ETH_BUF(buf) ((struct uip_eth_hdr *)buf)
+#define VLAN_ETH_BUF(buf) ((struct uip_vlan_eth_hdr *)buf)
+#define IPv4_BUF(buf) ((struct uip_tcp_ipv4_hdr *)buf)
+#define IPv6_BUF(buf) ((struct uip_tcp_ipv6_hdr *)buf)
+
+/*---------------------------------------------------------------------------*/
+/* First, the functions that should be called from the
+ * system. Initialization, the periodic timer and incoming packets are
+ * handled by the following three functions.
+ */
+
+/**
+ * Set the IP address of this host.
+ *
+ * The IP address is represented as a 4-byte array where the first
+ * octet of the IP address is put in the first member of the 4-byte
+ * array.
+ *
+ * Example:
+ \code
+
+ uip_ipaddr_t addr;
+
+ uip_ipaddr(&addr, 192,168,1,2);
+ uip_sethostaddr(&addr);
+
+ \endcode
+ * \param addr A pointer to an IP address of type uip_ipaddr_t;
+ *
+ * \sa uip_ipaddr()
+ *
+ * \hideinitializer
+ */
+void uip_sethostaddr4(struct uip_stack *ustack, uip_ip4addr_t *addr);
+
+/**
+ * Set the default router's IP address.
+ *
+ * \param addr A pointer to a uip_ipaddr_t variable containing the IP
+ * address of the default router.
+ *
+ * \sa uip_ipaddr()
+ *
+ * \hideinitializer
+ */
+void uip_setdraddr4(struct uip_stack *ustack, uip_ip4addr_t *addr);
+
+/**
+ * Set the netmask.
+ *
+ * \param addr A pointer to a uip_ipaddr_t variable containing the IP
+ * address of the netmask.
+ *
+ * \sa uip_ipaddr()
+ *
+ * \hideinitializer
+ */
+void uip_setnetmask4(struct uip_stack *ustack, uip_ip4addr_t *addr);
+
+/**
+ * Set the ethernet MAC address.
+ *
+ * \param addr A pointer to a uip_ipaddr_t variable containing the IP
+ * address of the netmask.
+ *
+ * \sa uip_ipaddr()
+ *
+ * \hideinitializer
+ */
+void uip_setethernetmac(struct uip_stack *ustack, uint8_t *mac);
+
+/**
+ * Get the default router's IP address.
+ *
+ * \param addr A pointer to a uip_ipaddr_t variable that will be
+ * filled in with the IP address of the default router.
+ *
+ * \hideinitializer
+ */
+#define uip_getdraddr(addr) uip_ipaddr_copy((addr), uip_draddr)
+
+/**
+ * Get the netmask.
+ *
+ * \param addr A pointer to a uip_ipaddr_t variable that will be
+ * filled in with the value of the netmask.
+ *
+ * \hideinitializer
+ */
+#define uip_getnetmask(addr) uip_ipaddr_copy((addr), uip_netmask)
+
+void set_uip_stack(struct uip_stack *ustack,
+                  uip_ip4addr_t *ip,
+                  uip_ip4addr_t *netmask,
+                  uip_ip4addr_t *default_route, uint8_t *mac_addr);
+
+/** @} */
+
+/**
+ * \defgroup uipinit uIP initialization functions
+ * @{
+ *
+ * The uIP initialization functions are used for booting uIP.
+ */
+
+/**
+ * uIP initialization function.
+ *
+ * This function should be called at boot up to initilize the uIP
+ * TCP/IP stack.
+ */
+void uip_init(struct uip_stack *ustack, uint8_t enable_ipv6);
+
+/**
+ * uIP reset function.
+ *
+ * This function should be called at to reset the uIP TCP/IP stack.
+ */
+void uip_reset(struct uip_stack *ustack);
+
+/**
+ * uIP initialization function.
+ *
+ * This function may be used at boot time to set the initial ip_id.
+ */
+void uip_setipid(u16_t id);
+
+/**
+ *
+ *
+ */
+#define uip_conn_active(conn) (uip_conns[conn].tcpstateflags != UIP_CLOSED)
+
+#if UIP_UDP
+void uip_udp_periodic(struct uip_stack *ustack, int conn);
+#endif /* UIP_UDP */
+
+void uip_ndp_periodic(struct uip_stack *ustack);
+
+/**
+ * The uIP packet buffer.
+ *
+ * The uip_buf array is used to hold incoming and outgoing
+ * packets. The device driver should place incoming data into this
+ * buffer. When sending data, the device driver should read the link
+ * level headers and the TCP/IP headers from this buffer. The size of
+ * the link level headers is configured by the UIP_LLH_LEN define.
+ *
+ * \note The application data need not be placed in this buffer, so
+ * the device driver must read it from the place pointed to by the
+ * uip_appdata pointer as illustrated by the following example:
+ \code
+ void
+ devicedriver_send(void)
+ {
+    hwsend(&uip_buf[0], UIP_LLH_LEN);
+    if(uip_len <= UIP_LLH_LEN + UIP_TCPIP_HLEN) {
+      hwsend(&uip_buf[UIP_LLH_LEN], uip_len - UIP_LLH_LEN);
+    } else {
+      hwsend(&uip_buf[UIP_LLH_LEN], UIP_TCPIP_HLEN);
+      hwsend(uip_appdata, uip_len - UIP_TCPIP_HLEN - UIP_LLH_LEN);
+    }
+ }
+ \endcode
+ */
+/*extern u8_t uip_buf[UIP_BUFSIZE+2]; */
+
+/** @} */
+
+/*---------------------------------------------------------------------------*/
+/* Functions that are used by the uIP application program. Opening and
+ * closing connections, sending and receiving data, etc. is all
+ * handled by the functions below.
+*/
+/**
+ * \defgroup uipappfunc uIP application functions
+ * @{
+ *
+ * Functions used by an application running of top of uIP.
+ */
+
+/**
+ * Start listening to the specified port.
+ *
+ * \note Since this function expects the port number in network byte
+ * order, a conversion using HTONS() or htons() is necessary.
+ *
+ \code
+ uip_listen(HTONS(80));
+ \endcode
+ *
+ * \param port A 16-bit port number in network byte order.
+ */
+void uip_listen(struct uip_stack *ustack, u16_t port);
+
+/**
+ * Stop listening to the specified port.
+ *
+ * \note Since this function expects the port number in network byte
+ * order, a conversion using HTONS() or htons() is necessary.
+ *
+ \code
+ uip_unlisten(HTONS(80));
+ \endcode
+ *
+ * \param port A 16-bit port number in network byte order.
+ */
+void uip_unlisten(struct uip_stack *ustack, u16_t port);
+
+/**
+ * Connect to a remote host using TCP.
+ *
+ * This function is used to start a new connection to the specified
+ * port on the specied host. It allocates a new connection identifier,
+ * sets the connection to the SYN_SENT state and sets the
+ * retransmission timer to 0. This will cause a TCP SYN segment to be
+ * sent out the next time this connection is periodically processed,
+ * which usually is done within 0.5 seconds after the call to
+ * uip_connect().
+ *
+ * \note This function is avaliable only if support for active open
+ * has been configured by defining UIP_ACTIVE_OPEN to 1 in uipopt.h.
+ *
+ * \note Since this function requires the port number to be in network
+ * byte order, a conversion using HTONS() or htons() is necessary.
+ *
+ \code
+ uip_ipaddr_t ipaddr;
+
+ uip_ipaddr(&ipaddr, 192,168,1,2);
+ uip_connect(&ipaddr, HTONS(80));
+ \endcode
+ *
+ * \param ripaddr The IP address of the remote hot.
+ *
+ * \param port A 16-bit port number in network byte order.
+ *
+ * \return A pointer to the uIP connection identifier for the new connection,
+ * or NULL if no connection could be allocated.
+ *
+ */
+struct uip_conn *uip_connect(struct uip_stack *ustack,
+                            uip_ip4addr_t *ripaddr, u16_t port);
+
+/**
+ * \internal
+ *
+ * Check if a connection has outstanding (i.e., unacknowledged) data.
+ *
+ * \param conn A pointer to the uip_conn structure for the connection.
+ *
+ * \hideinitializer
+ */
+#define uip_outstanding(conn) ((conn)->len)
+
+/**
+ * Send data on the current connection.
+ *
+ * This function is used to send out a single segment of TCP
+ * data. Only applications that have been invoked by uIP for event
+ * processing can send data.
+ *
+ * The amount of data that actually is sent out after a call to this
+ * funcion is determined by the maximum amount of data TCP allows. uIP
+ * will automatically crop the data so that only the appropriate
+ * amount of data is sent. The function uip_mss() can be used to query
+ * uIP for the amount of data that actually will be sent.
+ *
+ * \note This function does not guarantee that the sent data will
+ * arrive at the destination. If the data is lost in the network, the
+ * application will be invoked with the uip_rexmit() event being
+ * set. The application will then have to resend the data using this
+ * function.
+ *
+ * \param data A pointer to the data which is to be sent.
+ *
+ * \param len The maximum amount of data bytes to be sent.
+ *
+ * \hideinitializer
+ */
+void uip_send(struct uip_stack *ustack, const void *data, int len);
+void uip_appsend(struct uip_stack *ustack, const void *data, int len);
+
+/**
+ * The length of any incoming data that is currently avaliable (if avaliable)
+ * in the uip_appdata buffer.
+ *
+ * The test function uip_data() must first be used to check if there
+ * is any data available at all.
+ *
+ * \hideinitializer
+ */
+/*void uip_datalen(void);*/
+u16_t uip_datalen(struct uip_stack *ustack);
+
+/**
+ * The length of any out-of-band data (urgent data) that has arrived
+ * on the connection.
+ *
+ * \note The configuration parameter UIP_URGDATA must be set for this
+ * function to be enabled.
+ *
+ * \hideinitializer
+ */
+#define uip_urgdatalen()    uip_urglen
+
+/**
+ * Close the current connection.
+ *
+ * This function will close the current connection in a nice way.
+ *
+ * \hideinitializer
+ */
+#define uip_close()         (uip_flags = UIP_CLOSE)
+
+/**
+ * Abort the current connection.
+ *
+ * This function will abort (reset) the current connection, and is
+ * usually used when an error has occured that prevents using the
+ * uip_close() function.
+ *
+ * \hideinitializer
+ */
+#define uip_abort()         (uip_flags = UIP_ABORT)
+
+/**
+ * Tell the sending host to stop sending data.
+ *
+ * This function will close our receiver's window so that we stop
+ * receiving data for the current connection.
+ *
+ * \hideinitializer
+ */
+#define uip_stop()          (uip_conn->tcpstateflags |= UIP_STOPPED)
+
+/**
+ * Find out if the current connection has been previously stopped with
+ * uip_stop().
+ *
+ * \hideinitializer
+ */
+#define uip_stopped(conn)   ((conn)->tcpstateflags & UIP_STOPPED)
+
+/**
+ * Restart the current connection, if is has previously been stopped
+ * with uip_stop().
+ *
+ * This function will open the receiver's window again so that we
+ * start receiving data for the current connection.
+ *
+ * \hideinitializer
+ */
+#define uip_restart()  do { uip_flags |= UIP_NEWDATA; \
+                               uip_conn->tcpstateflags &= ~UIP_STOPPED; \
+                       } while (0)
+
+/* uIP tests that can be made to determine in what state the current
+   connection is, and what the application function should do. */
+
+/**
+ * Is the current connection a UDP connection?
+ *
+ * This function checks whether the current connection is a UDP connection.
+ *
+ * \hideinitializer
+ *
+ */
+#define uip_udpconnection() (uip_conn == NULL)
+
+/**
+ *  Function declarations for hte uip_flags
+ */
+/**
+ * Is new incoming data available?
+ *
+ * Will reduce to non-zero if there is new data for the application
+ * present at the uip_appdata pointer. The size of the data is
+ * avaliable through the uip_len variable.
+ *
+ * \hideinitializer
+ */
+int uip_newdata(struct uip_stack *ustack);
+
+/**
+ * Has previously sent data been acknowledged?
+ *
+ * Will reduce to non-zero if the previously sent data has been
+ * acknowledged by the remote host. This means that the application
+ * can send new data.
+ *
+ * \hideinitializer
+ */
+int uip_acked(struct uip_stack *ustack);
+
+/**
+ * Has the connection just been connected?
+ *
+ * Reduces to non-zero if the current connection has been connected to
+ * a remote host. This will happen both if the connection has been
+ * actively opened (with uip_connect()) or passively opened (with
+ * uip_listen()).
+ *
+ * \hideinitializer
+ */
+int uip_connected(struct uip_stack *ustack);
+
+/**
+ * Has the connection been closed by the other end?
+ *
+ * Is non-zero if the connection has been closed by the remote
+ * host. The application may then do the necessary clean-ups.
+ *
+ * \hideinitializer
+ */
+int uip_closed(struct uip_stack *ustack);
+
+/**
+ * Has the connection been aborted by the other end?
+ *
+ * Non-zero if the current connection has been aborted (reset) by the
+ * remote host.
+ *
+ * \hideinitializer
+ */
+int uip_aborted(struct uip_stack *ustack);
+
+/**
+ * Has the connection timed out?
+ *
+ * Non-zero if the current connection has been aborted due to too many
+ * retransmissions.
+ *
+ * \hideinitializer
+ */
+int uip_timedout(struct uip_stack *ustack);
+
+/**
+ * Do we need to retransmit previously data?
+ *
+ * Reduces to non-zero if the previously sent data has been lost in
+ * the network, and the application should retransmit it. The
+ * application should send the exact same data as it did the last
+ * time, using the uip_send() function.
+ *
+ * \hideinitializer
+ */
+int uip_rexmit(struct uip_stack *ustack);
+
+/**
+ * Is the connection being polled by uIP?
+ *
+ * Is non-zero if the reason the application is invoked is that the
+ * current connection has been idle for a while and should be
+ * polled.
+ *
+ * The polling event can be used for sending data without having to
+ * wait for the remote host to send data.
+ *
+ * \hideinitializer
+ */
+int uip_poll(struct uip_stack *ustack);
+
+/**
+ * Get the initial maxium segment size (MSS) of the current
+ * connection.
+ *
+ * \hideinitializer
+ */
+int uip_initialmss(struct uip_stack *ustack);
+
+/**
+ * Get the current maxium segment size that can be sent on the current
+ * connection.
+ *
+ * The current maxiumum segment size that can be sent on the
+ * connection is computed from the receiver's window and the MSS of
+ * the connection (which also is available by calling
+ * uip_initialmss()).
+ *
+ * \hideinitializer
+ */
+int uip_mss(struct uip_stack *ustack);
+
+/**
+ * Set up a new UDP connection.
+ *
+ * This function sets up a new UDP connection. The function will
+ * automatically allocate an unused local port for the new
+ * connection. However, another port can be chosen by using the
+ * uip_udp_bind() call, after the uip_udp_new() function has been
+ * called.
+ *
+ * Example:
+ \code
+ uip_ipaddr_t addr;
+ struct uip_udp_conn *c;
+
+ uip_ipaddr(&addr, 192,168,2,1);
+ c = uip_udp_new(&addr, HTONS(12345));
+ if(c != NULL) {
+   uip_udp_bind(c, HTONS(12344));
+ }
+ \endcode
+ * \param ripaddr The IP address of the remote host.
+ *
+ * \param rport The remote port number in network byte order.
+ *
+ * \return The uip_udp_conn structure for the new connection or NULL
+ * if no connection could be allocated.
+ */
+struct uip_udp_conn *uip_udp_new(struct uip_stack *ustack,
+                                uip_ip4addr_t *ripaddr, u16_t rport);
+
+/**
+ * Removed a UDP connection.
+ *
+ * \param conn A pointer to the uip_udp_conn structure for the connection.
+ *
+ * \hideinitializer
+ */
+#define uip_udp_remove(conn) ((conn)->lport = 0)
+
+/**
+ * Bind a UDP connection to a local port.
+ *
+ * \param conn A pointer to the uip_udp_conn structure for the
+ * connection.
+ *
+ * \param port The local port number, in network byte order.
+ *
+ * \hideinitializer
+ */
+#define uip_udp_bind(conn, port) ((conn)->lport = port)
+
+/**
+ * Send a UDP datagram of length len on the current connection.
+ *
+ * This function can only be called in response to a UDP event (poll
+ * or newdata). The data must be present in the uip_buf buffer, at the
+ * place pointed to by the uip_appdata pointer.
+ *
+ * \param len The length of the data in the uip_buf buffer.
+ *
+ * \hideinitializer
+ */
+#define uip_udp_send(len) uip_appsend((char *)uip_appdata, len)
+
+/** @} */
+
+/* uIP convenience and converting functions. */
+
+/**
+ * \defgroup uipconvfunc uIP conversion functions
+ * @{
+ *
+ * These functions can be used for converting between different data
+ * formats used by uIP.
+ */
+
+/**
+ * Construct an IP address from four bytes.
+ *
+ * This function constructs an IP address of the type that uIP handles
+ * internally from four bytes. The function is handy for specifying IP
+ * addresses to use with e.g. the uip_connect() function.
+ *
+ * Example:
+ \code
+ uip_ipaddr_t ipaddr;
+ struct uip_conn *c;
+
+ uip_ipaddr(&ipaddr, 192,168,1,2);
+ c = uip_connect(&ipaddr, HTONS(80));
+ \endcode
+ *
+ * \param addr A pointer to a uip_ipaddr_t variable that will be
+ * filled in with the IP address.
+ *
+ * \param addr0 The first octet of the IP address.
+ * \param addr1 The second octet of the IP address.
+ * \param addr2 The third octet of the IP address.
+ * \param addr3 The forth octet of the IP address.
+ *
+ * \hideinitializer
+ */
+#define uip_ipaddr(addr, addr0, addr1, addr2, addr3) do { \
+               ((u16_t *)(addr))[0] = const_htons(((addr0) << 8) | (addr1)); \
+               ((u16_t *)(addr))[1] = const_htons(((addr2) << 8) | (addr3)); \
+       } while (0)
+
+/**
+ * Construct an IPv6 address from eight 16-bit words.
+ *
+ * This function constructs an IPv6 address.
+ *
+ * \hideinitializer
+ */
+#define uip_ip6addr(addr, addr0, addr1, addr2, addr3, addr4, addr5, addr6, \
+                   addr7)                              \
+       do {                                            \
+               ((u16_t *)(addr))[0] = HTONS((addr0));  \
+               ((u16_t *)(addr))[1] = HTONS((addr1));  \
+               ((u16_t *)(addr))[2] = HTONS((addr2));  \
+               ((u16_t *)(addr))[3] = HTONS((addr3));  \
+               ((u16_t *)(addr))[4] = HTONS((addr4));  \
+               ((u16_t *)(addr))[5] = HTONS((addr5));  \
+               ((u16_t *)(addr))[6] = HTONS((addr6));  \
+               ((u16_t *)(addr))[7] = HTONS((addr7));  \
+       } while (0)
+
+/**
+ * Copy an IP address to another IP address.
+ *
+ * Copies an IP address from one place to another.
+ *
+ * Example:
+ \code
+ uip_ipaddr_t ipaddr1, ipaddr2;
+
+ uip_ipaddr(&ipaddr1, 192,16,1,2);
+ uip_ipaddr_copy(&ipaddr2, &ipaddr1);
+ \endcode
+ *
+ * \param dest The destination for the copy.
+ * \param src The source from where to copy.
+ *
+ * \hideinitializer
+ */
+#define uip_ip4addr_copy(dest, src) memcpy(dest, src, sizeof(uip_ip4addr_t))
+#define uip_ip6addr_copy(dest, src) memcpy(dest, src, sizeof(uip_ip6addr_t))
+
+/**
+ * Compare two IP addresses
+ *
+ * Compares two IP addresses.
+ *
+ * Example:
+ \code
+ uip_ipaddr_t ipaddr1, ipaddr2;
+
+ uip_ipaddr(&ipaddr1, 192,16,1,2);
+ if(uip_ipaddr_cmp(&ipaddr2, &ipaddr1)) {
+    printf("They are the same");
+ }
+ \endcode
+ *
+ * \param addr1 The first IP address.
+ * \param addr2 The second IP address.
+ *
+ * \hideinitializer
+ */
+#define uip_ip4addr_cmp(addr1, addr2) (memcmp(addr1, addr2, \
+                                      sizeof(uip_ip4addr_t)) == 0)
+#define uip_ip6addr_cmp(addr1, addr2) (memcmp(addr1, addr2, \
+                                      sizeof(uip_ip6addr_t)) == 0)
+
+/**
+ * Compare two IP addresses with netmasks
+ *
+ * Compares two IP addresses with netmasks. The masks are used to mask
+ * out the bits that are to be compared.
+ *
+ * Example:
+ \code
+ uip_ipaddr_t ipaddr1, ipaddr2, mask;
+
+ uip_ipaddr(&mask, 255,255,255,0);
+ uip_ipaddr(&ipaddr1, 192,16,1,2);
+ uip_ipaddr(&ipaddr2, 192,16,1,3);
+ if(uip_ipaddr_maskcmp(&ipaddr1, &ipaddr2, &mask)) {
+    printf("They are the same");
+ }
+ \endcode
+ *
+ * \param addr1 The first IP address.
+ * \param addr2 The second IP address.
+ * \param mask The netmask.
+ *
+ * \hideinitializer
+ */
+#define uip_ip4addr_maskcmp(addr1, addr2, mask) \
+                       (((((u16_t *)addr1)[0] & ((u16_t *)mask)[0]) == \
+                       (((u16_t *)addr2)[0] & ((u16_t *)mask)[0])) && \
+                       ((((u16_t *)addr1)[1] & ((u16_t *)mask)[1]) == \
+                       (((u16_t *)addr2)[1] & ((u16_t *)mask)[1])))
+
+/**
+ * Mask out the network part of an IP address.
+ *
+ * Masks out the network part of an IP address, given the address and
+ * the netmask.
+ *
+ * Example:
+ \code
+ uip_ipaddr_t ipaddr1, ipaddr2, netmask;
+
+ uip_ipaddr(&ipaddr1, 192,16,1,2);
+ uip_ipaddr(&netmask, 255,255,255,0);
+ uip_ipaddr_mask(&ipaddr2, &ipaddr1, &netmask);
+ \endcode
+ *
+ * In the example above, the variable "ipaddr2" will contain the IP
+ * address 192.168.1.0.
+ *
+ * \param dest Where the result is to be placed.
+ * \param src The IP address.
+ * \param mask The netmask.
+ *
+ * \hideinitializer
+ */
+#define uip_ip4addr_mask(dest, src, mask) do { \
+               ((u16_t *)dest)[0] = ((u16_t *)src)[0] & ((u16_t *)mask)[0]; \
+               ((u16_t *)dest)[1] = ((u16_t *)src)[1] & ((u16_t *)mask)[1]; \
+       } while (0)
+
+/**
+ * Pick the first octet of an IP address.
+ *
+ * Picks out the first octet of an IP address.
+ *
+ * Example:
+ \code
+ uip_ipaddr_t ipaddr;
+ u8_t octet;
+
+ uip_ipaddr(&ipaddr, 1,2,3,4);
+ octet = uip_ipaddr1(&ipaddr);
+ \endcode
+ *
+ * In the example above, the variable "octet" will contain the value 1.
+ *
+ * \hideinitializer
+ */
+#define uip_ipaddr1(addr) (htons(((u16_t *)(addr))[0]) >> 8)
+
+/**
+ * Pick the second octet of an IP address.
+ *
+ * Picks out the second octet of an IP address.
+ *
+ * Example:
+ \code
+ uip_ipaddr_t ipaddr;
+ u8_t octet;
+
+ uip_ipaddr(&ipaddr, 1,2,3,4);
+ octet = uip_ipaddr2(&ipaddr);
+ \endcode
+ *
+ * In the example above, the variable "octet" will contain the value 2.
+ *
+ * \hideinitializer
+ */
+#define uip_ipaddr2(addr) (htons(((u16_t *)(addr))[0]) & 0xff)
+
+/**
+ * Pick the third octet of an IP address.
+ *
+ * Picks out the third octet of an IP address.
+ *
+ * Example:
+ \code
+ uip_ipaddr_t ipaddr;
+ u8_t octet;
+
+ uip_ipaddr(&ipaddr, 1,2,3,4);
+ octet = uip_ipaddr3(&ipaddr);
+ \endcode
+ *
+ * In the example above, the variable "octet" will contain the value 3.
+ *
+ * \hideinitializer
+ */
+#define uip_ipaddr3(addr) (htons(((u16_t *)(addr))[1]) >> 8)
+
+/**
+ * Pick the fourth octet of an IP address.
+ *
+ * Picks out the fourth octet of an IP address.
+ *
+ * Example:
+ \code
+ uip_ipaddr_t ipaddr;
+ u8_t octet;
+
+ uip_ipaddr(&ipaddr, 1,2,3,4);
+ octet = uip_ipaddr4(&ipaddr);
+ \endcode
+ *
+ * In the example above, the variable "octet" will contain the value 4.
+ *
+ * \hideinitializer
+ */
+#define uip_ipaddr4(addr) (htons(((u16_t *)(addr))[1]) & 0xff)
+
+/**
+ * Convert 16-bit quantity from host byte order to network byte order.
+ *
+ * This macro is primarily used for converting constants from host
+ * byte order to network byte order. For converting variables to
+ * network byte order, use the htons() function instead.
+ *
+ * \hideinitializer
+ */
+#if 0
+#ifndef HTONS
+#   if UIP_BYTE_ORDER == UIP_BIG_ENDIAN
+#      define HTONS(n) (n)
+#   else /* UIP_BYTE_ORDER == UIP_BIG_ENDIAN */
+#      define HTONS(n) (u16_t)((((u16_t) (n)) << 8) | (((u16_t) (n)) >> 8))
+#   endif /* UIP_BYTE_ORDER == UIP_BIG_ENDIAN */
+#else
+#error "HTONS already defined!"
+#endif /* HTONS */
+#endif
+
+#if UIP_BYTE_ORDER == UIP_BIG_ENDIAN
+#      error "Should not be here"
+#      define const_htons(n) (n)
+#   else /* UIP_BYTE_ORDER == UIP_BIG_ENDIAN */
+#     define const_htons(n) (u16_t)((((u16_t) (n)) << 8) | (((u16_t) (n)) >> 8))
+#   endif /* UIP_BYTE_ORDER == UIP_BIG_ENDIAN */
+
+/*  BWL */
+#if 0
+/**
+ * Convert 16-bit quantity from host byte order to network byte order.
+ *
+ * This function is primarily used for converting variables from host
+ * byte order to network byte order. For converting constants to
+ * network byte order, use the HTONS() macro instead.
+ */
+#ifndef htons
+u16_t htons(u16_t val);
+#endif /* htons */
+#ifndef ntohs
+#define ntohs htons
+#endif
+#endif
+
+/** @} */
+
+/**
+ * Pointer to the application data in the packet buffer.
+ *
+ * This pointer points to the application data when the application is
+ * called. If the application wishes to send data, the application may
+ * use this space to write the data into before calling uip_send().
+ */
+/* extern void *uip_appdata; */
+
+#if UIP_URGDATA > 0
+/* u8_t *uip_urgdata:
+ *
+ * This pointer points to any urgent data that has been received. Only
+ * present if compiled with support for urgent data (UIP_URGDATA).
+ */
+extern void *uip_urgdata;
+#endif /* UIP_URGDATA > 0 */
+
+/**
+ * \defgroup uipdrivervars Variables used in uIP device drivers
+ * @{
+ *
+ * uIP has a few global variables that are used in device drivers for
+ * uIP.
+ */
+
+/**
+ * The length of the packet in the uip_buf buffer.
+ *
+ * The global variable uip_len holds the length of the packet in the
+ * uip_buf buffer.
+ *
+ * When the network device driver calls the uIP input function,
+ * uip_len should be set to the length of the packet in the uip_buf
+ * buffer.
+ *
+ * When sending packets, the device driver should use the contents of
+ * the uip_len variable to determine the length of the outgoing
+ * packet.
+ *
+ */
+/* extern u16_t uip_len; */
+
+/** @} */
+
+#if UIP_URGDATA > 0
+extern u16_t uip_urglen, uip_surglen;
+#endif /* UIP_URGDATA > 0 */
+
+/**
+ * Representation of a uIP TCP connection.
+ *
+ * The uip_conn structure is used for identifying a connection. All
+ * but one field in the structure are to be considered read-only by an
+ * application. The only exception is the appstate field whos purpose
+ * is to let the application store application-specific state (e.g.,
+ * file pointers) for the connection. The type of this field is
+ * configured in the "uipopt.h" header file.
+ */
+struct __attribute__ ((__packed__)) uip_conn {
+       uip_ip4addr_t ripaddr;
+       uip_ip6addr_t ripaddr6;
+                          /**< The IP address of the remote host. */
+
+       u16_t lport;  /**< The local TCP port, in network byte order. */
+       u16_t rport;  /**< The local remote TCP port, in network byte
+                        order. */
+
+       u8_t rcv_nxt[4];
+                     /**< The sequence number that we expect to
+                        receive next. */
+       u8_t snd_nxt[4];
+                     /**< The sequence number that was last sent by
+                        us. */
+       u16_t len;    /**< Length of the data that was previously sent. */
+       u16_t mss;    /**< Current maximum segment size for the
+                        connection. */
+       u16_t initialmss;
+                     /**< Initial maximum segment size for the
+                        connection. */
+       u8_t sa;      /**< Retransmission time-out calculation state
+                        variable. */
+       u8_t sv;      /**< Retransmission time-out calculation state
+                        variable. */
+       u8_t rto;     /**< Retransmission time-out. */
+       u8_t tcpstateflags;
+                     /**< TCP state and flags. */
+       u8_t timer;   /**< The retransmission timer. */
+       u8_t nrtx;    /**< The number of retransmissions for the last
+                        segment sent. */
+};
+
+/**
+ * \addtogroup uiparch
+ * @{
+ */
+
+/**
+ * 4-byte array used for the 32-bit sequence number calculations.
+ */
+extern u8_t uip_acc32[4];
+
+/** @} */
+
+#if UIP_UDP
+/**
+ * Representation of a uIP UDP connection.
+ */
+struct uip_udp_conn {
+       uip_ip4addr_t ripaddr;
+                          /**< The IP address of the remote peer. */
+       u16_t lport;  /**< The local port number in network byte order. */
+       u16_t rport;  /**< The remote port number in network byte order. */
+       u8_t ttl;     /**< Default time-to-live. */
+
+  /** The application state. */
+/* uip_udp_appstate_t appstate; */
+};
+
+#endif /* UIP_UDP */
+
+/**
+ * The structure holding the TCP/IP statistics that are gathered if
+ * UIP_STATISTICS is set to 1.
+ *
+ */
+struct uip_stats {
+       struct {
+               uip_stats_t drop;
+                         /**< Number of dropped packets at the IP
+                            layer. */
+               uip_stats_t recv;
+                         /**< Number of received packets at the IP
+                            layer. */
+               uip_stats_t sent;
+                         /**< Number of sent packets at the IP
+                            layer. */
+               uip_stats_t vhlerr;
+                         /**< Number of packets dropped due to wrong
+                            IP version or header length. */
+               uip_stats_t hblenerr;
+                         /**< Number of packets dropped due to wrong
+                            IP length, high byte. */
+               uip_stats_t lblenerr;
+                         /**< Number of packets dropped due to wrong
+                            IP length, low byte. */
+               uip_stats_t fragerr;
+                         /**< Number of packets dropped since they
+                            were IP fragments. */
+               uip_stats_t chkerr;
+                         /**< Number of packets dropped due to IP
+                            checksum errors. */
+               uip_stats_t protoerr;
+                         /**< Number of packets dropped since they
+                            were neither ICMP, UDP nor TCP. */
+       } ip;             /**< IP statistics. */
+       struct {
+               uip_stats_t drop;
+                         /**< Number of dropped ICMP packets. */
+               uip_stats_t recv;
+                         /**< Number of received ICMP packets. */
+               uip_stats_t sent;
+                         /**< Number of sent ICMP packets. */
+               uip_stats_t typeerr;
+                         /**< Number of ICMP packets with a wrong
+                            type. */
+       } icmp;           /**< ICMP statistics. */
+       struct {
+               uip_stats_t drop;
+                         /**< Number of dropped TCP segments. */
+               uip_stats_t recv;
+                         /**< Number of recived TCP segments. */
+               uip_stats_t sent;
+                         /**< Number of sent TCP segments. */
+               uip_stats_t chkerr;
+                         /**< Number of TCP segments with a bad
+                            checksum. */
+               uip_stats_t ackerr;
+                         /**< Number of TCP segments with a bad ACK
+                            number. */
+               uip_stats_t rst;
+                         /**< Number of recevied TCP RST (reset) segments. */
+               uip_stats_t rexmit;
+                         /**< Number of retransmitted TCP segments. */
+               uip_stats_t syndrop;
+                         /**< Number of dropped SYNs due to too few
+                            connections was avaliable. */
+               uip_stats_t synrst;
+                         /**< Number of SYNs for closed ports,
+                            triggering a RST. */
+       } tcp;            /**< TCP statistics. */
+#if UIP_UDP
+       struct {
+               uip_stats_t drop;
+                         /**< Number of dropped UDP segments. */
+               uip_stats_t recv;
+                         /**< Number of recived UDP segments. */
+               uip_stats_t sent;
+                         /**< Number of sent UDP segments. */
+               uip_stats_t chkerr;
+                         /**< Number of UDP segments with a bad
+                            checksum. */
+       } udp;            /**< UDP statistics. */
+#endif                         /* UIP_UDP */
+};
+
+/*---------------------------------------------------------------------------*/
+/* All the stuff below this point is internal to uIP and should not be
+ * used directly by an application or by a device driver.
+ */
+/*---------------------------------------------------------------------------*/
+/* u8_t uip_flags:
+ *
+ * When the application is called, uip_flags will contain the flags
+ * that are defined in this file. Please read below for more
+ * infomation.
+ */
+/* extern u8_t uip_flags; */
+
+/* The following flags may be set in the global variable uip_flags
+   before calling the application callback. The UIP_ACKDATA,
+   UIP_NEWDATA, and UIP_CLOSE flags may both be set at the same time,
+   whereas the others are mutualy exclusive. Note that these flags
+   should *NOT* be accessed directly, but only through the uIP
+   functions/macros. */
+
+#define UIP_ACKDATA   1                /* Signifies that the outstanding data was
+                                  acked and the application should send
+                                  out new data instead of retransmitting
+                                  the last data. */
+#define UIP_NEWDATA   2                /* Flags the fact that the peer has sent
+                                  us new data. */
+#define UIP_REXMIT    4                /* Tells the application to retransmit the
+                                  data that was last sent. */
+#define UIP_POLL      8                /* Used for polling the application, to
+                                  check if the application has data that
+                                  it wants to send. */
+#define UIP_CLOSE     16       /* The remote host has closed the
+                                  connection, thus the connection has
+                                  gone away. Or the application signals
+                                  that it wants to close the
+                                  connection. */
+#define UIP_ABORT     32       /* The remote host has aborted the
+                                  connection, thus the connection has
+                                  gone away. Or the application signals
+                                  that it wants to abort the
+                                  connection. */
+#define UIP_CONNECTED 64       /* We have got a connection from a remote
+                                  host and have set up a new connection
+                                  for it, or an active connection has
+                                  been successfully established. */
+
+#define UIP_TIMEDOUT  128      /* The connection has been aborted due to
+                                  too many retransmissions. */
+
+void uip_input(struct uip_stack *ustack);
+void uip_periodic(struct uip_stack *ustack, int conn);
+
+/* uip_process(flag):
+ *
+ * The actual uIP function which does all the work.
+ */
+void uip_process(struct uip_stack *ustack, u8_t flag);
+
+/* The following flags are passed as an argument to the uip_process()
+   function. They are used to distinguish between the two cases where
+   uip_process() is called. It can be called either because we have
+   incoming data that should be processed, or because the periodic
+   timer has fired. These values are never used directly, but only in
+   the macrose defined in this file. */
+
+#define UIP_DATA          1    /* Tells uIP that there is incoming
+                                  data in the uip_buf buffer. The
+                                  length of the data is stored in the
+                                  global variable uip_len. */
+#define UIP_TIMER         2    /* Tells uIP that the periodic timer
+                                  has fired. */
+#define UIP_POLL_REQUEST  3    /* Tells uIP that a connection should
+                                  be polled. */
+#define UIP_UDP_SEND_CONN 4    /* Tells uIP that a UDP datagram
+                                  should be constructed in the
+                                  uip_buf buffer. */
+#if UIP_UDP
+#define UIP_UDP_TIMER     5
+#endif /* UIP_UDP */
+
+#define UIP_NDP_TIMER     6
+
+/* The TCP states used in the uip_conn->tcpstateflags. */
+#define UIP_CLOSED      0
+#define UIP_SYN_RCVD    1
+#define UIP_SYN_SENT    2
+#define UIP_ESTABLISHED 3
+#define UIP_FIN_WAIT_1  4
+#define UIP_FIN_WAIT_2  5
+#define UIP_CLOSING     6
+#define UIP_TIME_WAIT   7
+#define UIP_LAST_ACK    8
+#define UIP_TS_MASK     15
+
+#define UIP_STOPPED      16
+
+struct __attribute__ ((__packed__)) uip_tcp_hdr {
+       /* TCP header. */
+       u16_t srcport, destport;
+       u8_t seqno[4], ackno[4], tcpoffset, flags, wnd[2];
+       u16_t tcpchksum;
+       u8_t urgp[2];
+       u8_t optdata[4];
+};
+
+struct __attribute__ ((__packed__)) uip_ipv4_hdr {
+       /* IPv4 header. */
+       u8_t vhl, tos, len[2], ipid[2], ipoffset[2], ttl, proto;
+       u16_t ipchksum;
+       u16_t srcipaddr[2], destipaddr[2];
+};
+
+struct __attribute__ ((__packed__)) uip_ipv6_hdr {
+       /* IPv6 header. */
+       u8_t vtc, tcflow;
+       u16_t flow;
+       u16_t len;
+       u8_t proto, ttl;
+       uip_ip6addr_t srcipaddr, destipaddr;
+};
+
+/* The TCP and IPv4 headers. */
+struct __attribute__ ((__packed__)) uip_tcp_ipv4_hdr {
+       /* IPv4 header. */
+       u8_t vhl, tos, len[2], ipid[2], ipoffset[2], ttl, proto;
+       u16_t ipchksum;
+       u16_t srcipaddr[2], destipaddr[2];
+
+       /* TCP header. */
+       u16_t srcport, destport;
+       u8_t seqno[4], ackno[4], tcpoffset, flags, wnd[2];
+       u16_t tcpchksum;
+       u8_t urgp[2];
+       u8_t optdata[4];
+};
+
+/* The TCP and IP headers. */
+struct __attribute__ ((__packed__)) uip_tcp_ipv6_hdr {
+       /* IPv6 header. */
+       u8_t vtc, tcflow;
+       u16_t flow;
+       u8_t len[2];
+       u8_t proto, ttl;
+       uip_ip6addr_t srcipaddr, destipaddr;
+
+       /* TCP header. */
+       u16_t srcport, destport;
+       u8_t seqno[4], ackno[4], tcpoffset, flags, wnd[2];
+       u16_t tcpchksum;
+       u8_t urgp[2];
+       u8_t optdata[4];
+};
+
+/* The ICMPv4 */
+struct __attribute__ ((__packed__)) uip_icmpv4_hdr {
+       /* ICMP (echo) header. */
+       u8_t type, icode;
+       u16_t icmpchksum;
+       u16_t id, seqno;
+};
+
+typedef struct uip_icmpv4_hdr uip_icmp_echo_hdr_t;
+
+/* The ICMPv6 */
+struct __attribute__ ((__packed__)) uip_icmpv6_hdr {
+       /* ICMP (echo) header. */
+       u8_t type, icode;
+       u16_t icmpchksum;
+       u8_t flags, reserved1, reserved2, reserved3;
+       u8_t icmp6data[16];
+       u8_t options[1];
+};
+
+/* The ICMP and IP headers. */
+struct __attribute__ ((__packed__)) uip_icmpip_hdr {
+#if UIP_CONF_IPV6
+       /* IPv6 header. */
+       u8_t vtc, tcf;
+       u16_t flow;
+       u8_t len[2];
+       u8_t proto, ttl;
+       uip_ip6addr_t srcipaddr, destipaddr;
+#else /* UIP_CONF_IPV6 */
+       /* IPv4 header. */
+       u8_t vhl, tos, len[2], ipid[2], ipoffset[2], ttl, proto;
+       u16_t ipchksum;
+       u16_t srcipaddr[2], destipaddr[2];
+#endif /* UIP_CONF_IPV6 */
+
+       /* ICMP (echo) header. */
+       u8_t type, icode;
+       u16_t icmpchksum;
+#if !UIP_CONF_IPV6
+       u16_t id, seqno;
+#else /* !UIP_CONF_IPV6 */
+       u8_t flags, reserved1, reserved2, reserved3;
+       u8_t icmp6data[16];
+       u8_t options[1];
+#endif /* !UIP_CONF_IPV6 */
+};
+
+/* The UDP  */
+struct __attribute__ ((__packed__)) uip_udp_hdr {
+       /* UDP header. */
+       u16_t srcport, destport;
+       u16_t udplen;
+       u16_t udpchksum;
+};
+
+/* The UDP and IP headers. */
+struct __attribute__ ((__packed__)) uip_udpip_hdr {
+#if UIP_CONF_IPV6
+       /* IPv6 header. */
+       u8_t vtc, tcf;
+       u16_t flow;
+       u8_t len[2];
+       u8_t proto, ttl;
+       uip_ip6addr_t srcipaddr, destipaddr;
+#else /* UIP_CONF_IPV6 */
+       /* IP header. */
+       u8_t vhl, tos, len[2], ipid[2], ipoffset[2], ttl, proto;
+       u16_t ipchksum;
+       u16_t srcipaddr[2], destipaddr[2];
+#endif /* UIP_CONF_IPV6 */
+
+       /* UDP header. */
+       u16_t srcport, destport;
+       u16_t udplen;
+       u16_t udpchksum;
+};
+
+/**
+ * The buffer size available for user data in the \ref uip_buf buffer.
+ *
+ * This macro holds the available size for user data in the \ref
+ * uip_buf buffer. The macro is intended to be used for checking
+ * bounds of available user data.
+ *
+ * Example:
+ \code
+ snprintf(uip_appdata, UIP_APPDATA_SIZE, "%u\n", i);
+ \endcode
+ *
+ * \hideinitializer
+ */
+#define UIP_APPDATA_SIZE (UIP_BUFSIZE - UIP_LLH_LEN - UIP_TCPIP_HLEN)
+
+#define UIP_PROTO_ICMP  1
+#define UIP_PROTO_TCP   6
+#define UIP_PROTO_UDP   17
+#define UIP_PROTO_ICMP6 58
+
+/* Header sizes. */
+#define UIP_IPv6_H_LEN    40   /* Size of IPv6 header */
+#define UIP_IPv4_H_LEN    20   /* Size of IPv4 header */
+
+#define UIP_UDPH_LEN    8      /* Size of UDP header */
+#define UIP_TCPH_LEN   20      /* Size of TCP header */
+
+#define UIP_IPv4_UDPH_LEN (UIP_UDPH_LEN + UIP_IPv4_H_LEN)      /* Size of IPv4
+                                                                  + UDP
+                                                                  header */
+#define UIP_IPv4_TCPH_LEN (UIP_TCPH_LEN + UIP_IPv4_H_LEN)      /* Size of IPv4
+                                                                  + TCP
+                                                                  header */
+#define UIP_TCP_IPv4_HLEN UIP_IPv4_TCPH_LEN
+
+#define UIP_IPv6_UDPH_LEN (UIP_UDPH_LEN + UIP_IPv6_H_LEN)      /* Size of IPv6
+                                                                  + UDP
+                                                                  header */
+#define UIP_IPv6_TCPH_LEN (UIP_TCPH_LEN + UIP_IPv6_H_LEN)      /* Size of IPv6
+                                                                  + TCP
+                                                                  header */
+#define UIP_TCP_IPv6_HLEN UIP_IPv6_TCPH_LEN
+
+/**
+ * Calculate the Internet checksum over a buffer.
+ *
+ * The Internet checksum is the one's complement of the one's
+ * complement sum of all 16-bit words in the buffer.
+ *
+ * See RFC1071.
+ *
+ * \param buf A pointer to the buffer over which the checksum is to be
+ * computed.
+ *
+ * \param len The length of the buffer over which the checksum is to
+ * be computed.
+ *
+ * \return The Internet checksum of the buffer.
+ */
+u16_t uip_chksum(u16_t *buf, u16_t len);
+
+/**
+ * Calculate the IP header checksum of the packet header in uip_buf.
+ *
+ * The IP header checksum is the Internet checksum of the 20 bytes of
+ * the IP header.
+ *
+ * \return The IP header checksum of the IP header in the uip_buf
+ * buffer.
+ */
+u16_t uip_ipchksum(struct uip_stack *ustack);
+
+/**
+ * Calculate the TCP checksum of the packet in uip_buf and uip_appdata.
+ *
+ * The TCP checksum is the Internet checksum of data contents of the
+ * TCP segment, and a pseudo-header as defined in RFC793.
+ *
+ * \return The TCP checksum of the TCP segment in uip_buf and pointed
+ * to by uip_appdata.
+ */
+u16_t uip_tcpchksum(struct uip_stack *ustack);
+
+/**
+ * Calculate the UDP checksum of the packet in uip_buf and uip_appdata.
+ *
+ * The UDP checksum is the Internet checksum of data contents of the
+ * UDP segment, and a pseudo-header as defined in RFC768.
+ *
+ * \return The UDP checksum of the UDP segment in uip_buf and pointed
+ * to by uip_appdata.
+ */
+u16_t uip_udpchksum(struct uip_stack *ustack);
+
+/*  IPv6 checksum */
+uint16_t icmpv6_checksum(uint8_t *data);
+
+struct neighbor_entry {
+       struct in6_addr ipaddr;
+       struct uip_eth_addr mac_addr;
+       u8_t time;
+};
+
+struct uip_stack {
+       struct uip_eth_addr uip_ethaddr;
+
+       u8_t *uip_buf;
+
+       uint8_t *data_link_layer;       /* Pointer to the data link layer */
+       uint8_t *network_layer; /* Pointer to the network layer   */
+       void *uip_appdata;      /* The uip_appdata pointer points to
+                                  application data. */
+       void *uip_sappdata;     /* The uip_appdata pointer points to
+                                  the application data which is to
+                                  be sent. */
+#if UIP_URGDATA > 0
+       void *uip_urgdata;      /* The uip_urgdata pointer points to
+                                  urgent data (out-of-band data), if
+                                  present. */
+       u16_t uip_urglen, uip_surglen;
+#endif                         /* UIP_URGDATA > 0 */
+
+       u16_t uip_len, uip_slen;        /* The uip_len is either 8 or 16 bits,
+                                          depending on the maximum packet
+                                          size. */
+       u8_t uip_flags;         /* The uip_flags variable is used for
+                                  communication between the TCP/IP stack
+                                  and the application program. */
+       struct uip_conn *uip_conn;      /* uip_conn always points to the current
+                                          connection. */
+
+       struct uip_conn uip_conns[UIP_CONNS];
+       /* The uip_conns array holds all TCP
+          connections. */
+       u16_t uip_listenports[UIP_LISTENPORTS];
+       /* The uip_listenports list all currently
+          listning ports. */
+#if UIP_UDP
+       struct uip_udp_conn *uip_udp_conn;
+       struct uip_udp_conn uip_udp_conns[UIP_UDP_CONNS];
+#endif                         /* UIP_UDP */
+
+       u16_t ipid;             /* This ipid variable is an increasing
+                                  number that is used for the IP ID
+                                  field. */
+
+       u8_t iss[4];            /* The iss variable is used for the TCP
+                                  initial sequence number. */
+
+#if UIP_ACTIVE_OPEN
+       u16_t lastport;         /* Keeps track of the last port used for
+                                  a new connection. */
+#endif                         /* UIP_ACTIVE_OPEN */
+
+#define IP_CONFIG_OFF                  0x00
+#define IPV4_CONFIG_OFF                        0x01
+#define IPV4_CONFIG_STATIC             0x02
+#define IPV4_CONFIG_DHCP               0x04
+#define IPV6_CONFIG_OFF                        0x10
+#define IPV6_CONFIG_STATIC             0x20
+#define IPV6_CONFIG_DHCP               0x40
+       u8_t ip_config;
+
+       uip_ip4addr_t hostaddr, netmask, default_route_addr;
+       uip_ip6addr_t hostaddr6, netmask6, default_route_addr6,
+                     linklocal6;
+       int prefix_len;
+       u8_t ipv6_autocfg;
+#define IPV6_AUTOCFG_DHCPV6            (1<<0)
+#define IPV6_AUTOCFG_ND                        (1<<1)
+#define IPV6_AUTOCFG_NOTSPEC           (1<<6)
+#define IPV6_AUTOCFG_NOTUSED           (1<<7)
+       u8_t linklocal_autocfg;
+#define IPV6_LL_AUTOCFG_ON             (1<<0)
+#define IPV6_LL_AUTOCFG_OFF            (1<<1)
+#define IPV6_LL_AUTOCFG_NOTSPEC                (1<<6)
+#define IPV6_LL_AUTOCFG_NOTUSED                (1<<7)
+       u8_t router_autocfg;
+#define IPV6_RTR_AUTOCFG_ON            (1<<0)
+#define IPV6_RTR_AUTOCFG_OFF           (1<<1)
+#define IPV6_RTR_AUTOCFG_NOTSPEC       (1<<6)
+#define IPV6_RTR_AUTOCFG_NOTUSED       (1<<7)
+
+#define UIP_NEIGHBOR_ENTRIES 8
+       struct neighbor_entry neighbor_entries[UIP_NEIGHBOR_ENTRIES];
+
+       struct uip_stats stats;
+
+       u8_t opt;
+
+       pthread_mutex_t lock;
+
+       /*  IPv6 support */
+#define UIP_SUPPORT_IPv6_ENABLED       0x01
+#define UIP_SUPPORT_IPv6_DISABLED      0x02
+       u8_t enable_IPv6;
+
+       /*  DHCPC client attached */
+       void *dhcpc;
+
+       /* NDP client */
+       void *ndpc;
+
+       void *ping_conf;
+};
+
+/*******************************************************************************
+ * IPv6 Support
+ ******************************************************************************/
+int set_ipv6_link_local_address(struct uip_stack *ustack);
+int is_ipv6_link_local_address(uip_ip6addr_t *addr);
+
+void dump_uip_packet(struct uip_stack *ustack);
+u16_t uip_icmp6chksum(struct uip_stack *ustack);
+
+#endif /* __UIP_H__ */
+
+/** @} */
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/uip_arch.h b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/uip_arch.h
new file mode 100644 (file)
index 0000000..3ddacec
--- /dev/null
@@ -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/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/uip_arp.c b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/uip_arp.c
new file mode 100644 (file)
index 0000000..1b3761f
--- /dev/null
@@ -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, &eth->src);
+       }
+}
+
+void
+uip_arp_arpin(nic_interface_t *nic_iface,
+             struct uip_stack *ustack, packet_t *pkt)
+{
+       struct arp_hdr *arp;
+       struct uip_eth_hdr *eth;
+
+       if (pkt->buf_size < sizeof(struct arp_hdr)) {
+               pkt->buf_size = 0;
+               return;
+       }
+       pkt->buf_size = 0;
+
+       eth = (struct uip_eth_hdr *)pkt->data_link_layer;
+       arp = (struct arp_hdr *)pkt->network_layer;
+
+       switch (arp->opcode) {
+       case const_htons(ARP_REQUEST):
+               /* ARP request. If it asked for our address, we send out a
+                  reply. */
+               if (uip_ip4addr_cmp(arp->dipaddr, ustack->hostaddr)) {
+                       /* First, we register the one who made the request in
+                          our ARP table, since it is likely that we will do
+                          more communication with this host in the future. */
+                       uip_arp_update(arp->sipaddr, &arp->shwaddr);
+
+                       /* The reply opcode is 2. */
+                       arp->opcode = htons(2);
+
+                       memcpy(arp->dhwaddr.addr, arp->shwaddr.addr, 6);
+                       memcpy(arp->shwaddr.addr, ustack->uip_ethaddr.addr, 6);
+                       memcpy(eth->src.addr, ustack->uip_ethaddr.addr, 6);
+                       memcpy(eth->dest.addr, arp->dhwaddr.addr, 6);
+
+                       arp->dipaddr[0] = arp->sipaddr[0];
+                       arp->dipaddr[1] = arp->sipaddr[1];
+                       arp->sipaddr[0] = ustack->hostaddr[0];
+                       arp->sipaddr[1] = ustack->hostaddr[1];
+
+                       if (nic_iface->vlan_id == 0) {
+                               eth->type = htons(UIP_ETHTYPE_ARP);
+                               pkt->buf_size = sizeof(*arp) + sizeof(*eth);
+                       } else {
+                               eth->type = htons(UIP_ETHTYPE_8021Q);
+                               pkt->buf_size = sizeof(*arp) +
+                                               sizeof(struct uip_vlan_eth_hdr);
+                       }
+               }
+               break;
+       case const_htons(ARP_REPLY):
+               uip_arp_update(arp->sipaddr, &arp->shwaddr);
+               break;
+       default:
+               LOG_WARN("Unknown ARP opcode: %d", ntohs(arp->opcode));
+               break;
+       }
+
+       return;
+}
+
+/**
+ * Prepend Ethernet header to an outbound IP packet and see if we need
+ * to send out an ARP request.
+ *
+ * This function should be called before sending out an IP packet. The
+ * function checks the destination IP address of the IP packet to see
+ * what Ethernet MAC address that should be used as a destination MAC
+ * address on the Ethernet.
+ *
+ * If the destination IP address is in the local network (determined
+ * by logical ANDing of netmask and our IP address), the function
+ * checks the ARP cache to see if an entry for the destination IP
+ * address is found. If so, an Ethernet header is prepended and the
+ * function returns. If no ARP cache entry is found for the
+ * destination IP address, the packet in the uip_buf[] is replaced by
+ * an ARP request packet for the IP address. The IP packet is dropped
+ * and it is assumed that they higher level protocols (e.g., TCP)
+ * eventually will retransmit the dropped packet.
+ *
+ * If the destination IP address is not on the local network, the IP
+ * address of the default router is used instead.
+ *
+ * When the function returns, a packet is present in the uip_buf[]
+ * buffer, and the length of the packet is in the global variable
+ * uip_len.
+ */
+
+dest_ipv4_addr_t
+uip_determine_dest_ipv4_addr(struct uip_stack *ustack, u16_t *ipaddr)
+{
+       struct 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(&eth->dest, broadcast_ethaddr.addr, 6);
+
+               return LOCAL_BROADCAST;
+       } else {
+               /* Check if the destination address is on the local network. */
+               if (!uip_ip4addr_maskcmp(ip_buf->destipaddr,
+                                        ustack->hostaddr, ustack->netmask)) {
+                       /* Destination address was not on the local network,
+                          so we need to use the default router's IP address
+                          instead of the destination address when determining
+                          the MAC address. */
+                       uip_ip4addr_copy(ipaddr, ustack->default_route_addr);
+               } else {
+                       /* Else, we use the destination IP address. */
+                       uip_ip4addr_copy(ipaddr, ip_buf->destipaddr);
+               }
+
+               return NONLOCAL_BROADCAST;
+       }
+}
+
+arp_out_t is_in_arp_table(u16_t *ipaddr, struct arp_entry **tabptr)
+{
+       u8_t i;
+
+       pthread_mutex_lock(&arp_table_mutex);
+
+       for (i = 0; i < UIP_ARPTAB_SIZE; ++i) {
+               if (uip_ip4addr_cmp(ipaddr, arp_table[i].ipaddr)) {
+                       *tabptr = &arp_table[i];
+                       break;
+               }
+       }
+
+       pthread_mutex_unlock(&arp_table_mutex);
+
+       if (i == UIP_ARPTAB_SIZE)
+               return NOT_IN_ARP_TABLE;
+       else
+               return IS_IN_ARP_TABLE;
+}
+
+void uip_build_arp_request(struct uip_stack *ustack, u16_t *ipaddr)
+{
+       struct arp_hdr *arp;
+       struct uip_eth_hdr *eth;
+
+       arp = (struct arp_hdr *)ustack->network_layer;
+       eth = (struct uip_eth_hdr *)ustack->data_link_layer;
+
+       /* The destination address was not in our ARP table, so we
+          overwrite the IP packet with an ARP request. */
+
+       memset(eth->dest.addr, 0xff, 6);
+       memset(arp->dhwaddr.addr, 0x00, 6);
+       memcpy(eth->src.addr, ustack->uip_ethaddr.addr, 6);
+       memcpy(arp->shwaddr.addr, ustack->uip_ethaddr.addr, 6);
+
+       uip_ip4addr_copy(arp->dipaddr, ipaddr);
+       uip_ip4addr_copy(arp->sipaddr, ustack->hostaddr);
+       arp->opcode = const_htons(ARP_REQUEST); /* ARP request. */
+       arp->hwtype = const_htons(ARP_HWTYPE_ETH);
+       arp->protocol = const_htons(UIP_ETHTYPE_IPv4);
+       arp->hwlen = 6;
+       arp->protolen = 4;
+       eth->type = const_htons(UIP_ETHTYPE_ARP);
+
+       ustack->uip_appdata = &ustack->uip_buf[UIP_TCP_IPv4_HLEN + UIP_LLH_LEN];
+
+       ustack->uip_len = sizeof(*arp) + sizeof(*eth);
+}
+
+void
+uip_build_eth_header(struct uip_stack *ustack,
+                    u16_t *ipaddr,
+                    struct arp_entry *tabptr,
+                    struct packet *pkt, u16_t vlan_id)
+{
+       struct uip_ipv4_hdr *ip_buf;
+       struct uip_eth_hdr *eth;
+       struct uip_vlan_eth_hdr *eth_vlan;
+
+       ip_buf = (struct uip_ipv4_hdr *)ustack->network_layer;
+       eth = (struct uip_eth_hdr *)ustack->data_link_layer;
+       eth_vlan = (struct uip_vlan_eth_hdr *)ustack->data_link_layer;
+
+       /* First check if destination is a local broadcast. */
+       if (uip_ip4addr_cmp(ip_buf->destipaddr, broadcast_ipaddr)) {
+               memcpy(eth->dest.addr, broadcast_ethaddr.addr, 6);
+       } else {
+               /* Build an ethernet header. */
+               memcpy(eth->dest.addr, tabptr->ethaddr.addr, 6);
+       }
+       memcpy(eth->src.addr, ustack->uip_ethaddr.addr, 6);
+
+       if (vlan_id == 0) {
+               eth->type = htons(UIP_ETHTYPE_IPv4);
+
+               ustack->uip_len += sizeof(struct uip_eth_hdr);
+               pkt->buf_size += sizeof(struct uip_eth_hdr);
+       } else {
+               eth_vlan->tpid = htons(UIP_ETHTYPE_8021Q);
+               eth_vlan->vid = htons(vlan_id);
+               eth_vlan->type = htons(UIP_ETHTYPE_IPv4);
+
+               ustack->uip_len += sizeof(struct uip_vlan_eth_hdr);
+               pkt->buf_size += sizeof(struct uip_vlan_eth_hdr);
+       }
+}
+
+static struct arp_entry *uip_get_arp_entry(int index)
+{
+       return &arp_table[index];
+}
+
+int uip_lookup_arp_entry(uint32_t ip_addr, uint8_t *mac_addr)
+{
+       int i;
+       int rc = -EINVAL;
+
+       pthread_mutex_lock(&arp_table_mutex);
+
+       for (i = 0; i < UIP_ARPTAB_SIZE; ++i) {
+               struct arp_entry *entry = uip_get_arp_entry(i);
+
+               if (((entry->ipaddr[1] << 16) == (ip_addr & 0xffff0000)) &&
+                   ((entry->ipaddr[0]) == (ip_addr & 0x0000ffff))) {
+                       struct in_addr addr;
+                       char *addr_str;
+
+                       addr.s_addr = ip_addr;
+                       addr_str = inet_ntoa(addr);
+
+                       memcpy(mac_addr, entry->ethaddr.addr, 6);
+
+                       LOG_INFO("Found %s at %02x:%02x:%02x:%02x:%02x:%02x",
+                                addr_str,
+                                mac_addr[0], mac_addr[1], mac_addr[2],
+                                mac_addr[3], mac_addr[4], mac_addr[5]);
+                       rc = 0;
+                       break;
+               }
+       }
+
+       pthread_mutex_unlock(&arp_table_mutex);
+       return rc;
+}
+
+/*----------------------------------------------------------------------------*/
+
+/** @} */
+/** @} */
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/uip_arp.h b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/uip_arp.h
new file mode 100644 (file)
index 0000000..339d57d
--- /dev/null
@@ -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/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/uip_eth.c b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/uip_eth.c
new file mode 100644 (file)
index 0000000..9e1ea81
--- /dev/null
@@ -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/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/uip_eth.h b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/uip_eth.h
new file mode 100644 (file)
index 0000000..830c04c
--- /dev/null
@@ -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/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/uipopt.h b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/uip/uipopt.h
new file mode 100644 (file)
index 0000000..bcc8949
--- /dev/null
@@ -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 16
+#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/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/.gitignore b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/.gitignore
new file mode 100644 (file)
index 0000000..b3b37db
--- /dev/null
@@ -0,0 +1,3 @@
+build_date.c
+build_date.h
+iscsiuio
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/Makefile.am b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/Makefile.am
new file mode 100644 (file)
index 0000000..f48a1f7
--- /dev/null
@@ -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            \
+                       ping.c                  \
+                       ${top_srcdir}/../sysdeps/sysdeps.c
+
+iscsiuio_CFLAGS =      $(AM_CFLAGS)            \
+                       $(LIBNL_CFLAGS)         \
+                       -DBYTE_ORDER=@ENDIAN@
+
+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      \
+                       $(AM_LDADD)                                             \
+                       -ldl                                                    \
+                       $(LIBNL_LIBS)                                           \
+                       -lpthread
+
+iscsiuio_YFLAGS = -d
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/build_date.sh b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/build_date.sh
new file mode 100755 (executable)
index 0000000..65888fe
--- /dev/null
@@ -0,0 +1,54 @@
+#!/bin/bash
+#
+# build the build_date.c and build_date.h files
+#
+# (bash required for getopts)
+#
+
+THIS_CMD=${0##*/}
+
+usage()
+{
+    echo "Usage: $THIS_CMD [OPTIONS]"
+    echo "Where OPTIONS are from:"
+    echo "  -c OUT_SOURCE         create C source file OUT_SOURCE with the date"
+    echo "  -i OUT_HEADER         create C include file OUT_HEADER for the date file"
+    echo "  -S EPOCH_DATE_NUMBER  use '--date=@EPOCH_DATE_NUMBER' to set date (repeatable builds)"
+    echo "Also sets EPOCH date number from SOURCE_DATE_EPOCH if set in the environment"
+}
+
+generate_source_file()
+{
+    outfile="$1"
+    if [ -n "$SOURCE_DATE_EPOCH" ] ; then
+       echo 'char *build_date = "'`LC_ALL=C.UTF-8 date --date=@$SOURCE_DATE_EPOCH -u`'";' >"$outfile"
+    else
+       echo 'char *build_date = "'`date`'";' >"$outfile"
+    fi
+}
+
+generate_include_file()
+{
+    outfile="$1"
+    echo 'extern char *build_date;' >"$outfile"
+}
+
+do_source=
+do_include=
+
+while getopts :c:i:S:h opt; do
+    case "$opt" in
+    c) do_source="$OPTARG" ;;
+    i) do_include="$OPTARG" ;;
+    S) SOURCE_DATE_EPOCH="$OPTARG" ;;
+    h) usage; exit 0 ;;
+    ?) echo "unknown option" 1>&2; usage; exit 1 ;; 
+    esac
+done
+
+if [ -n "$do_source" ]; then
+   generate_source_file $do_source
+fi
+if [ -n "$do_include" ]; then
+    generate_include_file $do_include
+fi
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/clock-arch.c b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/clock-arch.c
new file mode 100644 (file)
index 0000000..d853101
--- /dev/null
@@ -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/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/clock-arch.h b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/clock-arch.h
new file mode 100644 (file)
index 0000000..888933f
--- /dev/null
@@ -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/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/iscsid_ipc.c b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/iscsid_ipc.c
new file mode 100644 (file)
index 0000000..ea03d37
--- /dev/null
@@ -0,0 +1,1255 @@
+/*
+ * 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
+ *
+ */
+
+#define _GNU_SOURCE
+
+#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>
+#include <sys/types.h>
+#include <pwd.h>
+
+#define PFX "iscsi_ipc "
+
+#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 "sysdeps.h"
+
+#include "logger.h"
+#include "uip.h"
+#include "ping.h"
+
+/*  private iscsid options stucture */
+struct iscsid_options {
+       int fd;
+       pthread_t thread;
+};
+
+struct iface_rec_decode {
+       /* General */
+       int32_t                 iface_num;
+       uint32_t                ip_type;
+
+       /* IPv4 */
+       struct in_addr          ipv4_addr;
+       struct in_addr          ipv4_subnet_mask;
+       struct in_addr          ipv4_gateway;
+
+       /* IPv6 */
+       struct in6_addr         ipv6_addr;
+       struct in6_addr         ipv6_subnet_mask;
+       uint32_t                prefix_len;
+       struct in6_addr         ipv6_linklocal;
+       struct in6_addr         ipv6_router;
+
+       uint8_t                 ipv6_autocfg;
+       uint8_t                 linklocal_autocfg;
+       uint8_t                 router_autocfg;
+
+       uint8_t                 vlan_state;
+       uint8_t                 vlan_priority;
+       uint16_t                vlan_id;
+
+#define MIN_MTU_SUPPORT                46
+#define MAX_MTU_SUPPORT                9000
+       uint16_t                mtu;
+};
+
+#define PEERUSER_MAX   64
+
+/******************************************************************************
+ *  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];
+       unsigned long keepbits = 0;
+       struct in_addr ia;
+       struct in6_addr ia6;
+
+       strlcpy(ipaddr_str, in_ipaddr_str, NI_MAXHOST);
+
+       /* 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 = strtoull(tmp, NULL, 10);
+       }
+
+       /*  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) {
+                               strlcpy(ipaddr_str, rec->ipv6_linklocal,
+                                       NI_MAXHOST);
+                               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) {
+                               strlcpy(ipaddr_str, rec->ipv6_router,
+                                       NI_MAXHOST);
+                               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);
+
+                       strlcpy(ipaddr_str, rec->gateway, NI_MAXHOST);
+                       inet_pton(AF_INET, ipaddr_str, &ird->ipv4_gateway);
+               }
+       } else {
+               ird->ipv6_autocfg = IPV6_AUTOCFG_NOTUSED;
+               ird->linklocal_autocfg = IPV6_LL_AUTOCFG_NOTUSED;
+               ird->router_autocfg = IPV6_RTR_AUTOCFG_NOTUSED;
+       }
+       return rc;
+}
+
+static void *perform_ping(void *arg)
+{
+       struct ping_conf *png_c = (struct ping_conf *)arg;
+       nic_interface_t *nic_iface = png_c->nic_iface;
+       nic_t *nic = nic_iface->parent;
+       iscsid_uip_broadcast_t *data;
+       struct sockaddr_in *addr;
+       struct sockaddr_in6 *addr6;
+       uip_ip6addr_t dst_addr;
+       int rc = 0;
+       int datalen;
+       struct timespec ts = {.tv_sec = 5,
+                             .tv_nsec = 0};
+
+       data = (iscsid_uip_broadcast_t *)png_c->data;
+       datalen = data->u.ping_rec.datalen;
+       if ((datalen > STD_MTU_SIZE) || (datalen < 0)) {
+               LOG_ERR(PFX "Ping datalen invalid: %d", datalen);
+               rc = -EINVAL;
+               goto ping_done;
+       }
+
+       memset(dst_addr, 0, sizeof(uip_ip6addr_t));
+       if (nic_iface->protocol == AF_INET) {
+               /* IPv4 */
+               addr = (struct sockaddr_in *)&data->u.ping_rec.ipaddr;
+               memcpy(dst_addr, &addr->sin_addr.s_addr, sizeof(uip_ip4addr_t));
+       } else {
+               /* IPv6 */
+               addr6 = (struct sockaddr_in6 *)&data->u.ping_rec.ipaddr;
+               memcpy(dst_addr, &addr6->sin6_addr.s6_addr,
+                      sizeof(uip_ip6addr_t));
+       }
+
+       /*  Ensure that the NIC is RUNNING */
+       if ((nic->state != NIC_RUNNING) || !(nic->flags & NIC_ENABLED)) {
+               pthread_mutex_lock(&nic->nic_mutex);
+               rc = pthread_cond_timedwait(&nic->enable_done_cond,
+                                           &nic->nic_mutex, &ts);
+               if ((rc == 0) && (nic->state == NIC_RUNNING)) {
+                       LOG_DEBUG(PFX "%s: nic running", nic->log_name);
+               } else if (rc) {
+                       LOG_DEBUG(PFX "%s: err %d", nic->log_name, rc);
+                       rc = -EAGAIN;
+               }
+               pthread_mutex_unlock(&nic->nic_mutex);
+       }
+
+       if (rc || nic->state != NIC_RUNNING) {
+               png_c->state = rc;
+               goto ping_done;
+       }
+
+       ping_init(png_c, dst_addr, nic_iface->protocol, datalen);
+
+       rc = do_ping_from_nic_iface(png_c);
+       if (png_c->state == -1)
+               png_c->state = rc;
+
+ping_done:
+       LOG_INFO(PFX "ping thread end");
+       nic->ping_thread = INVALID_THREAD;
+       pthread_exit(NULL);
+}
+
+static int parse_iface(void *arg, int do_ping)
+{
+       int rc, i;
+       nic_t *nic = NULL;
+       nic_interface_t *nic_iface;
+       char *transport_name;
+       size_t transport_name_size;
+       nic_lib_handle_t *handle;
+       iscsid_uip_broadcast_t *data;
+       char ipv6_buf_str[INET6_ADDRSTRLEN];
+       int request_type = 0;
+       struct iface_rec *rec;
+       struct iface_rec_decode ird;
+       struct in_addr src_match, dst_match;
+       pthread_attr_t attr;
+       struct ping_conf *png_c;
+
+       data = (iscsid_uip_broadcast_t *) arg;
+       if (do_ping)
+               rec = &data->u.ping_rec.ifrec;
+       else
+               rec = &data->u.iface_rec.rec;
+
+       LOG_INFO(PFX "Received request for '%s' to set IP address: '%s' "
+                "VLAN: '%d'",
+                rec->netdev,
+                rec->ipaddress,
+                rec->vlan_id);
+
+       rc = decode_iface(&ird, rec);
+       if (ird.vlan_id && valid_vlan(ird.vlan_id) == 0) {
+               LOG_ERR(PFX "Invalid VLAN tag: %d", ird.vlan_id);
+               rc = -EIO;
+               goto early_exit;
+       }
+       if (rc && !ird.ip_type) {
+               LOG_ERR(PFX "iface err: rc=%d, ip_type=%d", rc, ird.ip_type);
+               goto early_exit;
+       }
+
+       for (i = 0; i < 10; i++) {
+               struct timespec sleep_req, sleep_rem;
+
+               if (pthread_mutex_trylock(&nic_list_mutex) == 0)
+                       break;
+
+               sleep_req.tv_sec = 0;
+               sleep_req.tv_nsec = 100000;
+               nanosleep(&sleep_req, &sleep_rem);
+       }
+
+       if (i >= 10) {
+               LOG_WARN(PFX "Could not acquire nic_list_mutex lock");
+               rc = -EIO;
+               goto early_exit;
+       }
+
+       /* nic_list_mutex locked */
+
+       /*  Check if we can find the NIC device using the netdev
+        *  name */
+       rc = from_netdev_name_find_nic(rec->netdev, &nic);
+
+       if (rc != 0) {
+               LOG_WARN(PFX "Couldn't find NIC: %s, creating an instance",
+                        rec->netdev);
+
+               nic = nic_init();
+               if (nic == NULL) {
+                       LOG_ERR(PFX "Couldn't allocate space for NIC %s",
+                               rec->netdev);
+
+                       rc = -ENOMEM;
+                       goto done;
+               }
+
+               strncpy(nic->eth_device_name,
+                       rec->netdev,
+                       sizeof(nic->eth_device_name));
+               nic->config_device_name = nic->eth_device_name;
+               nic->log_name = nic->eth_device_name;
+
+               if (nic_fill_name(nic) != 0) {
+                       free(nic);
+                       rc = -EIO;
+                       goto done;
+               }
+
+               nic_add(nic);
+       } else {
+               LOG_INFO(PFX " %s, using existing NIC",
+                        rec->netdev);
+       }
+
+       pthread_mutex_lock(&nic->nic_mutex);
+       if (nic->flags & NIC_GOING_DOWN) {
+               pthread_mutex_unlock(&nic->nic_mutex);
+               rc = -EIO;
+               LOG_INFO(PFX "nic->flags GOING DOWN");
+               goto done;
+       }
+
+       /*  If we retry too many times allow iscsid to timeout */
+       if (nic->pending_count > 1000) {
+               nic->pending_count = 0;
+               nic->flags &= ~NIC_ENABLED_PENDING;
+               pthread_mutex_unlock(&nic->nic_mutex);
+
+               LOG_WARN(PFX "%s: pending count exceeded 1000", nic->log_name);
+
+               rc = 0;
+               goto done;
+       }
+
+       if (nic->flags & NIC_ENABLED_PENDING) {
+               struct timespec sleep_req, sleep_rem;
+
+               nic->pending_count++;
+               pthread_mutex_unlock(&nic->nic_mutex);
+
+               sleep_req.tv_sec = 2;
+               sleep_req.tv_nsec = 0;
+               nanosleep(&sleep_req, &sleep_rem);
+
+               pthread_mutex_lock(&nic->nic_mutex);
+               if (!(nic->flags & NIC_ENABLED) ||
+                   nic->state != NIC_RUNNING) {
+                       pthread_mutex_unlock(&nic->nic_mutex);
+                       LOG_INFO(PFX "%s: enabled pending", nic->log_name);
+                       rc = -EAGAIN;
+                       goto done;
+               }
+       }
+       pthread_mutex_unlock(&nic->nic_mutex);
+
+       prepare_library(nic);
+
+       /*  Sanity Check to ensure the transport names are the same */
+       handle = nic->nic_library;
+       if (handle != NULL) {
+               (*handle->ops->lib_ops.get_transport_name) (&transport_name,
+                                                         &transport_name_size);
+
+               if (strncmp(transport_name,
+                           rec->transport_name,
+                           transport_name_size) != 0) {
+                       LOG_ERR(PFX "%s Transport name is not equal "
+                               "expected: %s got: %s",
+                               nic->log_name,
+                               rec->transport_name,
+                               transport_name);
+               }
+       } else {
+               LOG_ERR(PFX "%s Couldn't find nic library ", nic->log_name);
+               rc = -EIO;
+               goto done;
+       }
+
+       LOG_INFO(PFX "%s library set using transport_name %s",
+                nic->log_name, transport_name);
+
+       /*  Determine how to configure the IP address */
+       if (ird.ip_type == AF_INET) {
+               if (memcmp(&ird.ipv4_addr,
+                          all_zeroes_addr4, sizeof(uip_ip4addr_t)) == 0) {
+                       LOG_INFO(PFX "%s: requesting configuration using DHCP",
+                                nic->log_name);
+                       request_type = IPV4_CONFIG_DHCP;
+               } else {
+                       LOG_INFO(PFX "%s: requesting configuration using "
+                                "static IP address", nic->log_name);
+                       request_type = IPV4_CONFIG_STATIC;
+               }
+       } else if (ird.ip_type == AF_INET6) {
+               /* For the new 872_22, check ipv6_autocfg for DHCPv6 instead */
+               switch (ird.ipv6_autocfg) {
+               case IPV6_AUTOCFG_DHCPV6:
+                       request_type = IPV6_CONFIG_DHCP;
+                       break;
+               case IPV6_AUTOCFG_ND:
+                       request_type = IPV6_CONFIG_STATIC;
+                       break;
+               case IPV6_AUTOCFG_NOTSPEC:
+                       /* Treat NOTSPEC the same as NOTUSED for now */
+               case IPV6_AUTOCFG_NOTUSED:
+                       /* For 871 */
+               default:
+                       /* Just the IP address to determine */
+                       if (memcmp(&ird.ipv6_addr,
+                                  all_zeroes_addr6,
+                                  sizeof(struct in6_addr)) == 0)
+                               request_type = IPV6_CONFIG_DHCP;
+                       else
+                               request_type = IPV6_CONFIG_STATIC;
+               }
+       } else {
+               LOG_ERR(PFX "%s: unknown ip_type to configure: 0x%x",
+                       nic->log_name, ird.ip_type);
+
+               rc = -EIO;
+               goto done;
+       }
+
+       pthread_mutex_lock(&nic->nic_mutex);
+
+       nic_iface = nic_find_nic_iface(nic, ird.ip_type, ird.vlan_id,
+                                      ird.iface_num, request_type);
+
+       if (nic->flags & NIC_PATHREQ_WAIT) {
+               if (!nic_iface ||
+                   !(nic_iface->flags & NIC_IFACE_PATHREQ_WAIT)) {
+                       int pathreq_wait;
+
+                       if (nic_iface &&
+                           (nic_iface->flags & NIC_IFACE_PATHREQ_WAIT2))
+                               pathreq_wait = 12;
+                       else
+                               pathreq_wait = 10;
+
+                       if (nic->pathreq_pending_count < pathreq_wait) {
+                               struct timespec sleep_req, sleep_rem;
+
+                               pthread_mutex_unlock(&nic->nic_mutex);
+
+                               nic->pathreq_pending_count++;
+                               sleep_req.tv_sec = 0;
+                               sleep_req.tv_nsec = 100000;
+                               nanosleep(&sleep_req, &sleep_rem);
+                               /* Somebody else is waiting for PATH_REQ */
+                               LOG_INFO(PFX "%s: path req pending cnt=%d",
+                                        nic->log_name,
+                                        nic->pathreq_pending_count);
+                               rc = -EAGAIN;
+                               goto done;
+                       } else {
+                               nic->pathreq_pending_count = 0;
+                               LOG_DEBUG(PFX "%s: path req pending cnt "
+                                         "exceeded!", nic->log_name);
+                               /* Allow to fall thru */
+                       }
+               }
+       }
+
+       nic->flags |= NIC_PATHREQ_WAIT;
+
+       /* Create the network interface if it doesn't exist */
+       if (nic_iface == NULL) {
+               LOG_DEBUG(PFX "%s couldn't find interface with "
+                         "ip_type: 0x%x creating it",
+                         nic->log_name, ird.ip_type);
+               nic_iface = nic_iface_init();
+
+               if (nic_iface == NULL) {
+                       pthread_mutex_unlock(&nic->nic_mutex);
+                       LOG_ERR(PFX "%s Couldn't allocate "
+                               "interface with ip_type: 0x%x",
+                               nic->log_name, ird.ip_type);
+                       goto done;
+               }
+               nic_iface->protocol = ird.ip_type;
+               nic_iface->vlan_id = ird.vlan_id;
+               nic_iface->vlan_priority = ird.vlan_priority;
+               if (ird.mtu >= MIN_MTU_SUPPORT && ird.mtu <= MAX_MTU_SUPPORT)
+                       nic_iface->mtu = ird.mtu;
+               nic_iface->iface_num = ird.iface_num;
+               nic_iface->request_type = request_type;
+               nic_add_nic_iface(nic, nic_iface);
+
+               persist_all_nic_iface(nic);
+
+               LOG_INFO(PFX "%s: created network interface",
+                        nic->log_name);
+       } else {
+               /* Move the nic_iface to the front */
+               set_nic_iface(nic, nic_iface);
+               LOG_INFO(PFX "%s: using existing network interface",
+                        nic->log_name);
+       }
+
+       nic_iface->flags |= NIC_IFACE_PATHREQ_WAIT1;
+       if (nic->nl_process_thread == INVALID_THREAD) {
+               pthread_attr_init(&attr);
+               pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+               rc = pthread_create(&nic->nl_process_thread, &attr,
+                                   nl_process_handle_thread, nic);
+               if (rc != 0) {
+                       LOG_ERR(PFX "%s: Could not create NIC NL "
+                               "processing thread [%s]", nic->log_name,
+                               strerror(rc));
+                       nic->nl_process_thread = INVALID_THREAD;
+                       /* Reset both WAIT flags */
+                       nic_iface->flags &= ~NIC_IFACE_PATHREQ_WAIT;
+                       nic->flags &= ~NIC_PATHREQ_WAIT;
+               }
+       }
+
+       pthread_mutex_unlock(&nic->nic_mutex);
+
+       if (nic_iface->ustack.ip_config == request_type) {
+               /* Same request_type, check for STATIC address change */
+               if (request_type == IPV4_CONFIG_STATIC) {
+                       if (memcmp(nic_iface->ustack.hostaddr, &ird.ipv4_addr,
+                                  sizeof(struct in_addr)))
+                               goto reacquire;
+               } else if (request_type == IPV6_CONFIG_STATIC) {
+                       if (memcmp(nic_iface->ustack.hostaddr6, &ird.ipv6_addr,
+                                  sizeof(struct in6_addr)))
+                               goto reacquire;
+                       else
+                               inet_ntop(AF_INET6, &ird.ipv6_addr,
+                                         ipv6_buf_str,
+                                         sizeof(ipv6_buf_str));
+               }
+               LOG_INFO(PFX "%s: IP configuration didn't change using 0x%x",
+                        nic->log_name, nic_iface->ustack.ip_config);
+               /* No need to acquire the IP address */
+               inet_ntop(AF_INET6, &ird.ipv6_addr, ipv6_buf_str,
+                         sizeof(ipv6_buf_str));
+
+               goto enable_nic;
+       }
+reacquire:
+       /* Config needs to re-acquire for this nic_iface */
+       pthread_mutex_lock(&nic->nic_mutex);
+       nic_iface->flags |= NIC_IFACE_ACQUIRE;
+       pthread_mutex_unlock(&nic->nic_mutex);
+
+       /* Disable the nic loop from further processing, upon returned,
+          the nic_iface should be cleared */
+       nic_disable(nic, 0);
+
+       /*  Check to see if this is using DHCP or if this is
+        *  a static IPv4 address.  This is done by checking
+        *  if the IP address is equal to 0.0.0.0.  If it is
+        *  then the user has specified to use DHCP.  If not
+        *  then the user has spcicied to use a static IP address
+        *  an the default netmask will be used */
+       switch (request_type) {
+       case IPV4_CONFIG_DHCP:
+               memset(nic_iface->ustack.hostaddr, 0, sizeof(struct in_addr));
+               LOG_INFO(PFX "%s: configuring using DHCP", nic->log_name);
+               nic_iface->ustack.ip_config = IPV4_CONFIG_DHCP;
+               break;
+
+       case IPV4_CONFIG_STATIC:
+               memcpy(nic_iface->ustack.hostaddr, &ird.ipv4_addr,
+                      sizeof(struct in_addr));
+               LOG_INFO(PFX "%s: configuring using static IP "
+                        "IPv4 address :%s ",
+                        nic->log_name, inet_ntoa(ird.ipv4_addr));
+
+               if (ird.ipv4_subnet_mask.s_addr)
+                       memcpy(nic_iface->ustack.netmask,
+                              &ird.ipv4_subnet_mask, sizeof(struct in_addr));
+               LOG_INFO(PFX " netmask: %s", inet_ntoa(ird.ipv4_subnet_mask));
+
+               /* Default route */
+               if (ird.ipv4_gateway.s_addr) {
+                       /* Check for validity */
+                       src_match.s_addr = ird.ipv4_addr.s_addr &
+                                          ird.ipv4_subnet_mask.s_addr;
+                       dst_match.s_addr = ird.ipv4_gateway.s_addr &
+                                          ird.ipv4_subnet_mask.s_addr;
+                       if (src_match.s_addr == dst_match.s_addr)
+                               memcpy(nic_iface->ustack.default_route_addr,
+                                      &ird.ipv4_gateway,
+                                      sizeof(struct in_addr));
+               }
+               nic_iface->ustack.ip_config = IPV4_CONFIG_STATIC;
+               break;
+
+       case IPV6_CONFIG_DHCP:
+               memset(nic_iface->ustack.hostaddr6, 0,
+                      sizeof(struct in6_addr));
+               nic_iface->ustack.prefix_len = ird.prefix_len;
+               nic_iface->ustack.ipv6_autocfg = ird.ipv6_autocfg;
+               nic_iface->ustack.linklocal_autocfg = ird.linklocal_autocfg;
+               nic_iface->ustack.router_autocfg = ird.router_autocfg;
+
+               if (memcmp(&ird.ipv6_subnet_mask, all_zeroes_addr6,
+                          sizeof(struct in6_addr)))
+                       memcpy(nic_iface->ustack.netmask6,
+                              &ird.ipv6_subnet_mask, sizeof(struct in6_addr));
+               if (ird.linklocal_autocfg == IPV6_LL_AUTOCFG_OFF)
+                       memcpy(nic_iface->ustack.linklocal6,
+                              &ird.ipv6_linklocal, sizeof(struct in6_addr));
+               if (ird.router_autocfg == IPV6_RTR_AUTOCFG_OFF)
+                       memcpy(nic_iface->ustack.default_route_addr6,
+                              &ird.ipv6_router, sizeof(struct in6_addr));
+               inet_ntop(AF_INET6, &ird.ipv6_addr, ipv6_buf_str,
+                         sizeof(ipv6_buf_str));
+               LOG_INFO(PFX "%s: configuring using DHCPv6",
+                        nic->log_name);
+               nic_iface->ustack.ip_config = IPV6_CONFIG_DHCP;
+               break;
+
+       case IPV6_CONFIG_STATIC:
+               memcpy(nic_iface->ustack.hostaddr6, &ird.ipv6_addr,
+                      sizeof(struct in6_addr));
+               nic_iface->ustack.prefix_len = ird.prefix_len;
+               nic_iface->ustack.ipv6_autocfg = ird.ipv6_autocfg;
+               nic_iface->ustack.linklocal_autocfg = ird.linklocal_autocfg;
+               nic_iface->ustack.router_autocfg = ird.router_autocfg;
+
+               if (memcmp(&ird.ipv6_subnet_mask, all_zeroes_addr6,
+                          sizeof(struct in6_addr)))
+                       memcpy(nic_iface->ustack.netmask6,
+                              &ird.ipv6_subnet_mask, sizeof(struct in6_addr));
+               if (ird.linklocal_autocfg == IPV6_LL_AUTOCFG_OFF)
+                       memcpy(nic_iface->ustack.linklocal6,
+                              &ird.ipv6_linklocal, sizeof(struct in6_addr));
+               if (ird.router_autocfg == IPV6_RTR_AUTOCFG_OFF)
+                       memcpy(nic_iface->ustack.default_route_addr6,
+                              &ird.ipv6_router, sizeof(struct in6_addr));
+
+               inet_ntop(AF_INET6, &ird.ipv6_addr, ipv6_buf_str,
+                         sizeof(ipv6_buf_str));
+               LOG_INFO(PFX "%s: configuring using static IP "
+                        "IPv6 address: '%s'", nic->log_name, ipv6_buf_str);
+
+               nic_iface->ustack.ip_config = IPV6_CONFIG_STATIC;
+               break;
+
+       default:
+               LOG_INFO(PFX "%s: Unknown request type: 0x%x",
+                        nic->log_name, request_type);
+
+       }
+
+enable_nic:
+       switch (nic->state) {
+       case NIC_STOPPED:
+               /* This thread will be thrown away when completed */
+               if (nic->enable_thread != INVALID_THREAD) {
+                       rc = pthread_cancel(nic->enable_thread);
+                       if (rc != 0) {
+                               LOG_INFO(PFX "%s: failed to cancel enable NIC "
+                                        "thread\n", nic->log_name);
+                               goto eagain;
+                       }
+               }
+               pthread_attr_init(&attr);
+               pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+               rc = pthread_create(&nic->enable_thread, &attr,
+                                   enable_nic_thread, (void *)nic);
+               if (rc != 0)
+                       LOG_WARN(PFX "%s: failed starting enable NIC thread\n",
+                                nic->log_name);
+eagain:
+               rc = -EAGAIN;
+               break;
+
+       case NIC_RUNNING:
+               LOG_INFO(PFX "%s: NIC already enabled "
+                        "flags: 0x%x state: 0x%x\n",
+                        nic->log_name, nic->flags, nic->state);
+               rc = 0;
+               break;
+       default:
+               LOG_INFO(PFX "%s: NIC enable still in progress "
+                        "flags: 0x%x state: 0x%x\n",
+                        nic->log_name, nic->flags, nic->state);
+               rc = -EAGAIN;
+       }
+
+       LOG_INFO(PFX "ISCSID_UIP_IPC_GET_IFACE: command: %x "
+                "name: %s, netdev: %s ipaddr: %s vlan: %d transport_name:%s",
+                data->header.command, rec->name, rec->netdev,
+                (ird.ip_type == AF_INET) ? inet_ntoa(ird.ipv4_addr) :
+                                            ipv6_buf_str,
+                ird.vlan_id, rec->transport_name);
+
+       if (do_ping) {
+               if (nic->ping_thread != INVALID_THREAD) {
+                       rc = pthread_cancel(nic->ping_thread);
+                       if (rc != 0) {
+                               LOG_INFO(PFX "%s: failed to cancel ping thread",
+                                        nic->log_name);
+                               rc = -EAGAIN;
+                               goto done;
+                       }
+               }
+
+               png_c = malloc(sizeof(struct ping_conf));
+               if (!png_c) {
+                       LOG_ERR(PFX "Memory alloc failed for ping conf");
+                       rc = -ENOMEM;
+                       goto done;
+               }
+
+               memset(png_c, 0, sizeof(struct ping_conf));
+               png_c->nic_iface = nic_iface;
+               png_c->data = arg;
+               nic_iface->ustack.ping_conf = png_c;
+
+               /* Spawn a thread to perform ping operation.
+                * This thread will exit when done.
+                */
+               rc = pthread_create(&nic->ping_thread, NULL,
+                                   perform_ping, (void *)png_c);
+               if (rc != 0) {
+                       LOG_WARN(PFX "%s: failed starting ping thread\n",
+                                nic->log_name);
+               } else {
+                       pthread_join(nic->ping_thread, NULL);
+                       rc = png_c->state;
+                       if (rc == -EAGAIN)
+                               png_c->state = 0;
+               }
+               free(png_c);
+               nic_iface->ustack.ping_conf = NULL;
+       }
+
+done:
+       pthread_mutex_unlock(&nic_list_mutex);
+
+early_exit:
+       return rc;
+}
+
+/**
+ *  process_iscsid_broadcast() - This function is used to process the
+ *                               broadcast messages from iscsid
+ *
+ *                               s2 is an open file descriptor, which
+ *                               must not be left open upon return
+ */
+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));
+               close(s2);
+               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;
+       if (payload_len > sizeof(data->u)) {
+               LOG_ERR(PFX "Data payload length too large (%d). Corrupt payload?",
+                               payload_len);
+               rc = -EINVAL;
+               goto error;
+       }
+
+       LOG_DEBUG(PFX "recv iscsid request: cmd: %d, payload_len: %d",
+                 cmd, payload_len);
+
+       memset(&rsp, 0, sizeof(rsp));
+
+       switch (cmd) {
+       case ISCSID_UIP_IPC_GET_IFACE:
+               size = fread(&data->u.iface_rec, payload_len, 1, fd);
+               if (!size) {
+                       LOG_ERR(PFX "Could not read data: %d(%s)",
+                               errno, strerror(errno));
+                       goto error;
+               }
+
+               rc = parse_iface(data, 0);
+               switch (rc) {
+               case 0:
+                       rsp.command = cmd;
+                       rsp.err = ISCSID_UIP_MGMT_IPC_DEVICE_UP;
+                       break;
+               case -EAGAIN:
+                       rsp.command = cmd;
+                       rsp.err = ISCSID_UIP_MGMT_IPC_DEVICE_INITIALIZING;
+                       break;
+               default:
+                       rsp.command = cmd;
+                       rsp.err = ISCSID_UIP_MGMT_IPC_ERR;
+               }
+
+               break;
+       case ISCSID_UIP_IPC_PING:
+               size = fread(&data->u.ping_rec, payload_len, 1, fd);
+               if (!size) {
+                       LOG_ERR(PFX "Could not read data: %d(%s)",
+                               errno, strerror(errno));
+                       goto error;
+               }
+
+               rc = parse_iface(data, 1);
+               rsp.command = cmd;
+               rsp.ping_sc = rc;
+
+               switch (rc) {
+               case 0:
+                       rsp.err = ISCSID_UIP_MGMT_IPC_DEVICE_UP;
+                       break;
+               case -EAGAIN:
+                       rsp.err = ISCSID_UIP_MGMT_IPC_DEVICE_INITIALIZING;
+                       break;
+               default:
+                       rsp.err = ISCSID_UIP_MGMT_IPC_ERR;
+               }
+
+               break;
+       default:
+               LOG_WARN(PFX "Unknown iscsid broadcast command: %x",
+                        data->header.command);
+
+               /*  Send a response back to iscsid to tell it the
+                  operation succeeded */
+               rsp.command = cmd;
+               rsp.err = ISCSID_UIP_MGMT_IPC_OK;
+               break;
+       }
+
+       size = fwrite(&rsp, sizeof(rsp), 1, fd);
+       if (size == -1) {
+               LOG_ERR(PFX "Could not send response: %d(%s)",
+                       errno, strerror(errno));
+               rc = ferror(fd);
+       }
+
+error:
+       if (data)
+               free(data);
+       fclose(fd);
+
+       return rc;
+}
+
+static void iscsid_loop_close(void *arg)
+{
+       close(iscsid_opts.fd);
+
+       LOG_INFO(PFX "iSCSI daemon socket closed");
+}
+
+/*
+ * check that the peer user is privilidged
+ *
+ * return 1 if peer is ok else 0
+ *
+ * XXX: this function is copied from iscsid_ipc.c and should be
+ * moved into a common library
+ */
+static int
+mgmt_peeruser(int sock, char *user)
+{
+       struct ucred peercred;
+       socklen_t so_len = sizeof(peercred);
+       struct passwd *pass;
+
+       errno = 0;
+       if (getsockopt(sock, SOL_SOCKET, SO_PEERCRED, &peercred,
+               &so_len) != 0 || so_len != sizeof(peercred)) {
+               /* We didn't get a valid credentials struct. */
+               LOG_ERR(PFX "peeruser_unux: error receiving credentials: %m");
+               return 0;
+       }
+
+       pass = getpwuid(peercred.uid);
+       if (pass == NULL) {
+               LOG_ERR(PFX "peeruser_unix: unknown local user with uid %d",
+                               (int) peercred.uid);
+               return 0;
+       }
+
+       strlcpy(user, pass->pw_name, PEERUSER_MAX);
+       return 1;
+}
+
+/**
+ *  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;
+       char user[PEERUSER_MAX];
+
+       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;
+               }
+
+               if (!mgmt_peeruser(iscsid_opts.fd, user) || strncmp(user, "root", PEERUSER_MAX)) {
+                       close(s2);
+                       LOG_ERR(PFX "Access error: non-administrative connection rejected");
+                       break;
+               }
+
+               /* this closes the file descriptor s2 */
+               process_iscsid_broadcast(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 &&
+           iscsid_opts.thread != INVALID_THREAD) {
+               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/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/iscsid_ipc.h b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/iscsid_ipc.h
new file mode 100644 (file)
index 0000000..60bcd71
--- /dev/null
@@ -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/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/libs/Makefile.am b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/libs/Makefile.am
new file mode 100644 (file)
index 0000000..737546b
--- /dev/null
@@ -0,0 +1,14 @@
+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         \
+                                       qedi.c
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/libs/bnx2.c b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/libs/bnx2.c
new file mode 100644 (file)
index 0000000..1181cf4
--- /dev/null
@@ -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/sysmacros.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 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 "
+                                       "receive ", 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/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/libs/bnx2.h b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/libs/bnx2.h
new file mode 100644 (file)
index 0000000..3ec9437
--- /dev/null
@@ -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/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/libs/bnx2x.c b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/libs/bnx2x.c
new file mode 100644 (file)
index 0000000..7481e86
--- /dev/null
@@ -0,0 +1,1676 @@
+/*
+ * 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 nic.h before linux/ethtool.h to avoid redefinitions of
+ * eth structs
+*/
+#include "nic.h"
+#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/sysmacros.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_id.h"
+#include "nic_utils.h"
+#include "options.h"
+
+#define PFX    "bnx2x "
+
+/*  Foward struct declarations */
+struct nic_ops bnx2x_op;
+
+/*******************************************************************************
+ * NIC Library Strings
+ ******************************************************************************/
+static const char library_name[] = "bnx2x";
+static const char library_version[] = PACKAGE_VERSION;
+static const char library_uio_name[] = "bnx2x_cnic";
+
+/*  The name that should be returned from /sys/class/uio/uio0/name */
+static const char cnic_uio_sysfs_name_tempate[] = "/sys/class/uio/uio%i/name";
+static const char bnx2x_uio_sysfs_name[] = "bnx2x_cnic";
+
+/*******************************************************************************
+ * String constants used to display human readable adapter name
+ ******************************************************************************/
+static const char brcm_57710[] = "QLogic NetXtreme II BCM57710 10-Gigabit";
+static const char brcm_57711[] = "QLogic NetXtreme II BCM57711 10-Gigabit";
+static const char brcm_57711e[] = "QLogic NetXtreme II BCM57711E 10-Gigabit";
+static const char brcm_57712[] = "QLogic NetXtreme II BCM57712 10-Gigabit";
+static const char brcm_57712_MF[] = "QLogic NetXtreme II BCM57712 MF "
+                                   "10-Gigabit";
+static const char brcm_57712_VF[] = "QLogic NetXtreme II BCM57712 VF "
+                                   "10-Gigabit";
+static const char brcm_57713[] = "QLogic NetXtreme II BCM57713 10-Gigabit";
+static const char brcm_57713e[] = "QLogic NetXtreme II BCM57713E 10-Gigabit";
+static const char brcm_57800[] = "QLogic NetXtreme II BCM57800 10-Gigabit";
+static const char brcm_57800_MF[] = "QLogic NetXtreme II BCM57800 MF "
+                                   "10-Gigabit";
+static const char brcm_57800_VF[] = "QLogic NetXtreme II BCM57800 VF "
+                                   "10-Gigabit";
+static const char brcm_57810[] = "QLogic NetXtreme II BCM57810 10-Gigabit";
+static const char brcm_57810_MF[] = "QLogic NetXtreme II BCM57810 MF "
+                                   "10-Gigabit";
+static const char brcm_57810_VF[] = "QLogic NetXtreme II BCM57810 VF "
+                                   "10-Gigabit";
+static const char brcm_57811[] = "QLogic NetXtreme II BCM57811 10-Gigabit";
+static const char brcm_57811_MF[] = "QLogic NetXtreme II BCM57811 MF "
+                                   "10-Gigabit";
+static const char brcm_57811_VF[] = "QLogic NetXtreme II BCM57811 VF "
+                                   "10-Gigabit";
+static const char brcm_57840[] = "QLogic NetXtreme II BCM57840 10-Gigabit";
+static const char brcm_57840_MF[] = "QLogic NetXtreme II BCM57840 MF "
+                                   "10-Gigabit";
+static const char brcm_57840_VF[] = "QLogic NetXtreme II BCM57840 VF "
+                                   "10-Gigabit";
+static const char brcm_57840_4_10[] = "QLogic NetXtreme II BCM57840 4x"
+                                     "10-Gigabit";
+static const char brcm_57840_2_20[] = "QLogic NetXtreme II BCM57840 2x"
+                                     "20-Gigabit";
+
+/*******************************************************************************
+ * PCI ID constants
+ ******************************************************************************/
+#define PCI_VENDOR_ID_BROADCOM                 0x14e4
+#define PCI_VENDOR_ID_QLOGIC                   0x1077
+#define PCI_DEVICE_ID_NX2_57710                        0x164e
+#define PCI_DEVICE_ID_NX2_57711                        0x164f
+#define PCI_DEVICE_ID_NX2_57711E               0x1650
+#define PCI_DEVICE_ID_NX2_57712                        0x1662
+#define PCI_DEVICE_ID_NX2_57712_MF             0x1663
+#define PCI_DEVICE_ID_NX2_57712_VF             0x166f
+#define PCI_DEVICE_ID_NX2_57713                        0x1651
+#define PCI_DEVICE_ID_NX2_57713E               0x1652
+#define PCI_DEVICE_ID_NX2_57800                        0x168a
+#define PCI_DEVICE_ID_NX2_57800_MF             0x16a5
+#define PCI_DEVICE_ID_NX2_57800_VF             0x16a9
+#define PCI_DEVICE_ID_NX2_57810                        0x168e
+#define PCI_DEVICE_ID_NX2_57810_MF             0x16ae
+#define PCI_DEVICE_ID_NX2_57810_VF             0x16af
+#define PCI_DEVICE_ID_NX2_57811                        0x163d
+#define PCI_DEVICE_ID_NX2_57811_MF             0x163e
+#define PCI_DEVICE_ID_NX2_57811_VF             0x163f
+#define PCI_DEVICE_ID_NX2_57840_OBSOLETE       0x168d
+#define PCI_DEVICE_ID_NX2_57840_MF_OBSOLETE    0x16ab
+#define PCI_DEVICE_ID_NX2_57840_4_10           0x16a1
+#define PCI_DEVICE_ID_NX2_57840_2_20           0x16a2
+#define PCI_DEVICE_ID_NX2_57840_MF             0x16a4
+#define PCI_DEVICE_ID_NX2_57840_VF             0x16ad
+#define PCI_ANY_ID (~0)
+
+/*  This is the table used to match PCI vendor and device ID's to the
+ *  human readable string names of the devices */
+static const struct pci_device_id bnx2x_pci_tbl[] = {
+       {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57710,
+        PCI_ANY_ID, PCI_ANY_ID, brcm_57710},
+       {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57711,
+        PCI_ANY_ID, PCI_ANY_ID, brcm_57711},
+       {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57711E,
+        PCI_ANY_ID, PCI_ANY_ID, brcm_57711e},
+       {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57712,
+        PCI_ANY_ID, PCI_ANY_ID, brcm_57712},
+       {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57712_MF,
+        PCI_ANY_ID, PCI_ANY_ID, brcm_57712_MF},
+       {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57712_VF,
+        PCI_ANY_ID, PCI_ANY_ID, brcm_57712_VF},
+       {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57713,
+        PCI_ANY_ID, PCI_ANY_ID, brcm_57713},
+       {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57713E,
+        PCI_ANY_ID, PCI_ANY_ID, brcm_57713e},
+       {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57800,
+        PCI_ANY_ID, PCI_ANY_ID, brcm_57800},
+       {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57800_MF,
+        PCI_ANY_ID, PCI_ANY_ID, brcm_57800_MF},
+       {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57800_VF,
+        PCI_ANY_ID, PCI_ANY_ID, brcm_57800_VF},
+       {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57810,
+        PCI_ANY_ID, PCI_ANY_ID, brcm_57810},
+       {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57810_MF,
+        PCI_ANY_ID, PCI_ANY_ID, brcm_57810_MF},
+       {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57810_VF,
+        PCI_ANY_ID, PCI_ANY_ID, brcm_57810_VF},
+       {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57811,
+        PCI_ANY_ID, PCI_ANY_ID, brcm_57811},
+       {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57811_MF,
+        PCI_ANY_ID, PCI_ANY_ID, brcm_57811_MF},
+       {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57811_VF,
+        PCI_ANY_ID, PCI_ANY_ID, brcm_57811_VF},
+       {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57840_OBSOLETE,
+        PCI_ANY_ID, PCI_ANY_ID, brcm_57840},
+       {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57840_MF_OBSOLETE,
+        PCI_ANY_ID, PCI_ANY_ID, brcm_57840_MF},
+       {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57840_4_10,
+        PCI_ANY_ID, PCI_ANY_ID, brcm_57840_4_10},
+       {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57840_2_20,
+        PCI_ANY_ID, PCI_ANY_ID, brcm_57840_2_20},
+       {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57840_MF,
+        PCI_ANY_ID, PCI_ANY_ID, brcm_57840_MF},
+       {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57840_VF,
+        PCI_ANY_ID, PCI_ANY_ID, brcm_57840_VF},
+       {PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_NX2_57840_4_10,
+        PCI_ANY_ID, PCI_ANY_ID, brcm_57840_4_10},
+       {PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_NX2_57840_2_20,
+        PCI_ANY_ID, PCI_ANY_ID, brcm_57840_2_20},
+       {PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_NX2_57840_MF,
+        PCI_ANY_ID, PCI_ANY_ID, brcm_57840_MF},
+       {PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_NX2_57840_VF,
+        PCI_ANY_ID, PCI_ANY_ID, brcm_57840_VF},
+};
+
+static struct iro e1_iro[2] = {
+       {0x45a0, 0x90, 0x8, 0x0, 0x8},  /* T6.0 */
+       {0x50c8, 0x90, 0x8, 0x0, 0x8},  /* T6.4 */
+};
+
+static struct iro e1h_iro[2] = {
+       {0x1c40, 0xe0, 0x8, 0x0, 0x8},  /* T6.0 */
+       {0x1e00, 0xe0, 0x8, 0x0, 0x8},  /* T6.4 */
+};
+
+static struct iro e2_iro[2] = {
+       {0x6000, 0x20, 0x0, 0x0, 0x8},  /* T6.0 */
+       {0x6000, 0x20, 0x0, 0x0, 0x8},  /* T6.4 */
+};
+
+struct bnx2x_driver_version bnx2x_version = {
+       BNX2X_UNKNOWN_MAJOR_VERSION,
+       BNX2X_UNKNOWN_MINOR_VERSION,
+       BNX2X_UNKNOWN_SUB_MINOR_VERSION,
+};
+
+static int bnx2x_clear_tx_intr(nic_t *nic);
+
+/*******************************************************************************
+ * BNX2X Library Functions
+ ******************************************************************************/
+/**
+ *  bnx2x_get_library_name() - Used to get the name of this NIC libary
+ *  @param name - This function will return the pointer to this NIC
+ *                library name
+ *  @param name_size
+ */
+static void bnx2x_get_library_name(char **name, size_t *name_size)
+{
+       *name = (char *)library_name;
+       *name_size = sizeof(library_name);
+}
+
+/**
+ *  bnx2x_get_library_version() - Used to get the version string of this
+ *                                NIC libary
+ *  @param version - This function will return the pointer to this NIC
+ *                   library version string
+ *  @param version_size - This will be set with the version size
+ */
+static void bnx2x_get_library_version(char **version, size_t *version_size)
+{
+       *version = (char *)library_version;
+       *version_size = sizeof(library_version);
+}
+
+/**
+ *  bnx2x_get_build_date() - Used to get the build date string of this library
+ *  @param version - This function will return the pointer to this NIC
+ *                   library build date string
+ *  @param version_size - This will be set with the build date string size
+ */
+static void bnx2x_get_build_date(char **build, size_t *build_size)
+{
+       *build = (char *)build_date;
+       *build_size = sizeof(build_date);
+}
+
+/**
+ *  bnx2x_get_transport_name() - Used to get the transport name associated
+ *                              with this this NIC libary
+ *  @param transport_name - This function will return the pointer to this NIC
+ *                          library's associated transport string
+ *  @param transport_name_size - This will be set with the transport name size
+ */
+static void bnx2x_get_transport_name(char **transport_name,
+                                    size_t *transport_name_size)
+{
+       *transport_name = (char *)bnx2i_library_transport_name;
+       *transport_name_size = bnx2i_library_transport_name_size;
+}
+
+/**
+ *  bnx2x_get_uio_name() - Used to get the uio name associated with this this
+ *                        NIC libary
+ *  @param uio_name - This function will return the pointer to this NIC
+ *                    library's associated uio string
+ *  @param transport_name_size - This will be set with the uio name size
+ */
+static void bnx2x_get_uio_name(char **uio_name, size_t *uio_name_size)
+{
+       *uio_name = (char *)library_uio_name;
+       *uio_name_size = sizeof(library_uio_name);
+}
+
+/**
+ *  bnx2x_get_pci_table() - Used to get the PCI table for this NIC libary to
+ *                         determine which NIC's based off of PCI ID's are
+ *                         supported
+ *  @param table - This function will return the pointer to the PCI table
+ *  @param entries - This function will return the number of entries in the NIC
+ *                   library's PCI table
+ */
+static void bnx2x_get_pci_table(struct pci_device_id **table,
+                               uint32_t *entries)
+{
+       *table = (struct pci_device_id *)bnx2x_pci_tbl;
+       *entries =
+           (uint32_t) (sizeof(bnx2x_pci_tbl) / sizeof(bnx2x_pci_tbl[0]));
+}
+
+/**
+ *  bnx2x_get_ops() - Used to get the NIC library op table
+ *  @param op - The op table of this NIC library
+ */
+struct nic_ops *bnx2x_get_ops()
+{
+       return &bnx2x_op;
+}
+
+/*******************************************************************************
+ * bnx2x Utility Functions
+ ******************************************************************************/
+/*******************************************************************************
+ * Utility Functions Used to read register from the bnx2x device
+ ******************************************************************************/
+static void bnx2x_set_drv_version_unknown(bnx2x_t *bp)
+{
+       bp->version.major = BNX2X_UNKNOWN_MAJOR_VERSION;
+       bp->version.minor = BNX2X_UNKNOWN_MINOR_VERSION;
+       bp->version.sub_minor = BNX2X_UNKNOWN_SUB_MINOR_VERSION;
+}
+
+/* Return: 1 = Unknown, 0 = Known */
+static int bnx2x_is_drv_version_unknown(struct bnx2x_driver_version *version)
+{
+       if ((version->major == (uint16_t)BNX2X_UNKNOWN_MAJOR_VERSION) &&
+           (version->minor == (uint16_t)BNX2X_UNKNOWN_MINOR_VERSION) &&
+           (version->sub_minor == (uint16_t)BNX2X_UNKNOWN_SUB_MINOR_VERSION)) {
+               return 1;
+       }
+
+       return 0;
+}
+
+static void bnx2x_set_drv_version_default(bnx2x_t *bp)
+{
+       bp->version.major = BNX2X_DEFAULT_MAJOR_VERSION;
+       bp->version.minor = BNX2X_DEFAULT_MINOR_VERSION;
+       bp->version.sub_minor = BNX2X_DEFAULT_SUB_MINOR_VERSION;
+}
+
+/**
+ * bnx2x_get_drv_version() - Used to determine the driver version
+ * @param bp - Device used to determine bnx2x driver version
+ */
+static int bnx2x_get_drv_version(bnx2x_t *bp)
+{
+       nic_t *nic = bp->parent;
+       int fd, rc;
+       struct ifreq ifr;
+       struct ethtool_drvinfo drvinfo;
+       char *tok, *save_ptr = NULL;
+
+       /* Setup our control structures. */
+       memset(&ifr, 0, sizeof(ifr));
+       strcpy(ifr.ifr_name, nic->eth_device_name);
+
+       /* Open control socket. */
+       fd = socket(AF_INET, SOCK_DGRAM, 0);
+       if (fd < 0) {
+               LOG_ERR(PFX "%s: Cannot get socket to determine version "
+                       "[0x%x %s]", nic->log_name, errno, strerror(errno));
+               return -EIO;
+       }
+
+       memset(&drvinfo, 0, sizeof(drvinfo));
+       drvinfo.cmd = ETHTOOL_GDRVINFO;
+       ifr.ifr_data = (caddr_t) &drvinfo;
+       rc = ioctl(fd, SIOCETHTOOL, &ifr);
+       if (rc < 0) {
+               LOG_ERR(PFX "%s: call to ethool IOCTL failed [0x%x %s]",
+                       nic->log_name, errno, strerror(errno));
+               goto error;
+       }
+
+       tok = strtok_r(drvinfo.version, ".", &save_ptr);
+       if (tok == NULL) {
+               rc = -EIO;
+               goto error;
+       }
+       bp->version.major = atoi(tok);
+
+       tok = strtok_r(NULL, ".", &save_ptr);
+       if (tok == NULL) {
+               rc = -EIO;
+               goto error;
+       }
+       bp->version.minor = atoi(tok);
+
+       tok = strtok_r(NULL, ".", &save_ptr);
+       if (tok == NULL) {
+               rc = -EIO;
+               goto error;
+       }
+       bp->version.sub_minor = atoi(tok);
+
+       LOG_INFO(PFX "%s: interface version %d.%d.%d", nic->log_name,
+                bp->version.major, bp->version.minor, bp->version.sub_minor);
+
+       close(fd);
+
+       return 0;
+
+error:
+       close(fd);
+       bnx2x_set_drv_version_unknown(bp);
+
+       LOG_ERR(PFX "%s: error parsing driver string: '%s'",
+               nic->log_name, drvinfo.version);
+
+       return rc;
+
+}
+
+static inline int bnx2x_is_ver70(bnx2x_t *bp)
+{
+       return (bp->version.major == 1 && bp->version.minor >= 70);
+}
+
+static inline int bnx2x_is_ver60(bnx2x_t *bp)
+{
+       return (bp->version.major == 1 && (bp->version.minor == 60 ||
+                                          bp->version.minor == 62 ||
+                                          bp->version.minor == 64));
+}
+
+static inline int bnx2x_is_ver60_plus(bnx2x_t *bp)
+{
+       return bnx2x_is_ver60(bp) || bnx2x_is_ver70(bp);
+}
+
+static inline int bnx2x_is_ver52(bnx2x_t *bp)
+{
+       return (bp->version.major == 1 && bp->version.minor == 52);
+}
+
+static void bnx2x_wr32(bnx2x_t *bp, __u32 off, __u32 val)
+{
+       *((volatile __u32 *)(bp->reg + off)) = val;
+}
+
+static void bnx2x_doorbell(bnx2x_t *bp, __u32 off, __u32 val)
+{
+       *((volatile __u32 *)(bp->reg2 + off)) = val;
+}
+
+static void bnx2x_flush_doorbell(bnx2x_t *bp, __u32 off)
+{
+       volatile __u32 tmp __attribute__((__unused__));
+
+       barrier();
+       tmp = *((volatile __u32 *)(bp->reg2 + off));
+}
+
+static __u32 bnx2x_rd32(bnx2x_t *bp, __u32 off)
+{
+       return *((volatile __u32 *)(bp->reg + off));
+}
+
+static int bnx2x_reg_sync(bnx2x_t *bp, __u32 off, __u16 length)
+{
+       return msync(bp->reg + off, length, MS_SYNC);
+}
+
+static void bnx2x_update_rx_prod(bnx2x_t *bp)
+{
+       struct ustorm_eth_rx_producers rx_prods = { 0 };
+       int i;
+
+       rx_prods.bd_prod = bp->rx_bd_prod;
+       rx_prods.cqe_prod = bp->rx_prod;
+
+       barrier();
+
+       for (i = 0; i < sizeof(struct ustorm_eth_rx_producers) / 4; i++)
+               bnx2x_wr32(bp, bp->rx_prod_io + i * 4,
+                          ((__u32 *)&rx_prods)[i]);
+
+       barrier();
+
+       bnx2x_reg_sync(bp, bp->rx_prod_io,
+                      sizeof(struct ustorm_eth_rx_producers));
+}
+
+/**
+ * bnx2x_get_chip_id() - Used to retrive the chip ID from the nic
+ * @param dev - Device used to determin NIC type
+ * @return Chip ID read from the MISC ID register
+ */
+static int bnx2x_get_chip_id(bnx2x_t *bp)
+{
+       int val, id;
+
+       /* Get the chip revision id and number. */
+       /* chip num:16-31, rev:12-15, metal:4-11, bond_id:0-3 */
+       val = bnx2x_rd32(bp, BNX2X_MISC_REG_CHIP_NUM);
+       id = ((val & 0xffff) << 16);
+       val = bnx2x_rd32(bp, BNX2X_MISC_REG_CHIP_REV);
+       id |= ((val & 0xf) << 12);
+       val = bnx2x_rd32(bp, BNX2X_MISC_REG_CHIP_METAL);
+       id |= ((val & 0xff) << 4);
+       val = bnx2x_rd32(bp, BNX2X_MISC_REG_BOND_ID);
+       id |= (val & 0xf);
+
+       return id;
+}
+
+/**
+ *  bnx2x_uio_verify()
+ *
+ */
+static int bnx2x_uio_verify(nic_t *nic)
+{
+       char *raw = NULL, *raw_tmp;
+       uint32_t raw_size = 0;
+       char temp_path[sizeof(cnic_uio_sysfs_name_tempate) + 8];
+       int rc = 0;
+
+       /*  Build the path to determine uio name */
+       snprintf(temp_path, sizeof(temp_path),
+                cnic_uio_sysfs_name_tempate, nic->uio_minor);
+
+       rc = capture_file(&raw, &raw_size, temp_path);
+       if (rc != 0)
+               goto error;
+
+       /* sanitize name string by replacing newline with null termination */
+       raw_tmp = raw;
+       while (*raw_tmp != '\n')
+               raw_tmp++;
+       *raw_tmp = '\0';
+
+       if (strncmp(raw, bnx2x_uio_sysfs_name,
+                   sizeof(bnx2x_uio_sysfs_name)) != 0) {
+               LOG_ERR(PFX "%s: uio names not equal: "
+                       "expecting %s got %s from %s",
+                       nic->log_name, bnx2x_uio_sysfs_name, raw, temp_path);
+               rc = -EIO;
+       }
+
+       free(raw);
+
+       LOG_INFO(PFX "%s: Verified is a cnic_uio device", nic->log_name);
+
+error:
+       return rc;
+}
+
+/*******************************************************************************
+ * bnx2x Utility Functions to get to the hardware consumer indexes
+ ******************************************************************************/
+static __u16 bnx2x_get_rx(bnx2x_t *bp)
+{
+       struct host_def_status_block *sblk = bp->status_blk.def;
+       __u16 rx_comp_cons;
+
+       msync(sblk, sizeof(*sblk), MS_SYNC);
+       rx_comp_cons =
+           sblk->u_def_status_block.
+           index_values[HC_INDEX_DEF_U_ETH_ISCSI_RX_CQ_CONS];
+       if ((rx_comp_cons & BNX2X_MAX_RCQ_DESC_CNT(bp)) ==
+           BNX2X_MAX_RCQ_DESC_CNT(bp))
+               rx_comp_cons++;
+
+       return rx_comp_cons;
+}
+
+static __u16 bnx2x_get_rx_60(bnx2x_t *bp)
+{
+       struct host_sp_status_block *sblk = bp->status_blk.sp;
+       __u16 rx_comp_cons;
+
+       msync(sblk, sizeof(*sblk), MS_SYNC);
+       rx_comp_cons =
+           sblk->sp_sb.index_values[HC_SP_INDEX_ETH_ISCSI_RX_CQ_CONS];
+       if ((rx_comp_cons & BNX2X_MAX_RCQ_DESC_CNT(bp)) ==
+           BNX2X_MAX_RCQ_DESC_CNT(bp))
+               rx_comp_cons++;
+
+       return rx_comp_cons;
+}
+
+static __u16 bnx2x_get_tx(bnx2x_t *bp)
+{
+       struct host_def_status_block *sblk = bp->status_blk.def;
+       __u16 tx_cons;
+
+       msync(sblk, sizeof(*sblk), MS_SYNC);
+       tx_cons =
+           sblk->c_def_status_block.
+           index_values[HC_INDEX_DEF_C_ETH_ISCSI_CQ_CONS];
+
+       return tx_cons;
+}
+
+static __u16 bnx2x_get_tx_60(bnx2x_t *bp)
+{
+       struct host_sp_status_block *sblk = bp->status_blk.sp;
+       __u16 tx_cons;
+
+       msync(sblk, sizeof(*sblk), MS_SYNC);
+       tx_cons = sblk->sp_sb.index_values[HC_SP_INDEX_ETH_ISCSI_CQ_CONS];
+
+       return tx_cons;
+}
+
+typedef enum {
+       CNIC_VLAN_STRIPPING_ENABLED = 1,
+       CNIC_VLAN_STRIPPING_DISABLED = 2,
+} CNIC_VLAN_STRIPPING_MODE;
+
+/**
+ *  bnx2x_strip_vlan_enabled() - This will query the device to determine whether
+ *                              VLAN tag stripping is enabled or not
+ *  @param dev - device to check stripping or not
+ *  @ return CNIC_VLAN_STRIPPING_ENABLED stripping is enabled
+ *           CNIC_VLAN_STRIPPING_DISABLED stripping is not enabled
+ */
+static CNIC_VLAN_STRIPPING_MODE bnx2x_strip_vlan_enabled(bnx2x_t *bp)
+{
+       return CNIC_VLAN_STRIPPING_DISABLED;
+}
+
+/**
+ *  bnx2x_free() - Used to free a bnx2x structure
+ */
+static void bnx2x_free(nic_t *nic)
+{
+       if (nic->priv)
+               free(nic->priv);
+       nic->priv = NULL;
+}
+
+/**
+ *  bnx2x_alloc() - Used to allocate a bnx2x structure
+ */
+static bnx2x_t *bnx2x_alloc(nic_t *nic)
+{
+       bnx2x_t *bp = malloc(sizeof(*bp));
+
+       if (bp == NULL) {
+               LOG_ERR(PFX "%s: Could not allocate BNX2X space",
+                       nic->log_name);
+               return NULL;
+       }
+
+       /*  Clear out the CNIC contents */
+       memset(bp, 0, sizeof(*bp));
+
+       bp->bar0_fd = INVALID_FD;
+       bp->bar2_fd = INVALID_FD;
+
+       bp->parent = nic;
+       nic->priv = (void *)bp;
+
+       bnx2x_set_drv_version_unknown(bp);
+
+       return bp;
+}
+
+/**
+ * bnx2x_open() - This will initialize all the hardware resources underneath
+ *               a struct cnic_uio device
+ * @param dev - The struct cnic_uio device to attach the hardware with
+ * @return 0 on success, on failure a errno will be returned
+ */
+static int bnx2x_open(nic_t *nic)
+{
+       bnx2x_t *bp;
+       struct stat uio_stat;
+       int i, rc;
+       __u32 val;
+       int count;
+       char sysfs_resc_path[80];
+       uint32_t bus;
+       uint32_t slot;
+       uint32_t func;
+       uint32_t mode;
+       __u32 proto_offset;
+       __u32 ovtag_offset;
+
+       /*  Sanity Check: validate the parameters */
+       if (nic == NULL) {
+               LOG_ERR(PFX "nic == NULL");
+               return -EINVAL;
+       }
+
+       if ((nic->priv) != NULL &&
+           (((bnx2x_t *) (nic->priv))->flags & BNX2X_OPENED)) {
+               return 0;
+       }
+
+       bp = bnx2x_alloc(nic);
+       if (bp == NULL)
+               return -ENOMEM;
+
+       if (bnx2x_is_drv_version_unknown(&bnx2x_version)) {
+               /* If version is unknown, go read from ethtool */
+               rc = bnx2x_get_drv_version(bp);
+               if (rc)
+                       bnx2x_set_drv_version_default(bp);
+               else if (!(bnx2x_is_ver60_plus(bp) || bnx2x_is_ver52(bp)))
+                       bnx2x_set_drv_version_default(bp);
+
+               LOG_INFO(PFX "%s: bnx2x Use baseline version %d.%d.%d",
+                        nic->log_name,
+                        bp->version.major, bp->version.minor,
+                        bp->version.sub_minor);
+       } 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 (nic->fd == INVALID_FD) {
+               LOG_ERR(PFX "%s: Could not open device: %s, [%s]",
+                       nic->log_name, nic->uio_device_name,
+                       strerror(errno));
+               rc = errno;
+               goto open_error;
+       }
+       if (fstat(nic->fd, &uio_stat) < 0) {
+               LOG_ERR(PFX "%s: Could not fstat device", nic->log_name);
+               rc = -ENODEV;
+               goto open_error;
+       }
+       nic->uio_minor = minor(uio_stat.st_rdev);
+
+       cnic_get_sysfs_pci_resource_path(nic, 0, sysfs_resc_path, 80);
+       bp->bar0_fd = open(sysfs_resc_path, O_RDWR | O_SYNC);
+       if (bp->bar0_fd < 0) {
+               LOG_ERR(PFX "%s: Could not open %s", nic->log_name,
+                       sysfs_resc_path);
+               rc = -ENODEV;
+               goto open_error;
+       }
+
+       bp->reg = mmap(NULL, BNX2X_BAR_SIZE, PROT_READ | PROT_WRITE,
+                       MAP_SHARED, bp->bar0_fd, (off_t) 0);
+
+       if (bp->reg == MAP_FAILED) {
+               LOG_INFO(PFX "%s: Couldn't mmap BAR registers: %s",
+                        nic->log_name, strerror(errno));
+               bp->reg = NULL;
+               rc = errno;
+               goto open_error;
+       }
+
+       msync(bp->reg, BNX2X_BAR_SIZE, MS_SYNC);
+
+       cnic_get_sysfs_pci_resource_path(nic, 2, sysfs_resc_path, 80);
+       bp->bar2_fd = open(sysfs_resc_path, O_RDWR | O_SYNC);
+       if (bp->bar2_fd < 0) {
+               LOG_ERR(PFX "%s: Could not open %s", nic->log_name,
+                       sysfs_resc_path);
+               rc = -ENODEV;
+               goto open_error;
+       }
+
+       bp->reg2 = mmap(NULL, BNX2X_BAR2_SIZE, PROT_READ | PROT_WRITE,
+                       MAP_SHARED, bp->bar2_fd, (off_t) 0);
+
+       if (bp->reg2 == MAP_FAILED) {
+               LOG_INFO(PFX "%s: Couldn't mmap BAR2 registers: %s",
+                        nic->log_name, strerror(errno));
+               bp->reg2 = NULL;
+               rc = errno;
+               goto open_error;
+       }
+
+       /*  TODO: hardcoded with the cnic driver */
+       bp->rx_ring_size = 15;
+       bp->rx_buffer_size = 0x400;
+
+       LOG_DEBUG(PFX "%s: using rx ring size: %d, rx buffer size: %d",
+                 nic->log_name, bp->rx_ring_size, bp->rx_buffer_size);
+
+       /*  Determine the number of UIO events that have already occured */
+       rc = detemine_initial_uio_events(nic, &nic->intr_count);
+       if (rc != 0) {
+               LOG_ERR("Could not determine the number ofinitial UIO events");
+               nic->intr_count = 0;
+       }
+
+       /*  Allocate space for rx pkt ring */
+       bp->rx_pkt_ring = malloc(sizeof(void *) * bp->rx_ring_size);
+       if (bp->rx_pkt_ring == NULL) {
+               LOG_ERR(PFX "%s: Could not allocate space for rx_pkt_ring",
+                       nic->log_name);
+               rc = errno;
+               goto open_error;
+       }
+
+       if (bnx2x_is_ver60_plus(bp))
+               bp->status_blk_size = sizeof(struct host_sp_status_block);
+       else if (bnx2x_is_ver52(bp))
+               bp->status_blk_size = sizeof(struct host_def_status_block);
+       else {
+               LOG_INFO(PFX "%s: Unsupported bnx2x driver [%d.%d]",
+                        nic->log_name, bp->version.major, bp->version.minor);
+
+               rc = -ENOTSUP;
+               goto open_error;
+       }
+
+       bp->status_blk.def = mmap(NULL, bp->status_blk_size,
+                                 PROT_READ | PROT_WRITE, MAP_SHARED,
+                                 nic->fd, (off_t) nic->page_size);
+       if (bp->status_blk.def == MAP_FAILED) {
+               LOG_INFO(PFX "%s: Could not mmap status block: %s",
+                        nic->log_name, strerror(errno));
+               bp->status_blk.def = NULL;
+               rc = errno;
+               goto open_error;
+       }
+
+       bp->tx_ring = mmap(NULL, 4 * nic->page_size,
+                          PROT_READ | PROT_WRITE,
+                          MAP_SHARED | MAP_LOCKED,
+                          nic->fd, (off_t) 2 * nic->page_size);
+       if (bp->tx_ring == MAP_FAILED) {
+               LOG_INFO(PFX "%s: Could not mmap tx ring: %s",
+                        nic->log_name, strerror(errno));
+               bp->tx_ring = NULL;
+               rc = errno;
+               goto open_error;
+       }
+
+       bp->rx_comp_ring.cqe = (union eth_rx_cqe *)
+           (((__u8 *) bp->tx_ring) + 2 * nic->page_size);
+
+       bp->bufs = mmap(NULL, (bp->rx_ring_size + 1) * bp->rx_buffer_size,
+                       PROT_READ | PROT_WRITE,
+                       MAP_SHARED | MAP_LOCKED,
+                       nic->fd, (off_t) 3 * nic->page_size);
+       if (bp->bufs == MAP_FAILED) {
+               LOG_INFO(PFX "%s: Could not mmap buffers: %s",
+                        nic->log_name, strerror(errno));
+               bp->bufs = NULL;
+               rc = errno;
+               goto open_error;
+       }
+
+       bp->chip_id = bnx2x_get_chip_id(bp);
+       LOG_DEBUG(PFX "Chip ID: %x", bp->chip_id);
+
+       rc = get_bus_slot_func_num(nic, &bus, &slot, &func);
+       if (rc != 0) {
+               LOG_INFO(PFX "%s: Couldn't determine bus:slot.func",
+                        nic->log_name);
+               goto open_error;
+       }
+       /* In E1/E1H use pci device function as read from sysfs.
+        * In E2/E3 read physical function from ME register since these chips
+        * support Physical Device Assignment where kernel BDF maybe arbitrary
+        * (depending on hypervisor).
+        */
+       if (CHIP_IS_E2_PLUS(bp)) {
+               func = (bnx2x_rd32(bp, BAR_ME_REGISTER) & ME_REG_ABS_PF_NUM) >>
+                       ME_REG_ABS_PF_NUM_SHIFT;
+       }
+       bp->func = func;
+       bp->port = bp->func % PORT_MAX;
+
+       if (CHIP_IS_E2_PLUS(bp)) {
+               __u32 val = bnx2x_rd32(bp, MISC_REG_PORT4MODE_EN_OVWR);
+               if (!(val & 1))
+                       val = bnx2x_rd32(bp, MISC_REG_PORT4MODE_EN);
+               else
+                       val = (val >> 1) & 1;
+
+               if (val)
+                       bp->pfid = func >> 1;
+               else
+                       bp->pfid = func & 0x6;
+       } else {
+               bp->pfid = func;
+       }
+
+       if (bnx2x_is_ver60_plus(bp))
+               bp->port = bp->pfid & 1;
+
+       bp->cid = 17;
+       bp->client_id = 17;
+
+       if (bnx2x_is_ver60_plus(bp)) {
+               struct client_init_general_data *data = bp->bufs;
+
+               bp->client_id = data->client_id;
+               if (data->uid.cid)
+                       bp->cid = data->uid.cid;
+               if (bp->version.minor >= 78 && bp->version.sub_minor >= 55 &&
+                   data->uid.cid_override_key == UIO_USE_TX_DOORBELL) {
+                       bp->tx_doorbell = data->uid.tx_db_off;
+                       LOG_INFO(PFX "%s: tx doorbell override offset = 0x%x",
+                                nic->log_name, bp->tx_doorbell);
+               }
+       }
+
+       LOG_INFO(PFX "%s: func 0x%x, pfid 0x%x, client_id 0x%x, cid 0x%x",
+                nic->log_name, bp->func, bp->pfid, bp->client_id, bp->cid);
+
+       if (CHIP_IS_E1(bp))
+               bp->iro = e1_iro;
+       else if (CHIP_IS_E1H(bp))
+               bp->iro = e1h_iro;
+       else if (CHIP_IS_E2_PLUS(bp))
+               bp->iro = e2_iro;
+
+       if (bnx2x_is_ver60_plus(bp)) {
+               __u32 cl_qzone_id = BNX2X_CL_QZONE_ID(bp, bp->client_id);
+
+               bp->iro_idx = 0;
+               if (bp->version.minor >= 64) {
+                       bp->iro_idx = 1;
+                       cl_qzone_id = BNX2X_CL_QZONE_ID_64(bp, bp->client_id);
+               }
+
+               bp->rx_prod_io = BAR_USTRORM_INTMEM +
+                   (CHIP_IS_E2_PLUS(bp) ?
+                    USTORM_RX_PRODS_E2_OFFSET(cl_qzone_id) :
+                    USTORM_RX_PRODS_E1X_OFFSET(bp->port, bp->client_id));
+
+               if (!bp->tx_doorbell)
+                       bp->tx_doorbell = bp->cid * 0x80 + 0x40;
+
+               bp->get_rx_cons = bnx2x_get_rx_60;
+               bp->get_tx_cons = bnx2x_get_tx_60;
+               bp->tx_vlan_tag_bit = ETH_TX_BD_FLAGS_VLAN_TAG_T6X;
+       } else {
+               bp->rx_prod_io = BAR_USTRORM_INTMEM +
+                   USTORM_RX_PRODS_OFFSET(bp->port, bp->client_id);
+
+               bp->tx_doorbell = bp->cid * nic->page_size + 0x40;
+
+               bp->get_rx_cons = bnx2x_get_rx;
+               bp->get_tx_cons = bnx2x_get_tx;
+               bp->tx_vlan_tag_bit = ETH_TX_BD_FLAGS_VLAN_TAG_T5X;
+       }
+
+       bp->tx_cons = 0;
+       bp->tx_prod = 0;
+       bp->tx_bd_prod = 0;
+       bp->tx_pkt = bp->bufs;
+
+       bp->rx_index = 0;
+       bp->rx_cons = 0;
+       bp->rx_bd_cons = 0;
+       bp->rx_prod = 127;
+       bp->rx_bd_prod = bp->rx_ring_size;
+
+       for (i = 0; i < bp->rx_ring_size; i++) {
+               void *ptr = bp->bufs + (bp->rx_buffer_size * (i + 1));
+
+               bp->rx_pkt_ring[i] = ptr;
+       }
+
+       val = bnx2x_rd32(bp, MISC_REG_SHARED_MEM_ADDR);
+
+       bp->shmem_base = val;
+       val = bnx2x_rd32(bp, bp->shmem_base + SHMEM_ISCSI_MAC_UPPER(bp));
+       nic->mac_addr[0] = (__u8) (val >> 8);
+       nic->mac_addr[1] = (__u8) val;
+       val = bnx2x_rd32(bp, bp->shmem_base + SHMEM_ISCSI_MAC_LOWER(bp));
+       nic->mac_addr[2] = (__u8) (val >> 24);
+       nic->mac_addr[3] = (__u8) (val >> 16);
+       nic->mac_addr[4] = (__u8) (val >> 8);
+       nic->mac_addr[5] = (__u8) val;
+
+       if (bnx2x_is_ver60_plus(bp) && CHIP_IS_E2_PLUS(bp)) {
+               __u32 mf_cfg_addr = 0;
+               __u32 mac_offset;
+               __u8 mac[6];
+
+               val = bnx2x_rd32(bp, (BNX2X_PATH(bp) ? MISC_REG_GENERIC_CR_1 :
+                                     MISC_REG_GENERIC_CR_0));
+               bp->shmem_base2 = val;
+               if (bp->shmem_base2) {
+                       /* size */
+                       val = bnx2x_rd32(bp, bp->shmem_base2);
+
+                       if (val > 0x10)
+                               mf_cfg_addr =
+                                   bnx2x_rd32(bp, bp->shmem_base2 + 0x10);
+               }
+
+               if (!mf_cfg_addr)
+                       mf_cfg_addr = bp->shmem_base + 0x7e4;
+
+               /* shared_feat_cfg.config */
+               mode = bnx2x_rd32(bp, bp->shmem_base + 0x354);
+               mode &= 0x700;
+               LOG_DEBUG(PFX "%s: mode = 0x%x", nic->log_name, mode);
+               switch (mode) {
+               case 0x300: /* SI mode */
+                       mac_offset = 0xe4 + (bp->func * 0x28) + 4;
+                       val = bnx2x_rd32(bp, mf_cfg_addr + mac_offset);
+                       mac[0] = (__u8) (val >> 8);
+                       mac[1] = (__u8) val;
+                       mac_offset += 4;
+                       val = bnx2x_rd32(bp, mf_cfg_addr + mac_offset);
+                       mac[2] = (__u8) (val >> 24);
+                       mac[3] = (__u8) (val >> 16);
+                       mac[4] = (__u8) (val >> 8);
+                       mac[5] = (__u8) val;
+
+                       if (mac[0] != 0xff) {
+                               memcpy(nic->mac_addr, mac, 6);
+                       } else if (bp->func > 1) {
+                               LOG_INFO(PFX "%s:  Invalid mac address: "
+                                        "%02x:%02x:%02x:%02x:%02x:%02x, abort",
+                                        nic->log_name,
+                                        mac[0], mac[1], mac[2],
+                                        mac[3], mac[4], mac[5]);
+                               rc = -ENOTSUP;
+                               goto open_error;
+                       }
+                       break;
+
+               case 0x0: /* MF SD mode */
+               case 0x500:
+               case 0x600:
+                       proto_offset = 0x24 + (bp->func * 0x18);
+                       ovtag_offset = proto_offset + 0xc;
+
+                       rc = -ENOTSUP;
+                       val = bnx2x_rd32(bp, mf_cfg_addr + ovtag_offset);
+                       val &= 0xffff;
+                       /* SD mode, check for valid outer VLAN */
+                       if (val == 0xffff) {
+                               LOG_ERR(PFX "%s: Invalid OV detected for SD, "
+                                       " fallback to SF mode!\n",
+                                       nic->log_name);
+                               goto SF;
+                       }
+                       /* Check for iSCSI protocol */
+                       val = bnx2x_rd32(bp, mf_cfg_addr + proto_offset);
+                       if ((val & 6) != 6)
+                               goto open_error;
+
+                       mac_offset = proto_offset + 0x4;
+                       val = bnx2x_rd32(bp, mf_cfg_addr + mac_offset);
+                       mac[0] = (__u8) (val >> 8);
+                       mac[1] = (__u8) val;
+                       mac_offset += 4;
+                       val = bnx2x_rd32(bp, mf_cfg_addr + mac_offset);
+                       mac[2] = (__u8) (val >> 24);
+                       mac[3] = (__u8) (val >> 16);
+                       mac[4] = (__u8) (val >> 8);
+                       mac[5] = (__u8) val;
+                       memcpy(nic->mac_addr, mac, 6);
+                       break;
+               }
+       }
+SF:
+       LOG_INFO(PFX "%s:  Using mac address: %02x:%02x:%02x:%02x:%02x:%02x",
+                nic->log_name,
+                nic->mac_addr[0], nic->mac_addr[1], nic->mac_addr[2],
+                nic->mac_addr[3], nic->mac_addr[4], nic->mac_addr[5]);
+
+       /*  Determine if Hardware VLAN tag stripping is enabled or not */
+       if (CNIC_VLAN_STRIPPING_ENABLED == bnx2x_strip_vlan_enabled(bp))
+               nic->flags |= NIC_VLAN_STRIP_ENABLED;
+
+       msync(bp->reg, BNX2X_BAR_SIZE, MS_SYNC);
+
+       LOG_INFO("%s: bnx2x initialized", nic->log_name);
+
+       bnx2x_update_rx_prod(bp);
+       bp->flags |= BNX2X_OPENED;
+
+       return 0;
+
+open_error:
+       if (bp->tx_ring) {
+               munmap(bp->tx_ring, 4 * nic->page_size);
+               bp->tx_ring = NULL;
+       }
+
+       if (bp->status_blk.def) {
+               munmap(bp->status_blk.def, bp->status_blk_size);
+               bp->status_blk.def = NULL;
+       }
+
+       if (bp->reg) {
+               munmap(bp->reg, BNX2X_BAR_SIZE);
+               bp->reg = NULL;
+       }
+
+       if (bp->reg2) {
+               munmap(bp->reg2, BNX2X_BAR2_SIZE);
+               bp->reg2 = NULL;
+       }
+
+       if (bp->rx_pkt_ring) {
+               free(bp->rx_pkt_ring);
+               bp->rx_pkt_ring = NULL;
+       }
+
+       if (bp->bar2_fd != INVALID_FD) {
+               close(bp->bar2_fd);
+               bp->bar2_fd = INVALID_FD;
+       }
+
+       if (bp->bar0_fd != INVALID_FD) {
+               close(bp->bar0_fd);
+               bp->bar0_fd = INVALID_FD;
+       }
+       if (nic->fd != INVALID_FD) {
+               close(nic->fd);
+               nic->fd = INVALID_FD;
+       }
+       bnx2x_free(nic);
+
+       return rc;
+}
+
+/**
+ *  bnx2x_uio_close_resources() - Used to free resource for the NIC/CNIC
+ *  @param nic - NIC device to free resource
+ *  @param graceful - whether to wait to close gracefully
+ *  @return 0 on success, <0 on failure
+ */
+static int bnx2x_uio_close_resources(nic_t *nic, NIC_SHUTDOWN_T graceful)
+{
+       bnx2x_t *bp = (bnx2x_t *) nic->priv;
+       int rc = 0;
+
+       /*  Check if there is an assoicated bnx2x device */
+       if (bp == NULL) {
+               LOG_WARN(PFX "%s: when closing resources there is "
+                        "no assoicated bnx2x", nic->log_name);
+               return -EIO;
+       }
+
+       /*  Clean up allocated memory */
+
+       if (bp->rx_pkt_ring != NULL) {
+               free(bp->rx_pkt_ring);
+               bp->rx_pkt_ring = NULL;
+       }
+
+       /*  Clean up mapped registers */
+       if (bp->bufs != NULL) {
+               rc = munmap(bp->bufs,
+                           (bp->rx_ring_size + 1) * bp->rx_buffer_size);
+               if (rc != 0)
+                       LOG_WARN(PFX "%s: Couldn't unmap bufs", nic->log_name);
+               bp->bufs = NULL;
+       }
+
+       if (bp->tx_ring != NULL) {
+               rc = munmap(bp->tx_ring, 4 * nic->page_size);
+               if (rc != 0)
+                       LOG_WARN(PFX "%s: Couldn't unmap tx_rings",
+                                nic->log_name);
+               bp->tx_ring = NULL;
+       }
+
+       if (bp->status_blk.def != NULL) {
+               rc = munmap(bp->status_blk.def, bp->status_blk_size);
+               if (rc != 0)
+                       LOG_WARN(PFX "%s: Couldn't unmap status block",
+                                nic->log_name);
+               bp->status_blk.def = NULL;
+       }
+
+       if (bp->reg != NULL) {
+               rc = munmap(bp->reg, BNX2X_BAR_SIZE);
+               if (rc != 0)
+                       LOG_WARN(PFX "%s: Couldn't unmap regs", nic->log_name);
+               bp->reg = NULL;
+       }
+
+       if (bp->reg2 != NULL) {
+               rc = munmap(bp->reg2, BNX2X_BAR2_SIZE);
+               if (rc != 0)
+                       LOG_WARN(PFX "%s: Couldn't unmap regs", nic->log_name);
+               bp->reg2 = NULL;
+       }
+
+       if (bp->bar2_fd != INVALID_FD) {
+               close(bp->bar2_fd);
+               bp->bar2_fd = INVALID_FD;
+       }
+
+       if (bp->bar0_fd != INVALID_FD) {
+               close(bp->bar0_fd);
+               bp->bar0_fd = INVALID_FD;
+       }
+
+       if (nic->fd != INVALID_FD) {
+               rc = close(nic->fd);
+               if (rc != 0) {
+                       LOG_WARN(PFX
+                                "%s: Couldn't close uio file descriptor: %d",
+                                nic->log_name, nic->fd);
+               } else {
+                       LOG_DEBUG(PFX "%s: Closed uio file descriptor: %d",
+                                 nic->log_name, nic->fd);
+               }
+
+               nic->fd = INVALID_FD;
+       } else {
+               LOG_WARN(PFX "%s: Invalid uio file descriptor: %d",
+                        nic->log_name, nic->fd);
+       }
+
+       bnx2x_set_drv_version_unknown(bp);
+
+       LOG_INFO(PFX "%s: Closed all resources", nic->log_name);
+
+       return 0;
+}
+
+/**
+ *  bnx2x_close() - Used to close the NIC device
+ *  @param nic - NIC device to close
+ *  @param graceful - whether to wait to close gracefully
+ *  @return 0 if successful, <0 if there is an error
+ */
+static int bnx2x_close(nic_t *nic, NIC_SHUTDOWN_T graceful)
+{
+       /*  Sanity Check: validate the parameters */
+       if (nic == NULL) {
+               LOG_ERR(PFX "bnx2x_close(): nic == NULL");
+               return -EINVAL;
+       }
+       if (nic->priv == NULL) {
+               LOG_ERR(PFX "bnx2x_close(): nic->priv == NULL");
+               return -EINVAL;
+       }
+
+       LOG_INFO(PFX "Closing NIC device: %s", nic->log_name);
+
+       bnx2x_uio_close_resources(nic, graceful);
+       bnx2x_free(nic);
+
+       return 0;
+}
+
+static void bnx2x_prepare_xmit_packet(nic_t *nic,
+                                     nic_interface_t *nic_iface,
+                                     struct packet *pkt)
+{
+       bnx2x_t *bp = (bnx2x_t *) nic->priv;
+       struct uip_vlan_eth_hdr *eth_vlan = (struct uip_vlan_eth_hdr *)pkt->buf;
+       struct uip_eth_hdr *eth = (struct uip_eth_hdr *)bp->tx_pkt;
+
+       if (eth_vlan->tpid == htons(UIP_ETHTYPE_8021Q)) {
+               memcpy(bp->tx_pkt, pkt->buf, sizeof(struct uip_eth_hdr));
+               eth->type = eth_vlan->type;
+               pkt->buf_size -= (sizeof(struct uip_vlan_eth_hdr) -
+                                 sizeof(struct uip_eth_hdr));
+               memcpy(bp->tx_pkt + sizeof(struct uip_eth_hdr),
+                      pkt->buf + sizeof(struct uip_vlan_eth_hdr),
+                      pkt->buf_size - sizeof(struct uip_eth_hdr));
+       } else
+               memcpy(bp->tx_pkt, pkt->buf, pkt->buf_size);
+
+       msync(bp->tx_pkt, pkt->buf_size, MS_SYNC);
+}
+
+/**
+ *  bnx2x_get_tx_pkt() - This function is used to a TX packet from the NIC
+ *  @param nic - The NIC device to send the packet
+ */
+void *bnx2x_get_tx_pkt(nic_t *nic)
+{
+       bnx2x_t *bp = (bnx2x_t *) nic->priv;
+       return bp->tx_pkt;
+}
+
+/**
+ *  bnx2x_start_xmit() - This function is used to send a packet of data
+ *  @param nic - The NIC device to send the packet
+ *  @param len - the length of the TX packet
+ *
+ */
+void bnx2x_start_xmit(nic_t *nic, size_t len, u16_t vlan_id)
+{
+       bnx2x_t *bp = (bnx2x_t *) nic->priv;
+       uint16_t ring_prod;
+       struct eth_tx_start_bd *txbd;
+       struct eth_tx_bd *txbd2;
+       struct eth_rx_bd *rx_bd;
+       rx_bd = (struct eth_rx_bd *)(((__u8 *) bp->tx_ring) + nic->page_size);
+
+       if ((rx_bd->addr_hi == 0) && (rx_bd->addr_lo == 0)) {
+               LOG_PACKET(PFX "%s: trying to transmit when device is closed",
+                          nic->log_name);
+               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 {
+               LOG_ERR(PFX "Pkt transmission failed.");
+       }
+
+       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);
+
+       pthread_mutex_unlock(&nic->xmit_mutex);
+
+       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)
+                       return 0;
+               return -EAGAIN;
+       }
+
+       if (pthread_mutex_trylock(&nic->xmit_mutex)) {
+               LOG_ERR(PFX "%s: unable to get xmit_mutex.", nic->log_name);
+               return -EINVAL;
+       }
+
+       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);
+
+                       pthread_mutex_unlock(&nic->xmit_mutex);
+                       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/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/libs/bnx2x.h b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/libs/bnx2x.h
new file mode 100644 (file)
index 0000000..e204cbb
--- /dev/null
@@ -0,0 +1,715 @@
+/*
+ * 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_DEFAULT_MAJOR_VERSION    1
+#define BNX2X_DEFAULT_MINOR_VERSION    70
+#define BNX2X_DEFAULT_SUB_MINOR_VERSION        1
+#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/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/libs/cnic.c b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/libs/cnic.c
new file mode 100644 (file)
index 0000000..9cdf933
--- /dev/null
@@ -0,0 +1,671 @@
+/*
+ * 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 <sys/mman.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"
+#include "qedi.h"
+
+/*******************************************************************************
+ * Constants
+ ******************************************************************************/
+#define PFX "CNIC "
+
+/*******************************************************************************
+ * 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);
+
+/*******************************************************************************
+ * Constants for qedi module
+ ******************************************************************************/
+const char qedi_library_transport_name[] = "qedi";
+const size_t qedi_library_transport_name_size =
+                       sizeof(qedi_library_transport_name);
+
+/******************************************************************************
+ * Netlink Functions
+ ******************************************************************************/
+
+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 };
+
+       LOG_DEBUG(PFX "%s: host:%d - try getting xmit mutex cnic arp send",
+                 nic->log_name, nic->host_no);
+       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);
+               pthread_mutex_unlock(&nic->xmit_mutex);
+               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);
+       pthread_mutex_unlock(&nic->xmit_mutex);
+
+       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);
+
+       pthread_mutex_unlock(&nic->xmit_mutex);
+
+       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 {
+                       LOG_DEBUG(PFX "%s: no default route address",
+                                 nic->log_name);
+               }
+       }
+       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 (ev) {
+               cnic_nl_neigh_rsp(nic, fd, ev, path, mac_addr,
+                                 nic_iface, status, AF_INET);
+       }
+
+       return rc;
+}
+
+/**
+ * cnic_handle_ipv6_iscsi_path_req() - This function will handle the IPv4
+ *                                    path req calls the bnx2i kernel module
+ * @param nic - The nic the message is directed towards
+ * @param fd  - The file descriptor to be used to extract the private data
+ * @param ev  - The iscsi_uevent
+ * @param buf - The private message buffer
+ */
+int cnic_handle_ipv6_iscsi_path_req(nic_t *nic, int fd,
+                                   struct iscsi_uevent *ev,
+                                   struct iscsi_path *path,
+                                   nic_interface_t *nic_iface)
+{
+       __u8 mac_addr[6];
+       int rc, i;
+       uint16_t neighbor_retry;
+       int status = 0;
+       char addr_dst_str[INET6_ADDRSTRLEN];
+       struct in6_addr src_addr, dst_addr,
+                       src_matching_addr, dst_matching_addr, netmask;
+       struct in6_addr *addr;
+       struct ndpc_reqptr req_ptr;
+
+       memset(mac_addr, 0, sizeof(mac_addr));
+
+       inet_ntop(AF_INET6, &path->dst.v6_addr,
+                 addr_dst_str, sizeof(addr_dst_str));
+
+       /*  Depending on the IPv6 address of the target we will need to
+        *  determine whether we use the assigned IPv6 address or the
+        *  link local IPv6 address */
+       memcpy(&dst_addr, &path->dst.v6_addr, sizeof(struct in6_addr));
+       if (ndpc_request(&nic_iface->ustack, &dst_addr,
+                        &rc, CHECK_LINK_LOCAL_ADDR)) {
+               neighbor_retry = MAX_ARP_RETRY;
+               LOG_DEBUG(PFX "Check LL failed");
+               goto done;
+       }
+       if (rc) {
+               LOG_DEBUG(PFX "Use LL");
+               /* Get link local IPv6 address */
+               addr = (struct in6_addr *)&nic_iface->ustack.linklocal6;
+       } else {
+               LOG_DEBUG(PFX "Use Best matched");
+               if (ndpc_request(&nic_iface->ustack,
+                                &dst_addr,
+                                &addr, GET_HOST_ADDR)) {
+                       neighbor_retry = MAX_ARP_RETRY;
+                       LOG_DEBUG(PFX "Use Best matched failed");
+                       goto done;
+               }
+               if (addr == NULL) {
+                       neighbor_retry = MAX_ARP_RETRY;
+                       LOG_DEBUG(PFX "No Best matched found");
+                       goto done;
+               }
+       }
+       /* Got the best matched src IP address */
+       memcpy(&src_addr, addr, sizeof(struct in6_addr));
+
+       if (nic_iface->ustack.netmask6[0] | nic_iface->ustack.netmask6[1] |
+           nic_iface->ustack.netmask6[2] | nic_iface->ustack.netmask6[3] |
+           nic_iface->ustack.netmask6[4] | nic_iface->ustack.netmask6[5] |
+           nic_iface->ustack.netmask6[6] | nic_iface->ustack.netmask6[7])
+               memcpy(&netmask.s6_addr, nic_iface->ustack.netmask6,
+                      sizeof(struct in6_addr));
+       else
+               memcpy(&netmask.s6_addr, all_zeroes_addr6,
+                      sizeof(struct in6_addr));
+
+       inet_ntop(AF_INET6, &src_addr.s6_addr16, addr_dst_str,
+                 sizeof(addr_dst_str));
+       LOG_DEBUG(PFX "src IP addr %s", addr_dst_str);
+       inet_ntop(AF_INET6, &dst_addr.s6_addr16, addr_dst_str,
+                 sizeof(addr_dst_str));
+       LOG_DEBUG(PFX "dst IP addr %s", addr_dst_str);
+       inet_ntop(AF_INET6, &netmask.s6_addr16, addr_dst_str,
+                 sizeof(addr_dst_str));
+       LOG_DEBUG(PFX "prefix mask %s", addr_dst_str);
+
+       for (i = 0; i < 4; i++) {
+               src_matching_addr.s6_addr32[i] = src_addr.s6_addr32[i] &
+                   netmask.s6_addr32[i];
+               dst_matching_addr.s6_addr32[i] = dst_addr.s6_addr32[i] &
+                   netmask.s6_addr32[i];
+               if (src_matching_addr.s6_addr32[i] !=
+                   dst_matching_addr.s6_addr32[i]) {
+                       /* No match with the prefix mask, use default route */
+                       if (memcmp(nic_iface->ustack.default_route_addr6,
+                                  all_zeroes_addr6, sizeof(*addr))) {
+                               memcpy(&dst_addr,
+                                      nic_iface->ustack.default_route_addr6,
+                                      sizeof(dst_addr));
+                               inet_ntop(AF_INET6, &dst_addr.s6_addr16,
+                                         addr_dst_str, sizeof(addr_dst_str));
+                               LOG_DEBUG(PFX "Use default router IP addr %s",
+                                         addr_dst_str);
+                               break;
+                       } else {
+                               neighbor_retry = MAX_ARP_RETRY;
+                               goto done;
+                       }
+               }
+       }
+
+#define MAX_ARP_RETRY 4
+       neighbor_retry = 0;
+
+       req_ptr.eth = (void *)mac_addr;
+       req_ptr.ipv6 = (void *)&dst_addr;
+       if (ndpc_request(&nic_iface->ustack, &req_ptr, &rc, CHECK_ARP_TABLE)) {
+               /* ndpc request failed, skip neighbor solicit send */
+               neighbor_retry = MAX_ARP_RETRY;
+               goto done;
+       }
+       if (!rc) {
+               inet_ntop(AF_INET6, &dst_addr.s6_addr16,
+                         addr_dst_str, sizeof(addr_dst_str));
+               LOG_DEBUG(PFX
+                         "%s: Preparing to send IPv6 neighbor solicitation "
+                         "to dst: '%s'", nic->log_name, addr_dst_str);
+               while ((neighbor_retry < MAX_ARP_RETRY)
+                      && (event_loop_stop == 0)) {
+                       int count;
+                       struct timespec ts;
+                       struct timeval tp;
+                       struct timeval tp_abs;
+
+                       LOG_INFO(PFX "%s: Didn't find IPv6: '%s'\n",
+                                nic->log_name, addr_dst_str);
+
+                       rc = cnic_neigh_soliciation_send(nic, nic_iface, fd,
+                                                        mac_addr,
+                                                        &dst_addr,
+                                                        addr_dst_str);
+                       if (rc != 0) {
+                               status = -EIO;
+                               goto done;
+                       }
+
+                       for (count = 0; count < 8; count++) {
+                               /* Convert from timeval to timespec */
+                               rc = gettimeofday(&tp, NULL);
+
+                               timeradd(&tp, &tp_wait, &tp_abs);
+
+                               ts.tv_sec = tp_abs.tv_sec;
+                               ts.tv_nsec = tp_abs.tv_usec * 1000;
+
+                               pthread_mutex_lock(&nic->nl_process_mutex);
+                               rc = pthread_cond_timedwait
+                                   (&nic->nl_process_if_down_cond,
+                                    &nic->nl_process_mutex, &ts);
+
+                               if (rc == ETIMEDOUT) {
+                                       pthread_mutex_unlock
+                                               (&nic->nl_process_mutex);
+
+                                       req_ptr.eth = (void *)mac_addr;
+                                       req_ptr.ipv6 = (void *)&dst_addr;
+                                       if (ndpc_request
+                                           (&nic_iface->ustack, &req_ptr, &rc,
+                                            CHECK_ARP_TABLE)) {
+                                               /* ndpc request failed,
+                                                  force retry */
+                                               rc = 0;
+                                       }
+                                       if (rc)
+                                               goto done;
+                               } else {
+                                       nic->nl_process_if_down = 0;
+                                       pthread_mutex_unlock
+                                               (&nic->nl_process_mutex);
+
+                                       neighbor_retry = MAX_ARP_RETRY;
+                                       goto done;
+                               }
+                       }
+                       neighbor_retry++;
+               }
+       }
+
+done:
+       if (neighbor_retry >= MAX_ARP_RETRY) {
+               status = -EIO;
+               rc = -EIO;
+       }
+
+       if (ev) {
+               cnic_nl_neigh_rsp(nic, fd, ev, path, mac_addr,
+                                 nic_iface, status, AF_INET6);
+       }
+       return rc;
+}
+
+/**
+ * cnic_handle_iscsi_path_req() - This function will handle the path req calls
+ *                               the bnx2i kernel module
+ * @param nic - The nic the message is directed towards
+ * @param fd  - The file descriptor to be used to extract the private data
+ * @param ev  - The iscsi_uevent
+ * @param path - The private message buffer
+ * @param nic_iface - The nic_iface to use for this connection request
+ */
+int cnic_handle_iscsi_path_req(nic_t *nic, int fd, struct iscsi_uevent *ev,
+                              struct iscsi_path *path,
+                              nic_interface_t *nic_iface)
+{
+
+       LOG_DEBUG(PFX "%s: Netlink message with VLAN ID: %d, path MTU: %d "
+                 "minor: %d ip_addr_len: %d",
+                 nic->log_name, path->vlan_id, path->pmtu, 0 /* TODO FIX */ ,
+                 path->ip_addr_len);
+
+       if (path->ip_addr_len == 4)
+               return cnic_handle_ipv4_iscsi_path_req(nic, fd, ev, path,
+                                                      nic_iface);
+       else if (path->ip_addr_len == 16)
+               return cnic_handle_ipv6_iscsi_path_req(nic, fd, ev, path,
+                                                      nic_iface);
+       else {
+               LOG_DEBUG(PFX "%s: unknown ip_addr_len: %d size dropping ",
+                         nic->log_name, path->ip_addr_len);
+               return -EIO;
+       }
+}
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/libs/cnic.h b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/libs/cnic.h
new file mode 100644 (file)
index 0000000..c86595c
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * 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;
+extern const char qedi_library_transport_name[];
+extern const size_t qedi_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/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/libs/qedi.c b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/libs/qedi.c
new file mode 100644 (file)
index 0000000..1af8d1b
--- /dev/null
@@ -0,0 +1,1195 @@
+/*
+ * Copyright (c) 2016, Cavium Inc.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed by Adam Dunkels.
+ * 4. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * qedi.c - qedi user space driver
+ * This file handles different qedi NIC operations,
+ * qedi_open - initializes all hardware resources under NIC device
+ * qedi_close - closes the NIC device
+ * qedi_read - reads data to the hardware
+ * qedi_write - writes data to the hardware
+ * qedi_start_xmit - sends a pkt of data on NIC device
+ * qedi_get_tx_pkt - gets a Tx pkt from NIC
+ * qedi_clear_tx_intr - clears the Tx interrupt
+ * NOTE: nic_t is used as NIC device,
+ *      qedi is not attached to netdev hence it is not mandatory
+ *      for netdev to be upd
+ */
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <arpa/inet.h>
+#include <linux/types.h>
+#include <linux/sockios.h>
+#include <linux/netlink.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 <sys/sysmacros.h>
+
+#include "config.h"
+
+#include "build_date.h"
+#include "bnx2x.h"
+#include "qedi.h"
+#include "cnic.h"
+#include "logger.h"
+#include "nic.h"
+#include "nic_id.h"
+#include "nic_utils.h"
+#include "options.h"
+
+#define PFX    "qedi "
+
+extern int nl_sock;
+
+static pthread_mutex_t host_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/*  Foward struct declarations */
+struct nic_ops qedi_op;
+
+/*******************************************************************************
+ * NIC Library Strings
+ ******************************************************************************/
+static const char library_name[] = "qedi";
+static const char library_version[] = PACKAGE_VERSION;
+static const char library_uio_name[] = "qedi_uio";
+
+/*  The name that should be returned from /sys/class/uio/uio0/name */
+static const char cnic_uio_sysfs_name_tempate[] = "/sys/class/uio/uio%i/name";
+static const char qedi_uio_sysfs_name[] = "qedi_uio";
+static const char qedi_host_mac_template[] =
+       "/sys/class/iscsi_host/host%i/hwaddress";
+
+struct qedi_driver_version qedi_version = {
+       QEDI_UNKNOWN_MAJOR_VERSION,
+       QEDI_UNKNOWN_MINOR_VERSION,
+       QEDI_UNKNOWN_SUB_MINOR_VERSION,
+};
+
+static int qedi_clear_tx_intr(nic_t *nic);
+
+/*******************************************************************************
+ * QEDI Library Functions
+ ******************************************************************************/
+/**
+ *  qedi_get_library_name() - Used to get the name of this NIC library
+ *  @param name - This function will return the pointer to this NIC
+ *                library name
+ *  @param name_size
+ */
+static void qedi_get_library_name(char **name, size_t *name_size)
+{
+       *name = (char *)library_name;
+       *name_size = sizeof(library_name);
+}
+
+/**
+ *  qedi_get_library_version() - Used to get the version string of this
+ *                                NIC library
+ *  @param version - This function will return the pointer to this NIC
+ *                   library version string
+ *  @param version_size - This will be set with the version size
+ */
+static void qedi_get_library_version(char **version, size_t *version_size)
+{
+       *version = (char *)library_version;
+       *version_size = sizeof(library_version);
+}
+
+/**
+ *  qedi_get_build_date() - Used to get the build date string of this library
+ *  @param version - This function will return the pointer to this NIC
+ *                   library build date string
+ *  @param version_size - This will be set with the build date string size
+ */
+static void qedi_get_build_date(char **build, size_t *build_size)
+{
+       *build = (char *)build_date;
+       *build_size = sizeof(build_date);
+}
+
+/**
+ *  qedi_get_transport_name() - Used to get the transport name associated
+ *                              with this this NIC library
+ *  @param transport_name - This function will return the pointer to this NIC
+ *                          library's associated transport string
+ *  @param transport_name_size - This will be set with the transport name size
+ */
+static void qedi_get_transport_name(char **transport_name,
+                                   size_t *transport_name_size)
+{
+       *transport_name = (char *)qedi_library_transport_name;
+       *transport_name_size = qedi_library_transport_name_size;
+}
+
+/**
+ *  qedi_get_uio_name() - Used to get the uio name associated with this this
+ *                        NIC library
+ *  @param uio_name - This function will return the pointer to this NIC
+ *                    library's associated uio string
+ *  @param transport_name_size - This will be set with the uio name size
+ */
+static void qedi_get_uio_name(char **uio_name, size_t *uio_name_size)
+{
+       *uio_name = (char *)library_uio_name;
+       *uio_name_size = sizeof(library_uio_name);
+}
+
+/**
+ *  qedi_get_ops() - Used to get the NIC library op table
+ *  @param op - The op table of this NIC library
+ */
+struct nic_ops *qedi_get_ops()
+{
+       return &qedi_op;
+}
+
+/*******************************************************************************
+ * qedi Utility Functions
+ ******************************************************************************/
+/*******************************************************************************
+ * Utility Functions Used to read register from the qedi device
+ ******************************************************************************/
+static void qedi_set_drv_version_unknown(qedi_t *bp)
+{
+       bp->version.major = QEDI_UNKNOWN_MAJOR_VERSION;
+       bp->version.minor = QEDI_UNKNOWN_MINOR_VERSION;
+       bp->version.sub_minor = QEDI_UNKNOWN_SUB_MINOR_VERSION;
+}
+
+/* Return: 1 = Unknown, 0 = Known */
+static int qedi_is_drv_version_unknown(struct qedi_driver_version *version)
+{
+       if ((version->major == (uint16_t)QEDI_UNKNOWN_MAJOR_VERSION) &&
+           (version->minor == (uint16_t)QEDI_UNKNOWN_MINOR_VERSION) &&
+           (version->sub_minor == (uint16_t)QEDI_UNKNOWN_SUB_MINOR_VERSION)) {
+               return 1;
+       }
+
+       return 0;
+}
+
+/**
+ * qedi_get_drv_version() - Used to determine the driver version
+ * @param bp - Device used to determine qedi driver version
+ */
+static int qedi_get_drv_version(qedi_t *bp)
+{
+       nic_t *nic = bp->parent;
+
+       /*
+        * CAPABILITIES: Get the iscsi driver version from qedi
+        * This may be obtained from sysfs
+        */
+       LOG_INFO(PFX "%s: qedi driver using version %d.%d.%d",
+                nic->log_name,
+                bp->version.major, bp->version.minor, bp->version.sub_minor);
+
+       return 0;
+}
+
+/******************************************************************************/
+
+/**
+ * qedi_get_chip_id() - Used to retrieve the chip ID from the nic
+ * @param dev - Device used to determin NIC type
+ * @return Chip ID read from the MISC ID register
+ */
+static int qedi_get_chip_id(qedi_t *bp)
+{
+       /* int val, id; */
+
+       /* Get the chip revision id and number. */
+       /* chip num:16-31, rev:12-15, metal:4-11, bond_id:0-3 */
+       /*
+        * CAPABILITIES: Get the CHIP info from qedi through sysfs or uio struct.
+        */
+       return 0;
+}
+
+/**
+ *  qedi_uio_verify()
+ *
+ */
+static int qedi_uio_verify(nic_t *nic)
+{
+       char *raw = NULL, *raw_tmp;
+       uint32_t raw_size = 0;
+       char temp_path[sizeof(cnic_uio_sysfs_name_tempate) + 8];
+       int rc = 0;
+
+       /*  Build the path to determine uio name */
+       snprintf(temp_path, sizeof(temp_path),
+                cnic_uio_sysfs_name_tempate, nic->uio_minor);
+
+       rc = capture_file(&raw, &raw_size, temp_path);
+       if (rc != 0)
+               goto error;
+
+       /* sanitize name string by replacing newline with null termination */
+       raw_tmp = raw;
+       while (*raw_tmp != '\n')
+               raw_tmp++;
+       *raw_tmp = '\0';
+
+       if (strncmp(raw, qedi_uio_sysfs_name,
+                   sizeof(qedi_uio_sysfs_name)) != 0) {
+               LOG_ERR(PFX "%s: uio names not equal: expecting %s got %s from %s",
+                       nic->log_name, qedi_uio_sysfs_name, raw, temp_path);
+               rc = -EIO;
+       }
+
+       free(raw);
+
+       LOG_INFO(PFX "%s: Verified is a qedi_uio device", nic->log_name);
+
+error:
+       return rc;
+}
+
+static int qedi_get_mac_addr(qedi_t *bp)
+{
+       nic_t *nic = bp->parent;
+       char *raw = NULL, *raw_tmp;
+       uint32_t raw_size = 0;
+       char temp_path[sizeof(qedi_host_mac_template) + 8];
+       int rc = 0;
+
+       /*  Build the path to determine mac address */
+       snprintf(temp_path, sizeof(temp_path),
+                qedi_host_mac_template, nic->host_no);
+
+       rc = capture_file(&raw, &raw_size, temp_path);
+       if (rc != 0)
+               goto error;
+
+       /* sanitize name string by replacing newline with null termination */
+       raw_tmp = raw;
+       while (*raw_tmp != '\n')
+               raw_tmp++;
+       *raw_tmp = '\0';
+
+       rc = sscanf(raw, "%02x:%02x:%02x:%02x:%02x:%02x",
+              (uint32_t *)&nic->mac_addr[0], (uint32_t *)&nic->mac_addr[1],
+              (uint32_t *)&nic->mac_addr[2], (uint32_t *)&nic->mac_addr[3],
+              (uint32_t *)&nic->mac_addr[4], (uint32_t *)&nic->mac_addr[5]);
+       if (rc != 1) {
+               LOG_WARN(PFX "%s: Could not parse mac_addr",
+                       nic->log_name);
+               rc = -ENODEV;
+               goto error;
+       }
+
+error:
+       if (raw)
+               free(raw);
+       return rc;
+}
+
+/*******************************************************************************
+ * qedi Utility Functions to get to the hardware consumer indexes
+ ******************************************************************************/
+
+static __u32 qedi_get_rx(qedi_t *bp)
+{
+       return ((struct qedi_uio_ctrl *)bp->uctrl_map)->host_rx_cons;
+}
+
+static __u32 qedi_get_tx(qedi_t *bp)
+{
+       return ((struct qedi_uio_ctrl *)bp->uctrl_map)->hw_tx_cons;
+}
+
+/**
+ *  qedi_free() - Used to free a qedi structure
+ */
+static void qedi_free(nic_t *nic)
+{
+       if (nic->priv)
+               free(nic->priv);
+       nic->priv = NULL;
+}
+
+/**
+ *  qedi_alloc() - Used to allocate a qedi structure
+ */
+static qedi_t *qedi_alloc(nic_t *nic)
+{
+       qedi_t *bp = malloc(sizeof(*bp));
+
+       if (!bp) {
+               LOG_ERR(PFX "%s: Could not allocate QEDI space",
+                       nic->log_name);
+               return NULL;
+       }
+
+       /*  Clear out the CNIC contents */
+       memset(bp, 0, sizeof(*bp));
+
+       bp->parent = nic;
+       nic->priv = (void *)bp;
+       get_iscsi_transport_handle(nic, &nic->transport_handle);
+       qedi_set_drv_version_unknown(bp);
+
+       return bp;
+}
+
+int uio_get_map_offset(nic_t *nic, uint8_t map, uint32_t *offset)
+{
+       char *raw = NULL;
+       uint32_t raw_size = 0;
+       ssize_t elements_read;
+       char temp_path[sizeof(UIO_OFFSET_TMPL) + 8];
+       int rc = 0;
+
+       /*  Capture RX buffer size */
+       snprintf(temp_path, sizeof(temp_path),
+                UIO_OFFSET_TMPL, nic->uio_minor, map);
+
+       rc = capture_file(&raw, &raw_size, temp_path);
+       if (rc != 0)
+               goto error;
+
+       elements_read = sscanf(raw, "0x%x", offset);
+       if (elements_read != 1) {
+               LOG_ERR(PFX "%s: Couldn't get the offset from %s",
+                       nic->log_name, temp_path);
+               rc = -EIO;
+               goto error;
+       }
+
+       rc = 0;
+error:
+       if (raw)
+               free(raw);
+
+       return rc;
+}
+
+int uio_get_map_info(nic_t *nic, uint8_t map, char *attr, uint32_t *val)
+{
+       char *raw = NULL;
+       uint32_t raw_size = 0;
+       ssize_t elements_read;
+       char temp_path[sizeof(UIO_ATTR_TMPL) + 8];
+       int rc = 0;
+
+       /*  Capture RX buffer size */
+       snprintf(temp_path, sizeof(temp_path),
+                UIO_ATTR_TMPL, nic->uio_minor, map, attr);
+
+       rc = capture_file(&raw, &raw_size, temp_path);
+       if (rc != 0)
+               goto error;
+
+       elements_read = sscanf(raw, "0x%x", val);
+       if (elements_read != 1) {
+               LOG_ERR(PFX "%s: Couldn't get the offset from %s",
+                       nic->log_name, temp_path);
+               rc = -EIO;
+               goto error;
+       }
+
+       rc = 0;
+error:
+       if (raw)
+               free(raw);
+
+       return rc;
+}
+
+/**
+ * qedi_open() - This will initialize all the hardware resources underneath
+ *               a struct cnic_uio device
+ * @param dev - The struct cnic_uio device to attach the hardware with
+ * @return 0 on success, on failure a errno will be returned
+ */
+static int qedi_open(nic_t *nic)
+{
+       qedi_t *bp = NULL;
+       struct stat uio_stat;
+       int i, rc;
+       size_t count;
+       uint32_t bus;
+       uint32_t slot;
+       uint32_t func;
+       uint32_t offset;
+
+       /*  Sanity Check: validate the parameters */
+       if (!nic) {
+               LOG_ERR(PFX "nic == NULL");
+               return -EINVAL;
+       }
+
+       if ((nic->priv) != NULL &&
+           (((qedi_t *)(nic->priv))->flags & QEDI_OPENED)) {
+               return 0;
+       }
+
+       if (nic->host_no == INVALID_HOST_NO) {
+               rc = sscanf(nic->config_device_name, "host%d", &nic->host_no);
+               if (rc != 1) {
+                       LOG_WARN(PFX "%s: Could not parse for host number",
+                                nic->config_device_name);
+                       rc = -ENODEV;
+                       goto open_error;
+               }
+       }
+
+       bp = qedi_alloc(nic);
+       if (!bp)
+               return -ENOMEM;
+
+       if (qedi_is_drv_version_unknown(&qedi_version)) {
+               /* If version is unknown, go read from ethtool */
+               rc = qedi_get_drv_version(bp);
+               if (rc)
+                       goto open_error;
+       } else {
+               /* Version is not unknown, just use it */
+               qedi_version.major = bp->version.major;
+               qedi_version.minor = bp->version.minor;
+               qedi_version.sub_minor = bp->version.sub_minor;
+       }
+
+       count = 0;
+       while ((nic->fd < 0) && count < 15) {
+               /*  udev might not have created the file yet */
+               pthread_mutex_unlock(&nic->nic_mutex);
+               sleep(1);
+               pthread_mutex_lock(&nic->nic_mutex);
+
+               nic->fd = open(nic->uio_device_name, O_RDWR | O_NONBLOCK);
+               if (nic->fd != INVALID_FD) {
+                       LOG_ERR(PFX "%s: uio device has been brought up via pid: %d on fd: %d",
+                               nic->uio_device_name, getpid(), nic->fd);
+
+                       rc = qedi_uio_verify(nic);
+                       if (rc != 0)
+                               continue;
+
+                       break;
+               } else {
+                       LOG_WARN(PFX "%s: Could not open device: %s, [%s]",
+                                nic->log_name, nic->uio_device_name,
+                                strerror(errno));
+
+                       manually_trigger_uio_event(nic, nic->uio_minor);
+
+                       /*  udev might not have created the file yet */
+                       pthread_mutex_unlock(&nic->nic_mutex);
+                       sleep(1);
+                       pthread_mutex_lock(&nic->nic_mutex);
+
+                       count++;
+               }
+       }
+       if (nic->fd == INVALID_FD) {
+               LOG_ERR(PFX "%s: Could not open device: %s, [%s]",
+                       nic->log_name, nic->uio_device_name,
+                       strerror(errno));
+               rc = errno;
+               goto open_error;
+       }
+       if (fstat(nic->fd, &uio_stat) < 0) {
+               LOG_ERR(PFX "%s: Could not fstat device", nic->log_name);
+               rc = -ENODEV;
+               goto open_error;
+       }
+       nic->uio_minor = minor(uio_stat.st_rdev);
+
+       /*
+        * CAPABILITIES: acquire the rx buffer size and rx ring size from qedi
+        */
+
+       bp->rx_ring_size = RX_RING_SIZE;
+       bp->rx_buffer_size = PKT_BUF_SIZE;
+
+       LOG_DEBUG(PFX "%s: using rx ring size: %d, rx buffer size: %d",
+                 nic->log_name, bp->rx_ring_size, bp->rx_buffer_size);
+
+       /* Determine the number of UIO events that have already occurred */
+       rc = detemine_initial_uio_events(nic, &nic->intr_count);
+       if (rc != 0) {
+               LOG_ERR(PFX "Could not get the no. of initial UIO events");
+               nic->intr_count = 0;
+       }
+
+       /* Allocate space for rx pkt ring */
+       bp->rx_pkt_ring = malloc(sizeof(void *) * bp->rx_ring_size);
+       if (!bp->rx_pkt_ring) {
+               LOG_ERR(PFX "%s: Could not allocate space for rx_pkt_ring",
+                       nic->log_name);
+               rc = errno;
+               goto open_error;
+       }
+
+       /*
+        * Map the uio struct and packet buffer
+        */
+       offset = 0;
+       rc = uio_get_map_info(nic, QEDI_UCTRL_MAP_REG, "size", &offset);
+       if (rc) {
+               LOG_INFO(PFX "Failed to get the map size rc=%d", rc);
+               goto open_error;
+       }
+       LOG_INFO(PFX "uctrl map size=%u", offset);
+
+       offset = 0;
+       rc = uio_get_map_info(nic, QEDI_RING_MAP_REG, "size", &offset);
+       if (rc) {
+               LOG_INFO(PFX "Failed to get the map size rc=%d", rc);
+               goto open_error;
+       }
+       LOG_INFO(PFX "ring map size=%u", offset);
+
+       offset = 0;
+       rc = uio_get_map_info(nic, QEDI_BUF_MAP_REG, "size", &offset);
+       if (rc) {
+               LOG_INFO(PFX "Failed to get the map size rc=%d", rc);
+               goto open_error;
+       }
+       LOG_INFO(PFX "buf map size=%u", offset);
+
+       offset = 0;
+       rc = uio_get_map_offset(nic, QEDI_UCTRL_MAP_REG, &offset);
+       if (rc) {
+               LOG_INFO(PFX "Failed to get the map offset rc=%d", rc);
+               goto open_error;
+       }
+
+       bp->uctrl_map = mmap(NULL, sizeof(struct qedi_uio_ctrl),
+                           PROT_READ | PROT_WRITE,
+                           MAP_SHARED | MAP_LOCKED,
+                           nic->fd, (off_t)0);
+       if (bp->uctrl_map == MAP_FAILED) {
+               LOG_INFO(PFX "%s: Could not mmap uio ctrl struct: %s",
+                        nic->log_name, strerror(errno));
+               bp->uctrl_map = NULL;
+               rc = errno;
+               goto open_error;
+       }
+
+       bp->uctrl_map_offset = offset;
+       bp->uctrl_map += offset;
+
+       bp->rx_comp_ring = mmap(NULL, nic->page_size,
+                          PROT_READ | PROT_WRITE, MAP_SHARED | MAP_LOCKED,
+                          nic->fd, (off_t)nic->page_size);
+       if (bp->rx_comp_ring == MAP_FAILED) {
+               LOG_INFO(PFX "%s: Could not mmap rx_comp_ring: %s",
+                        nic->log_name, strerror(errno));
+               bp->rx_comp_ring = NULL;
+               rc = errno;
+               goto open_error;
+       }
+
+       bp->bufs = mmap(NULL, (bp->rx_ring_size + 1) * bp->rx_buffer_size,
+                       PROT_READ | PROT_WRITE, MAP_SHARED | MAP_LOCKED,
+                       nic->fd, (off_t)2 * nic->page_size);
+       if (bp->bufs == MAP_FAILED) {
+               LOG_INFO(PFX "%s: Could not mmap pkt buffers: %s",
+                        nic->log_name, strerror(errno));
+               bp->bufs = NULL;
+               rc = errno;
+               goto open_error;
+       }
+
+       /*
+        * Get all CHIP related info from qedi
+        */
+       bp->chip_id = qedi_get_chip_id(bp);
+       LOG_DEBUG(PFX "Chip ID: %x", bp->chip_id);
+
+       rc = get_bus_slot_func_num(nic, &bus, &slot, &func);
+       if (rc != 0) {
+               LOG_INFO(PFX "%s: Couldn't determine bus:slot.func",
+                        nic->log_name);
+               goto open_error;
+       }
+
+       /*
+        * Get all function, pfid, client_id and cid info from qedi
+        */
+       LOG_INFO(PFX "%s: func 0x%x, pfid 0x%x, client_id 0x%x, cid 0x%x",
+                nic->log_name, bp->func, bp->pfid, bp->client_id, bp->cid);
+
+       bp->get_rx_cons = qedi_get_rx;
+       bp->get_tx_cons = qedi_get_tx;
+       bp->tx_cons = 0;
+       bp->tx_prod = 0;
+       bp->tx_bd_prod = 0;
+       bp->tx_pkt = bp->bufs;
+       bp->rx_pkts = bp->bufs + bp->rx_buffer_size;
+
+       bp->rx_index = 0;
+       bp->rx_cons = 0;
+       bp->rx_bd_cons = 0;
+       bp->rx_prod = 127;
+       bp->rx_bd_prod = bp->rx_ring_size;
+
+       for (i = 0; i < bp->rx_ring_size; i++) {
+               void *ptr = bp->bufs + (bp->rx_buffer_size * (i + 1));
+
+               bp->rx_pkt_ring[i] = ptr;
+       }
+
+       qedi_get_mac_addr(bp);
+       LOG_INFO(PFX "%s:  Using mac address: %02x:%02x:%02x:%02x:%02x:%02x",
+                nic->log_name,
+                nic->mac_addr[0], nic->mac_addr[1], nic->mac_addr[2],
+                nic->mac_addr[3], nic->mac_addr[4], nic->mac_addr[5]);
+
+       qedi_get_library_name(&nic->library_name, &count);
+       LOG_INFO("%s: qedi initialized", nic->log_name);
+
+       bp->flags |= QEDI_OPENED;
+
+       return 0;
+
+open_error:
+
+       if (bp->bufs) {
+               munmap(bp->bufs, (bp->rx_ring_size + 1) * bp->rx_buffer_size);
+               bp->bufs = NULL;
+       }
+
+       if (bp->rx_comp_ring) {
+               munmap(bp->rx_comp_ring, nic->page_size);
+               bp->rx_comp_ring = NULL;
+       }
+
+       if (bp->uctrl_map) {
+               bp->uctrl_map -= bp->uctrl_map_offset;
+               munmap(bp->uctrl_map, sizeof(struct qedi_uio_ctrl));
+               bp->uctrl_map = NULL;
+       }
+
+       if (bp->rx_pkt_ring) {
+               free(bp->rx_pkt_ring);
+               bp->rx_pkt_ring = NULL;
+       }
+
+       if (nic->fd != INVALID_FD) {
+               close(nic->fd);
+               nic->fd = INVALID_FD;
+       }
+
+       qedi_free(nic);
+
+       return rc;
+}
+
+/**
+ *  qedi_uio_close_resources() - Used to free resource for the NIC/CNIC
+ *  @param nic - NIC device to free resource
+ *  @param graceful - whether to wait to close gracefully
+ *  @return 0 on success, <0 on failure
+ */
+static int qedi_uio_close_resources(nic_t *nic, NIC_SHUTDOWN_T graceful)
+{
+       qedi_t *bp = (qedi_t *)nic->priv;
+       int rc = 0;
+
+       /*  Check if there is an assoicated qedi device */
+       if (!bp) {
+               LOG_WARN(PFX "%s: when closing resources there is no assoicated qedi",
+                        nic->log_name);
+               return -EIO;
+       }
+
+       /*  Clean up allocated memory */
+
+       if (bp->rx_pkt_ring) {
+               free(bp->rx_pkt_ring);
+               bp->rx_pkt_ring = NULL;
+       }
+
+       /*  Clean up mapped registers */
+       if (bp->bufs) {
+               rc = munmap(bp->bufs,
+                           (bp->rx_ring_size + 1) * bp->rx_buffer_size);
+               if (rc != 0)
+                       LOG_ERR(PFX "%s: Couldn't unmap bufs", nic->log_name);
+               bp->bufs = NULL;
+       }
+
+       if (bp->rx_comp_ring) {
+               rc = munmap(bp->rx_comp_ring, nic->page_size);
+               if (rc != 0)
+                       LOG_ERR(PFX "%s: Couldn't unmap ring", nic->log_name);
+               bp->rx_comp_ring = NULL;
+       }
+
+       if (bp->uctrl_map) {
+               bp->uctrl_map -= bp->uctrl_map_offset;
+               rc = munmap(bp->uctrl_map, sizeof(struct qedi_uio_ctrl));
+               if (rc != 0) {
+                       LOG_ERR(PFX "%s: Couldn't unmap uio ctrl",
+                               nic->log_name);
+               }
+               bp->uctrl_map = NULL;
+       }
+
+       if (nic->fd != INVALID_FD) {
+               rc = close(nic->fd);
+               if (rc != 0) {
+                       LOG_ERR(PFX
+                                "%s: Couldn't close uio file descriptor: %d",
+                                nic->log_name, nic->fd);
+               } else {
+                       LOG_DEBUG(PFX "%s: Closed uio file descriptor: %d",
+                                 nic->log_name, nic->fd);
+               }
+
+               nic->fd = INVALID_FD;
+       } else {
+               LOG_ERR(PFX "%s: Invalid uio file descriptor: %d",
+                       nic->log_name, nic->fd);
+       }
+
+       qedi_set_drv_version_unknown(bp);
+
+       LOG_INFO(PFX "%s: Closed all resources", nic->log_name);
+
+       return 0;
+}
+
+/**
+ *  qedi_close() - Used to close the NIC device
+ *  @param nic - NIC device to close
+ *  @param graceful - whether to wait to close gracefully
+ *  @return 0 if successful, <0 if there is an error
+ */
+static int qedi_close(nic_t *nic, NIC_SHUTDOWN_T graceful)
+{
+       /*  Sanity Check: validate the parameters */
+       if (!nic) {
+               LOG_ERR(PFX "%s: nic == NULL", __func__);
+               return -EINVAL;
+       }
+       if (!nic->priv) {
+               LOG_ERR(PFX "%s: nic->priv == NULL", __func__);
+               return -EINVAL;
+       }
+
+       LOG_INFO(PFX "Closing NIC device: %s", nic->log_name);
+
+       qedi_uio_close_resources(nic, graceful);
+       qedi_free(nic);
+
+       return 0;
+}
+
+static void qedi_prepare_xmit_packet(nic_t *nic,
+                                    nic_interface_t *nic_iface,
+                                    struct packet *pkt)
+{
+       qedi_t *bp = (qedi_t *)nic->priv;
+       struct uip_vlan_eth_hdr *eth_vlan = (struct uip_vlan_eth_hdr *)pkt->buf;
+       struct uip_eth_hdr *eth = (struct uip_eth_hdr *)bp->tx_pkt;
+
+       LOG_DEBUG(PFX "%s: pkt->buf_size=%d tpid=0x%x", nic->log_name,
+                 pkt->buf_size, eth_vlan->tpid);
+       
+       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));
+
+       LOG_DEBUG(PFX "%s: pkt->buf_size=%d type=0x%x", nic->log_name,
+                 pkt->buf_size, eth->type);
+       LOG_DEBUG(PFX "%s: pkt->buf_size - eth_hdr_size = %d", nic->log_name,
+                 pkt->buf_size - 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 {
+               LOG_DEBUG(PFX "%s: NO VLAN pkt->buf_size=%d", nic->log_name,
+                         pkt->buf_size);
+               memcpy(bp->tx_pkt, pkt->buf, pkt->buf_size);
+       }
+
+       msync(bp->tx_pkt, pkt->buf_size, MS_SYNC);
+}
+
+/**
+ *  qedi_get_tx_pkt() - This function is used to a TX packet from the NIC
+ *  @param nic - The NIC device to send the packet
+ */
+void *qedi_get_tx_pkt(nic_t *nic)
+{
+       qedi_t *bp = (qedi_t *)nic->priv;
+
+       return bp->tx_pkt;
+}
+
+/**
+ *  qedi_start_xmit() - This function is used to send a packet of data
+ *  @param nic - The NIC device to send the packet
+ *  @param len - the length of the TX packet
+ *
+ */
+void qedi_start_xmit(nic_t *nic, size_t len, u16_t vlan_id)
+{
+       qedi_t *bp = (qedi_t *)nic->priv;
+       uint8_t *ubuf;
+       struct iscsi_uevent *ev;
+       struct iscsi_path *path_data;
+       struct qedi_uio_ctrl *uctrl;
+       int rc = 0;
+       uint16_t buflen;
+
+       uctrl = (struct qedi_uio_ctrl *)bp->uctrl_map;
+
+       buflen = sizeof(struct iscsi_uevent) + sizeof(struct iscsi_path);
+       ubuf = calloc(1, NLMSG_SPACE(buflen));
+       if (!ubuf) {
+               LOG_ERR(PFX "%s: alloc failed for uevent buf", __func__);
+               return;
+       }
+
+       memset(ubuf, 0, NLMSG_SPACE(buflen));
+
+       /*  prepare the iscsi_uevent buffer */
+       ev = (struct iscsi_uevent *)ubuf;
+       ev->type = ISCSI_UEVENT_PATH_UPDATE;
+       ev->transport_handle = nic->transport_handle;
+       ev->u.set_path.host_no = nic->host_no;
+
+       /*  Prepare the iscsi_path buffer */
+       path_data = (struct iscsi_path *)(ubuf + sizeof(struct iscsi_uevent));
+       path_data->handle = QEDI_PATH_HANDLE;
+       path_data->vlan_id = vlan_id;
+       uctrl->host_tx_pkt_len = len;
+       LOG_DEBUG(PFX "%s: host_no:%d vlan_id=%d, tx_pkt_len=%d",
+                 nic->log_name, ev->u.set_path.host_no, path_data->vlan_id, uctrl->host_tx_pkt_len);
+
+       LOG_DEBUG(PFX "%s: ACQUIRE HOST MUTEX", nic->log_name);
+       pthread_mutex_lock(&host_mutex);
+       rc = __kipc_call(nl_sock, ev, buflen);
+       if (rc > 0) {
+               bp->tx_prod++;
+               uctrl->host_tx_prod++;
+               LOG_DEBUG(PFX "%s: bp->tx_prod: %d, uctrl->host_tx_prod=%d",
+                         nic->log_name, bp->tx_prod, uctrl->host_tx_prod);
+
+               msync(uctrl, sizeof(struct qedi_uio_ctrl), MS_SYNC);
+               LOG_PACKET(PFX "%s: sent %d bytes using bp->tx_prod: %d",
+                          nic->log_name, len, bp->tx_prod);
+       } else {
+               LOG_ERR(PFX "Pkt transmission failed: %d", rc);
+       }
+
+       LOG_DEBUG(PFX "%s: RELEASE HOST MUTEX", nic->log_name);
+       pthread_mutex_unlock(&host_mutex);
+       free(ubuf);
+}
+
+/**
+ *  qedi_write() - Used to write the data to the hardware
+ *  @param nic - NIC hardware to read from
+ *  @param pkt - The packet which will hold the data to be sent on the wire
+ *  @return 0 if successful, <0 if failed
+ */
+int qedi_write(nic_t *nic, nic_interface_t *nic_iface, packet_t *pkt)
+{
+       qedi_t *bp;
+       struct uip_stack *uip;
+       int i = 0;
+
+       /* Sanity Check: validate the parameters */
+       if (!nic || !nic_iface || !pkt) {
+               LOG_ERR(PFX "%s: qedi_write() nic == 0x%p || nic_iface == 0x%p || pkt == 0x%x",
+                       nic, nic_iface, pkt);
+               return -EINVAL;
+       }
+       bp = (qedi_t *)nic->priv;
+       uip = &nic_iface->ustack;
+
+       if (pkt->buf_size == 0) {
+               LOG_ERR(PFX "%s: Trying to transmitted 0 sized packet",
+                       nic->log_name);
+               return -EINVAL;
+       }
+
+       /*  Try to wait for a TX completion */
+       for (i = 0; i < 15; i++) {
+               struct timespec sleep_req = {.tv_sec = 0, .tv_nsec = 5000000 },
+                   sleep_rem;
+
+               LOG_DEBUG(PFX "%s: host:%d - calling clear_tx_intr from qedi_write",
+                         nic->log_name, nic->host_no);
+               if (qedi_clear_tx_intr(nic) == 0)
+                       break;
+
+               nanosleep(&sleep_req, &sleep_rem);
+       }
+
+       LOG_DEBUG(PFX "%s: host:%d - try getting xmit mutex",
+                  nic->log_name, nic->host_no);
+       if (pthread_mutex_trylock(&nic->xmit_mutex) != 0) {
+               LOG_DEBUG(PFX "%s: Dropped previous transmitted packet",
+                          nic->log_name);
+               return -EINVAL;
+       }
+
+       qedi_prepare_xmit_packet(nic, nic_iface, pkt);
+       qedi_start_xmit(nic, pkt->buf_size,
+                       (nic_iface->vlan_priority << 12) |
+                       nic_iface->vlan_id);
+
+       /* bump up the tx stats */
+       nic->stats.tx.packets++;
+       nic->stats.tx.bytes += uip->uip_len;
+
+       LOG_DEBUG(PFX "%s: transmitted %d bytes dev->tx_cons: %d, dev->tx_prod: %d, dev->tx_bd_prod:%d",
+                  nic->log_name, pkt->buf_size,
+                  bp->tx_cons, bp->tx_prod, bp->tx_bd_prod);
+
+       LOG_DEBUG(PFX "%s: host:%d - releasing xmit mutex",
+                 nic->log_name, nic->host_no);
+       pthread_mutex_unlock(&nic->xmit_mutex);
+
+       return 0;
+}
+
+/**
+ *  qedi_read() - Used to read the data from the hardware
+ *  @param nic - NIC hardware to read from
+ *  @param pkt - The packet which will hold the data
+ *  @return 0 if successful, < 0 if failed
+ */
+static int qedi_read(nic_t *nic, packet_t *pkt)
+{
+       qedi_t *bp;
+       void *rx_pkt;
+       int rc = 0;
+       uint32_t sw_cons, bd_cons;
+       uint32_t hw_prod, bd_prod;
+       uint32_t rx_pkt_idx;
+       int len;
+       struct qedi_rx_bd *rx_bd;
+       struct qedi_uio_ctrl *uctrl;
+       uint16_t vlan_id;
+
+       /* Sanity Check: validate the parameters */
+       if (!nic || !pkt) {
+               LOG_ERR(PFX "%s: qedi_read() nic == 0x%p || pkt == 0x%x",
+                       nic, pkt);
+               return -EINVAL;
+       }
+
+       bp = (qedi_t *)nic->priv;
+       msync(bp->uctrl_map, sizeof(struct qedi_uio_ctrl), MS_SYNC);
+       msync(bp->rx_comp_ring, nic->page_size, MS_SYNC);
+       uctrl = (struct qedi_uio_ctrl *)bp->uctrl_map;
+       hw_prod = uctrl->hw_rx_prod;
+       bd_prod = uctrl->hw_rx_bd_prod;
+       sw_cons = uctrl->host_rx_cons;
+       bd_cons = uctrl->host_rx_bd_cons;
+       rx_bd = bp->rx_comp_ring + (bd_prod * sizeof(*rx_bd));
+       len = rx_bd->rx_pkt_len;
+       rx_pkt_idx = rx_bd->rx_pkt_index;
+       vlan_id = rx_bd->vlan_id;
+
+       LOG_DEBUG(PFX "%s:hw_prod %d bd_prod %d, rx_pkt_idx %d, rxlen %d",
+                 nic->log_name, hw_prod, bd_prod, rx_bd->rx_pkt_index, len);
+       LOG_DEBUG(PFX "%s: sw_con %d bd_cons %d num BD %d",
+                 nic->log_name, sw_cons, bd_cons, QEDI_NUM_RX_BD);
+
+       if (bd_cons != bd_prod) {
+               LOG_DEBUG(PFX "%s: clearing rx interrupt: %d %d",
+                         nic->log_name, sw_cons, hw_prod);
+               rc = 1;
+               rx_pkt = bp->rx_pkts + (bp->rx_buffer_size * rx_pkt_idx);
+
+               if (len > 0) {
+                       msync(rx_pkt, len, MS_SYNC);
+                       /*  Copy the data */
+                       memcpy(pkt->buf, rx_pkt, len);
+                       pkt->buf_size = len;
+                       if (vlan_id) {
+                               pkt->vlan_tag = vlan_id;
+                               pkt->flags |= VLAN_TAGGED;
+                       } else {
+                               pkt->vlan_tag = 0;
+                       }
+
+                       LOG_DEBUG(PFX "%s: processing packet length: %d",
+                                 nic->log_name, len);
+
+                       /* bump up the recv stats */
+                       nic->stats.rx.packets++;
+                       nic->stats.rx.bytes += pkt->buf_size;
+               } else {
+                       rc = 0;
+               }
+
+               sw_cons = (sw_cons + 1) % RX_RING_SIZE;
+               bd_cons = (bd_cons + 1) % QEDI_NUM_RX_BD;
+               uctrl->host_rx_cons_cnt++;
+       }
+
+       uctrl->host_rx_bd_cons = bd_cons;
+       uctrl->host_rx_cons = sw_cons;
+
+       msync(uctrl, sizeof(struct qedi_uio_ctrl), MS_SYNC);
+       msync(bp->rx_comp_ring, nic->page_size, MS_SYNC);
+       return rc;
+}
+
+/*******************************************************************************
+ * Clearing TX interrupts
+ ******************************************************************************/
+/**
+ *  qedi_clear_tx_intr() - This routine is called when a TX interrupt occurs
+ *  @param nic - the nic the interrupt occurred on
+ *  @return  0 on success
+ */
+
+static int qedi_clear_tx_intr(nic_t *nic)
+{
+       qedi_t *bp;
+       uint32_t hw_cons;
+       struct qedi_uio_ctrl *uctrl;
+
+       /* Sanity check: ensure the parameters passed in are valid */
+       if (unlikely(!nic)) {
+               LOG_ERR(PFX "%s: nic == NULL", __func__);
+               return -EINVAL;
+       }
+
+       bp = (qedi_t *)nic->priv;
+       uctrl = (struct qedi_uio_ctrl *)bp->uctrl_map;
+       msync(bp->uctrl_map, sizeof(struct qedi_uio_ctrl), MS_SYNC);
+       hw_cons = uctrl->hw_tx_cons;
+
+       if (bp->tx_cons == hw_cons) {
+               if (bp->tx_cons == bp->tx_prod)
+                       return 0;
+               return -EAGAIN;
+       }
+
+       if (pthread_mutex_trylock(&nic->xmit_mutex)) {
+               LOG_ERR(PFX "%s: unable to get xmit_mutex.", nic->log_name);
+               return -EINVAL;
+       }
+
+       LOG_DEBUG(PFX "%s: clearing tx interrupt [%d %d]",
+                  nic->log_name, bp->tx_cons, hw_cons);
+       bp->tx_cons = hw_cons;
+
+       /* There is a queued TX packet that needs to be sent out.  The usual
+        * case is when stack will send an ARP packet out before sending the
+        * intended packet
+        */
+       if (nic->tx_packet_queue) {
+               packet_t *pkt;
+               int i;
+
+               LOG_DEBUG(PFX "%s: sending queued tx packet", nic->log_name);
+               pkt = nic_dequeue_tx_packet(nic);
+
+               /* Got a TX packet buffer of the TX queue and put it onto
+                * the hardware
+                */
+               if (pkt) {
+                       qedi_prepare_xmit_packet(nic, pkt->nic_iface, pkt);
+
+                       qedi_start_xmit(nic, pkt->buf_size,
+                                       (pkt->nic_iface->vlan_priority << 12) |
+                                       pkt->nic_iface->vlan_id);
+
+                       LOG_DEBUG(PFX "%s: transmitted queued packet %d bytes, dev->tx_cons: %d, dev->tx_prod: %d, dev->tx_bd_prod:%d",
+                                  nic->log_name, pkt->buf_size,
+                                  bp->tx_cons, bp->tx_prod, bp->tx_bd_prod);
+
+                       pthread_mutex_unlock(&nic->xmit_mutex);
+                       return 0;
+               }
+
+               /* Try to wait for a TX completion */
+               for (i = 0; i < 15; i++) {
+                       struct timespec sleep_req = {.tv_sec = 0,
+                               .tv_nsec = 5000000
+                       }, sleep_rem;
+
+                       hw_cons = uctrl->hw_tx_cons;
+                       if (bp->tx_cons != hw_cons) {
+                               LOG_PACKET(PFX
+                                          "%s: clearing tx interrupt [%d %d]",
+                                          nic->log_name, bp->tx_cons, hw_cons);
+                               bp->tx_cons = hw_cons;
+
+                               break;
+                       }
+
+                       nanosleep(&sleep_req, &sleep_rem);
+               }
+       }
+
+       LOG_DEBUG(PFX "%s: host:%d - releasing xmit mutex",
+                  nic->log_name, nic->host_no);
+       pthread_mutex_unlock(&nic->xmit_mutex);
+
+       return 0;
+}
+
+/*******************************************************************************
+ * qedi NIC op's table
+ ******************************************************************************/
+struct nic_ops qedi_op = {
+       .description = "qedi",
+       .open = qedi_open,
+       .close = qedi_close,
+       .write = qedi_write,
+       .get_tx_pkt = qedi_get_tx_pkt,
+       .start_xmit = qedi_start_xmit,
+       .read = qedi_read,
+       .clear_tx_intr = qedi_clear_tx_intr,
+       .handle_iscsi_path_req = cnic_handle_iscsi_path_req,
+
+       .lib_ops = {
+                   .get_library_name = qedi_get_library_name,
+                   .get_library_version = qedi_get_library_version,
+                   .get_build_date = qedi_get_build_date,
+                   .get_transport_name = qedi_get_transport_name,
+                   .get_uio_name = qedi_get_uio_name,
+                   },
+};
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/libs/qedi.h b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/libs/qedi.h
new file mode 100644 (file)
index 0000000..7e0140a
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2016, Cavium Inc.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed by Adam Dunkels.
+ * 4. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * qedi.h - qedi user space driver
+ *
+ */
+#ifndef __QEDI_H__
+#define __QEDI_H__
+
+#include "nic.h"
+
+#define RX_RING_SIZE   15
+#define PKT_BUF_SIZE 0X400
+#define QEDI_PAGE_SIZE 4096
+
+#define QEDI_UNKNOWN_MAJOR_VERSION     -1
+#define QEDI_UNKNOWN_MINOR_VERSION     -1
+#define QEDI_UNKNOWN_SUB_MINOR_VERSION -1
+struct qedi_driver_version {
+       uint16_t major;
+       uint16_t minor;
+       uint16_t sub_minor;
+};
+
+#define QEDI_UCTRL_MAP_REG     0
+#define QEDI_RING_MAP_REG      1
+#define QEDI_BUF_MAP_REG       2
+#define UIO_ATTR_TMPL  "/sys/class/uio/uio%u/maps/map%u/%s"
+#define UIO_ADDR_TMPL  "/sys/class/uio/uio%u/maps/map%u/addr"
+#define UIO_OFFSET_TMPL        "/sys/class/uio/uio%u/maps/map%u/offset"
+#define UIO_SIZE_TMPL  "/sys/class/uio/uio%u/maps/map%u/size"
+
+struct qedi_uio_ctrl {
+       /* meta data */
+       __u32 uio_hsi_version;
+
+       /* user writes */
+       __u32 host_tx_prod;
+       __u32 host_rx_cons;
+       __u32 host_rx_bd_cons;
+       __u32 host_tx_pkt_len;
+       __u32 host_rx_cons_cnt;
+
+       /* driver writes */
+       __u32 hw_tx_cons;
+       __u32 hw_rx_prod;
+       __u32 hw_rx_bd_prod;
+       __u32 hw_rx_prod_cnt;
+
+       /* other */
+       __u8 mac_addr[6];
+       __u8 reserve[2];
+};
+
+struct qedi_rx_bd {
+       __u32 rx_pkt_index;
+       __u32 rx_pkt_len;
+       __u16 vlan_id;
+};
+
+#define QEDI_RX_DESC_CNT       (QEDI_PAGE_SIZE / sizeof(struct qedi_rx_bd))
+#define QEDI_MAX_RX_DESC_CNT   (QEDI_RX_DESC_CNT - 1)
+#define QEDI_NUM_RX_BD         (QEDI_RX_DESC_CNT * 1)
+#define QEDI_MAX_RX_BD         (QEDI_NUM_RX_BD - 1)
+
+#define QEDI_NEXT_RX_IDX(x)    ((((x) & (QEDI_MAX_RX_DESC_CNT)) ==     \
+                                 (QEDI_MAX_RX_DESC_CNT - 1)) ?         \
+                                (x) + 2 : (x) + 1)
+
+#define QEDI_PATH_HANDLE       0xFE0000000
+
+typedef struct qedi {
+       nic_t *parent;
+
+       struct qedi_driver_version version;
+
+       uint16_t flags;
+#define CNIC_UIO_UNITIALIZED           0x0001
+#define CNIC_UIO_INITIALIZED           0x0002
+#define CNIC_UIO_ENABLED               0x0004
+#define CNIC_UIO_DISABLED              0x0008
+#define CNIC_UIO_IPv6_ENABLED          0x0010
+#define CNIC_UIO_ADDED_MULICAST                0x0020
+#define CNIC_UIO_MSIX_ENABLED          0x0200
+#define CNIC_UIO_TX_HAS_SENT           0x0400
+#define QEDI_OPENED                    0x0800
+
+       __u32 chip_id;
+       int func;
+       int port;
+       int pfid;
+       __u32 cid;
+       __u32 client_id;
+
+       __u32 tx_prod;
+       __u32 tx_bd_prod;
+       __u32 tx_cons;
+       __u8 tx_vlan_tag_bit;
+
+       __u32 rx_prod;
+       __u32 rx_bd_prod;
+       __u32 rx_cons;
+       __u32 rx_bd_cons;
+       __u32 rx_hw_prod;
+
+        __u32 (*get_rx_cons)(struct qedi *);
+        __u32 (*get_tx_cons)(struct qedi *);
+
+       /* RX ring parameters */
+       uint32_t rx_ring_size;
+       uint32_t rx_buffer_size;
+
+       void *bufs; /* Pointer to the mapped buffer space */
+       void *uctrl_map; /* UIO control structure */
+       uint32_t uctrl_map_offset; /* UIO control structure mmap offset */
+
+       uint32_t rx_index;
+       void *rx_comp_ring;
+       void **rx_pkt_ring;
+       void *tx_pkt;
+       void *rx_pkts;
+} qedi_t;
+
+/******************************************************************************
+ *  qedi Function Declarations
+ ******************************************************************************/
+void qedi_start_xmit(nic_t *nic, size_t len, u16_t vlan_id);
+struct nic_ops *qedi_get_ops();
+
+#endif /* __QEDI_H__ */
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/logger.c b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/logger.c
new file mode 100644 (file)
index 0000000..87e16cd
--- /dev/null
@@ -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) {
+               fprintf(stderr, "WARN: 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/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/logger.h b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/logger.h
new file mode 100644 (file)
index 0000000..06e2084
--- /dev/null
@@ -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/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/main.c b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/main.c
new file mode 100644 (file)
index 0000000..0c9ad49
--- /dev/null
@@ -0,0 +1,442 @@
+/*
+ * 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>
+#ifndef        NO_SYSTEMD
+#include <systemd/sd-daemon.h>
+#endif
+#include <assert.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[] = "/run/iscsiuio.pid";
+
+/*******************************************************************************
+ *  Global Variables
+ ******************************************************************************/
+static const struct option long_options[] = {
+       {"foreground", no_argument, NULL, 'f'},
+       {"debug", required_argument, NULL, 'd'},
+       {"pid", required_argument, NULL, 'p'},
+       {"version", no_argument, NULL, 'v'},
+       {"help", no_argument, NULL, 'h'},
+       {NULL, no_argument, NULL, 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)
+                       fprintf(stderr, "WARN: Could not initialize the logger in "
+                              "signal!\n");
+               goto signal_wait;
+       default:
+               break;
+       }
+       event_loop_stop = 1;
+
+       LOG_INFO("terminating...");
+
+       cleanup();
+       exit(EXIT_SUCCESS);
+}
+
+static void show_version()
+{
+       printf("%s: Version '%s', Build Date: '%s'\n",
+              APP_NAME, PACKAGE_VERSION, build_date);
+}
+
+static void main_usage()
+{
+       show_version();
+
+       printf("\nUsage: %s [OPTION]\n", APP_NAME);
+       printf("iscsiuio daemon.\n"
+              "-f, --foreground        make the program run in the foreground\n"
+              "-d, --debug debuglevel  print debugging information\n"
+              "-p, --pid pidfile       use pid file (default  %s).\n"
+              "-h, --help              display this help and exit\n"
+              "-v, --version           display version and exit\n",
+              default_pid_filepath);
+}
+
+static void daemon_init()
+{
+       int fd;
+       int res;
+
+       fd = open("/dev/null", O_RDWR);
+       assert(fd >= 0);
+
+       dup2(fd, 0);
+       dup2(fd, 1);
+       dup2(fd, 2);
+       setsid();
+       res = chdir("/");
+       assert(res == 0);
+       close(fd);
+}
+
+#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;
+       int pipefds[2];
+
+       /*  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)
+                       fprintf(stderr, "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) {
+                       fprintf(stderr, "ERR: Unable to create pid file: %s\n",
+                               pid_file);
+                       exit(1);
+               }
+
+               if (pipe(pipefds) < 0) {
+                       fprintf(stderr, "ERR: Unable to create a PIPE: %s\n",
+                               strerror(errno));
+                       exit(1);
+               }
+
+               pid = fork();
+               if (pid < 0) {
+                       fprintf(stderr, "ERR: Starting daemon failed\n");
+                       exit(1);
+               } else if (pid) {
+                       char msgbuf[4];
+                       int res;
+
+                       /* parent: wait for child msg then exit */
+                       close(pipefds[1]);      /* close unused end */
+                       res = read(pipefds[0], msgbuf, sizeof(msgbuf));
+                       assert(res > 0);
+                       exit(0);
+               }
+
+               /* the child */
+               rc = chdir("/");
+               if (rc == -1)
+                       fprintf(stderr, "WARN: Unable to chdir(\") [%s]\n", strerror(errno));
+
+               if (lockf(fd, F_TLOCK, 0) < 0) {
+                       fprintf(stderr, "ERR: Unable to lock pid file: %s [%s]\n",
+                              pid_file, strerror(errno));
+                       exit(1);
+               }
+
+               rc = ftruncate(fd, 0);
+               if (rc == -1)
+                       fprintf(stderr, "WARN: ftruncate(%d, 0) failed [%s]\n",
+                              fd, strerror(errno));
+
+               sprintf(buf, "%d\n", getpid());
+               written_bytes = write(fd, buf, strlen(buf));
+               if (written_bytes == -1) {
+                       fprintf(stderr, "ERR: Could not write pid file [%s]\n",
+                              strerror(errno));
+                       exit(1);
+               }
+               close(fd);
+
+               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;
+
+       if (!foreground) {
+               int res;
+
+               /* signal parent they can go away now */
+               close(pipefds[0]);      /* close unused end */
+               res = write(pipefds[1], "ok\n", 3);
+               assert(res > 0);
+               close(pipefds[1]);
+       }
+
+#ifndef        NO_SYSTEMD
+       sd_notify(0, "READY=1\n"
+                    "STATUS=Ready to process requests\n");
+#endif
+
+       /*  NetLink connection to listen to NETLINK_ISCSI private messages */
+       if (nic_nl_open() != 0)
+               goto error;
+
+error:
+       cleanup();
+       exit(EXIT_FAILURE);
+}
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/nic.c b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/nic.c
new file mode 100644 (file)
index 0000000..f449935
--- /dev/null
@@ -0,0 +1,1548 @@
+/*
+ * 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 "qedi.h"
+#include "ipv6.h"
+
+/******************************************************************************
+ *  Constants
+ *****************************************************************************/
+#define PFX "nic "
+#define PCI_ANY_ID (~0)
+
+/******************************************************************************
+ *  Global variables
+ *****************************************************************************/
+/*  Used to store a list of NIC libraries */
+pthread_mutex_t nic_lib_list_mutex = PTHREAD_MUTEX_INITIALIZER;
+nic_lib_handle_t *nic_lib_list;
+
+/*  Used to store a list of active cnic devices */
+pthread_mutex_t nic_list_mutex = PTHREAD_MUTEX_INITIALIZER;
+nic_t *nic_list;
+
+/******************************************************************************
+ *  Functions to handle NIC libraries
+ *****************************************************************************/
+/**
+ *  alloc_nic_library_handle() - Used to allocate a NIC library handle
+ *  @return NULL if memory couldn't be allocated, pointer to the handle
+ *    to the NIC library handle
+ */
+static nic_lib_handle_t *alloc_nic_library_handle()
+{
+       nic_lib_handle_t *handle;
+
+       handle = malloc(sizeof(*handle));
+       if (handle == NULL) {
+               LOG_ERR("Could not allocate memory for library handle");
+               return NULL;
+       }
+
+       memset(handle, 0, sizeof(*handle));
+       handle->ops = NULL;
+
+       pthread_mutex_init(&handle->mutex, NULL);
+
+       return handle;
+}
+
+static void free_nic_library_handle(nic_lib_handle_t *handle)
+{
+       free(handle);
+}
+
+/**
+ *  load_nic_library() - This function is used to load a NIC library
+ *  @param handle - This is the library handle to load
+ *  @return 0 = Success; <0 = failure
+ */
+static int load_nic_library(nic_lib_handle_t *handle)
+{
+       int rc;
+       char *library_name;
+       size_t library_name_size;
+       char *library_version;
+       size_t library_version_size;
+       char *build_date_str;
+       size_t build_date_str_size;
+
+       pthread_mutex_lock(&handle->mutex);
+
+       /* Validate the NIC ops table ensure that all the fields are not NULL */
+       if ((handle->ops->open) == NULL ||
+           (handle->ops->close) == NULL ||
+           (handle->ops->read) == NULL ||
+           (handle->ops->write) == NULL ||
+           (handle->ops->clear_tx_intr == NULL)) {
+               LOG_ERR("Invalid NIC ops table: open: 0x%x, close: 0x%x,"
+                       "read: 0x%x, write: 0x%x clear_tx_intr: 0x%x "
+                       "lib_ops: 0x%x",
+                       handle->ops->open, handle->ops->close,
+                       handle->ops->read, handle->ops->write,
+                       handle->ops->clear_tx_intr, handle->ops->lib_ops);
+               rc = -EINVAL;
+               handle->ops = NULL;
+               goto error;
+       }
+
+       /*  Validate the NIC library ops table to ensure that all the proper
+        *  fields are filled */
+       if ((handle->ops->lib_ops.get_library_name == NULL) ||
+           (handle->ops->lib_ops.get_library_version == NULL) ||
+           (handle->ops->lib_ops.get_build_date == NULL) ||
+           (handle->ops->lib_ops.get_transport_name == NULL)) {
+               rc = -EINVAL;
+               goto error;
+       }
+
+       (*handle->ops->lib_ops.get_library_name) (&library_name,
+                                                 &library_name_size);
+       (*handle->ops->lib_ops.get_library_version) (&library_version,
+                                                    &library_version_size);
+       (*handle->ops->lib_ops.get_build_date) (&build_date_str,
+                                               &build_date_str_size);
+
+       LOG_DEBUG("Loaded nic library '%s' Version: '%s' build on %s'",
+                 library_name, library_version, build_date_str);
+
+       pthread_mutex_unlock(&handle->mutex);
+
+       return 0;
+
+error:
+       pthread_mutex_unlock(&handle->mutex);
+
+       return rc;
+}
+
+static struct nic_ops *(*nic_get_ops[]) () = {
+bnx2_get_ops, bnx2x_get_ops, qedi_get_ops};
+
+int load_all_nic_libraries()
+{
+       int rc, i = 0;
+       nic_lib_handle_t *handle;
+
+       for (i = 0; i < sizeof(nic_get_ops) / sizeof(nic_get_ops[0]); i++) {
+               /*  Add the CNIC library */
+               handle = alloc_nic_library_handle();
+               if (handle == NULL) {
+                       LOG_ERR("Could not allocate memory for CNIC nic lib");
+                       return -ENOMEM;
+               }
+
+               handle->ops = (*nic_get_ops[i]) ();
+
+               rc = load_nic_library(handle);
+               if (rc != 0) {
+                       free_nic_library_handle(handle);
+                       return rc;
+               }
+               /*  Add the CNIC library to the list of library handles */
+               pthread_mutex_lock(&nic_lib_list_mutex);
+
+               /*  Add this library to the list of nic libraries we
+                *  know about */
+               if (nic_lib_list == NULL) {
+                       nic_lib_list = handle;
+               } else {
+                       nic_lib_handle_t *current = nic_lib_list;
+
+                       while (current->next != NULL)
+                               current = current->next;
+
+                       current->next = handle;
+               }
+               pthread_mutex_unlock(&nic_lib_list_mutex);
+
+               LOG_DEBUG("Added '%s' nic library", handle->ops->description);
+       }
+
+       return rc;
+}
+
+int unload_all_nic_libraries()
+{
+       nic_lib_handle_t *current, *next;
+
+       pthread_mutex_lock(&nic_lib_list_mutex);
+       current = nic_lib_list;
+
+       while (current != NULL) {
+               next = current->next;
+               free_nic_library_handle(current);
+
+               current = next;
+       }
+
+       pthread_mutex_unlock(&nic_lib_list_mutex);
+
+       nic_lib_list = NULL;
+
+       return 0;
+}
+
+NIC_LIBRARY_EXIST_T does_nic_uio_name_exist(char *name,
+                                           nic_lib_handle_t **handle)
+{
+       NIC_LIBRARY_EXIST_T rc;
+       nic_lib_handle_t *current;
+
+       pthread_mutex_lock(&nic_lib_list_mutex);
+       current = nic_lib_list;
+
+       while (current != NULL) {
+               char *uio_name;
+               size_t uio_name_size;
+
+               (*current->ops->lib_ops.get_uio_name) (&uio_name,
+                                                      &uio_name_size);
+
+               if (strncmp(name, uio_name, uio_name_size) == 0) {
+                       if (handle)
+                               *handle = current;
+
+                       rc = NIC_LIBRARY_EXSITS;
+                       goto done;
+               }
+
+               current = current->next;
+       }
+
+       rc = NIC_LIBRARY_DOESNT_EXIST;
+
+done:
+       pthread_mutex_unlock(&nic_lib_list_mutex);
+       return rc;
+}
+
+NIC_LIBRARY_EXIST_T does_nic_library_exist(char *name,
+                                          nic_lib_handle_t **handle)
+{
+       NIC_LIBRARY_EXIST_T rc;
+       nic_lib_handle_t *current;
+
+       pthread_mutex_lock(&nic_lib_list_mutex);
+       current = nic_lib_list;
+
+       while (current != NULL) {
+               char *library_name;
+               size_t library_name_size;
+
+               (*current->ops->lib_ops.get_library_name) (&library_name,
+                                                          &library_name_size);
+
+               if (strncmp(name, library_name, library_name_size) == 0) {
+                       if (handle)
+                               *handle = current;
+
+                       rc = NIC_LIBRARY_EXSITS;
+                       goto done;
+               }
+
+               current = current->next;
+       }
+
+       rc = NIC_LIBRARY_DOESNT_EXIST;
+
+done:
+       pthread_mutex_unlock(&nic_lib_list_mutex);
+       return rc;
+}
+
+/**
+ *  find_nic_lib_using_pci_id() - Find the proper NIC library using the
+ *     PCI ID's
+ *  @param vendor - PCI vendor ID to search on
+ *  @param device - PCI device ID to search on
+ *  @param subvendor - PCI subvendor ID to search on
+ *  @param subdevice - PCI subdevice ID to search on
+ *  @param handle - This function will return the nic lib handle if found
+ *  @return 0 if found, <0 not found
+ */
+int find_nic_lib_using_pci_id(uint32_t vendor, uint32_t device,
+                             uint32_t subvendor, uint32_t subdevice,
+                             nic_lib_handle_t **handle,
+                             struct pci_device_id **pci_entry)
+{
+       int rc;
+       nic_lib_handle_t *current;
+
+       pthread_mutex_lock(&nic_lib_list_mutex);
+       current = nic_lib_list;
+
+       while (current != NULL) {
+               struct pci_device_id *pci_table;
+               uint32_t entries;
+               int i;
+
+               if (current->ops->lib_ops.get_pci_table != NULL) {
+                       current->ops->lib_ops.get_pci_table(&pci_table,
+                                                           &entries);
+               } else {
+                       current = current->next;
+                       continue;
+               }
+               /*  Sanity check the the pci table coming from the
+                *  hardware library */
+               if (entries > MAX_PCI_DEVICE_ENTRIES) {
+                       LOG_WARN(PFX "Too many pci_table entries(%d) skipping",
+                                entries);
+                       continue;
+               }
+
+               for (i = 0; i < entries; i++) {
+                       LOG_DEBUG(PFX "Checking against: "
+                                 "vendor: 0x%x device:0x%x "
+                                 "subvendor:0x%x subdevice:0x%x",
+                                 pci_table[i].vendor, pci_table[i].device,
+                                 pci_table[i].subvendor,
+                                 pci_table[i].subdevice);
+
+                       if ((pci_table[i].vendor == vendor) &&
+                           (pci_table[i].device == device) &&
+                           (pci_table[i].subvendor == PCI_ANY_ID ||
+                            pci_table[i].subvendor == subvendor) &&
+                           (pci_table[i].subdevice == PCI_ANY_ID ||
+                            pci_table[i].subdevice == subdevice)) {
+                               *handle = current;
+                               *pci_entry = &pci_table[i];
+                               rc = 0;
+                               goto done;
+                       }
+               }
+
+               current = current->next;
+       }
+       rc = -EINVAL;
+
+done:
+       pthread_mutex_unlock(&nic_lib_list_mutex);
+
+       return rc;
+}
+
+/**
+ * nic_init() - This will properly initialize a struct cnic_uio device
+ * @return NULL is there is a failure and pointer to an allocated/initialized
+ *         struct cnic_uio on success
+ */
+nic_t *nic_init()
+{
+       nic_t *nic;
+
+       nic = malloc(sizeof(*nic));
+       if (nic == NULL) {
+               LOG_ERR("Couldn't malloc space for nic");
+               return NULL;
+       }
+
+       memset(nic, 0, sizeof(*nic));
+       nic->uio_minor = -1;
+       nic->fd = INVALID_FD;
+       nic->host_no = INVALID_HOST_NO;
+       nic->next = NULL;
+       nic->thread = INVALID_THREAD;
+       nic->enable_thread = INVALID_THREAD;
+       nic->flags |= NIC_DISABLED;
+       nic->state = NIC_STOPPED;
+       nic->free_packet_queue = NULL;
+       nic->tx_packet_queue = NULL;
+       nic->nic_library = NULL;
+       nic->pci_id = NULL;
+       nic->page_size = getpagesize();
+
+       /* nic_mutex is used to protect nic ops */
+       pthread_mutex_init(&nic->nic_mutex, NULL);
+       pthread_mutex_init(&nic->xmit_mutex, NULL);
+       pthread_mutex_init(&nic->free_packet_queue_mutex, NULL);
+
+       pthread_cond_init(&nic->enable_wait_cond, NULL);
+       pthread_cond_init(&nic->enable_done_cond, NULL);
+       pthread_cond_init(&nic->nic_loop_started_cond, NULL);
+       pthread_cond_init(&nic->disable_wait_cond, NULL);
+
+       nic->rx_poll_usec = DEFAULT_RX_POLL_USEC;
+
+       pthread_mutex_init(&nic->nl_process_mutex, NULL);
+       pthread_cond_init(&nic->nl_process_if_down_cond, NULL);
+       pthread_cond_init(&nic->nl_process_cond, NULL);
+       nic->nl_process_thread = INVALID_THREAD;
+       nic->nl_process_if_down = 0;
+       nic->nl_process_head = 0;
+       nic->nl_process_tail = 0;
+       memset(&nic->nl_process_ring, 0, sizeof(nic->nl_process_ring));
+
+       nic->ping_thread = INVALID_THREAD;
+
+       return nic;
+}
+
+void nic_add(nic_t *nic)
+{
+       /*  Add this device to our list of nics */
+       if (nic_list == NULL) {
+               nic_list = nic;
+       } else {
+               nic_t *current = nic_list;
+
+               while (current->next != NULL)
+                       current = current->next;
+
+               current->next = nic;
+       }
+}
+
+/**
+ *  nic_remove() - Used to remove the NIC for the nic list
+ *  @param nic - the nic to remove
+ */
+int nic_remove(nic_t *nic)
+{
+       int rc;
+       nic_t *prev, *current;
+       struct stat file_stat;
+       nic_interface_t *nic_iface, *next_nic_iface, *vlan_iface;
+
+       pthread_mutex_lock(&nic->nic_mutex);
+
+       /*  Check if the file node exists before closing */
+       if (nic->uio_device_name) {
+               rc = stat(nic->uio_device_name, &file_stat);
+               if ((rc == 0) && (nic->ops))
+                       nic->ops->close(nic, 0);
+       }
+       pthread_mutex_unlock(&nic->nic_mutex);
+
+       nic->state = NIC_EXIT;
+
+       if (nic->enable_thread != INVALID_THREAD) {
+               LOG_DEBUG(PFX "%s: Canceling nic enable thread", nic->log_name);
+
+               rc = pthread_cancel(nic->enable_thread);
+               if (rc != 0)
+                       LOG_DEBUG(PFX "%s: Couldn't send cancel to nic enable "
+                                 "thread", nic->log_name);
+
+               nic->enable_thread = INVALID_THREAD;
+               LOG_DEBUG(PFX "%s: nic enable thread cleaned", nic->log_name);
+       } else {
+               LOG_DEBUG(PFX "%s: NIC enable thread already canceled",
+                         nic->log_name);
+       }
+
+       if (nic->thread != INVALID_THREAD) {
+               LOG_DEBUG(PFX "%s: Canceling nic thread", nic->log_name);
+
+               rc = pthread_cancel(nic->thread);
+               if (rc != 0)
+                       LOG_DEBUG(PFX "%s: Couldn't send cancel to nic",
+                                 nic->log_name);
+
+               nic->thread = INVALID_THREAD;
+               LOG_DEBUG(PFX "%s: nic thread cleaned", nic->log_name);
+       } else {
+               LOG_DEBUG(PFX "%s: NIC thread already canceled", nic->log_name);
+       }
+
+       if (nic->nl_process_thread != INVALID_THREAD) {
+               LOG_DEBUG(PFX "%s: Canceling nic nl thread", nic->log_name);
+
+               rc = pthread_cancel(nic->nl_process_thread);
+               if (rc != 0)
+                       LOG_DEBUG(PFX "%s: Couldn't send cancel to nic nl "
+                                 "thread", nic->log_name);
+
+               nic->nl_process_thread = INVALID_THREAD;
+               LOG_DEBUG(PFX "%s: nic nl thread cleaned", nic->log_name);
+       } else {
+               LOG_DEBUG(PFX "%s: NIC nl thread already canceled",
+                         nic->log_name);
+       }
+
+       current = prev = nic_list;
+       while (current != NULL) {
+               if (current == nic)
+                       break;
+
+               prev = current;
+               current = current->next;
+       }
+
+       if (current != NULL) {
+               if (current == nic_list)
+                       nic_list = current->next;
+               else
+                       prev->next = current->next;
+
+               /* Before freeing the nic, must free all the associated
+                  nic_iface */
+               nic_iface = current->nic_iface;
+               while (nic_iface != NULL) {
+                       vlan_iface = nic_iface->vlan_next;
+                       while (vlan_iface != NULL) {
+                               next_nic_iface = vlan_iface->vlan_next;
+                               free(vlan_iface);
+                               vlan_iface = next_nic_iface;
+                       }
+                       next_nic_iface = nic_iface->next;
+                       free(nic_iface);
+                       nic_iface = next_nic_iface;
+               }
+               free(nic);
+       } else {
+               LOG_ERR(PFX "%s: Couldn't find nic to remove", nic->log_name);
+       }
+
+       return 0;
+}
+
+/**
+ *  nic_close() - Used to indicate to a NIC that it should close
+ *                Must be called with nic->nic_mutex
+ *  @param nic - the nic to close
+ *  @param graceful -  ALLOW_GRACEFUL_SHUTDOWN will check the nic state
+ *                     before proceeding to close()
+ *                     FORCE_SHUTDOWN will force the nic to close()
+ *                     reguardless of the state
+ *  @param clean    -  this will free the proper strings assoicated
+ *                     with the NIC
+ *
+ */
+void nic_close(nic_t *nic, NIC_SHUTDOWN_T graceful, int clean)
+{
+       int rc;
+       nic_interface_t *nic_iface, *vlan_iface;
+       struct stat file_stat;
+
+       /*  The NIC could be configured by the uIP config file
+        *  but not assoicated with a hardware library just yet
+        *  we will need to check for this */
+       if (nic->ops == NULL) {
+               LOG_WARN(PFX "%s: when closing nic->ops == NULL",
+                        nic->log_name);
+               goto error;
+       }
+
+       /*  Check if the file node exists */
+       rc = stat(nic->uio_device_name, &file_stat);
+       if ((rc == 0) && (nic->ops))
+               rc = (*nic->ops->close) (nic, graceful);
+       if (rc != 0) {
+               LOG_ERR(PFX "%s: Could not close nic", nic->log_name);
+       } else {
+               nic->state = NIC_STOPPED;
+               nic->flags &= ~NIC_ENABLED;
+               nic->flags |= NIC_DISABLED;
+       }
+
+       nic_iface = nic->nic_iface;
+       while (nic_iface != NULL) {
+               if (!((nic_iface->flags & NIC_IFACE_PERSIST) ==
+                     NIC_IFACE_PERSIST)) {
+                       uip_reset(&nic_iface->ustack);
+                       vlan_iface = nic_iface->vlan_next;
+                       while (vlan_iface != NULL) {
+                               uip_reset(&vlan_iface->ustack);
+                               vlan_iface = vlan_iface->vlan_next;
+                       }
+               }
+               nic_iface = nic_iface->next;
+       }
+
+       /*  The NIC must be destroyed and init'ed once again,
+        *  POSIX defines that the mutex will be undefined it
+        *  init'ed twice without a destroy */
+       pthread_mutex_destroy(&nic->xmit_mutex);
+       pthread_mutex_init(&nic->xmit_mutex, NULL);
+
+       if (clean & FREE_CONFIG_NAME) {
+               /*  Free any named strings we might be holding onto */
+               if (nic->flags & NIC_CONFIG_NAME_MALLOC) {
+                       free(nic->config_device_name);
+                       nic->flags &= ~NIC_CONFIG_NAME_MALLOC;
+               }
+               nic->config_device_name = NULL;
+       }
+
+       if (clean & FREE_UIO_NAME) {
+               if (nic->flags & NIC_UIO_NAME_MALLOC) {
+                       free(nic->uio_device_name);
+                       nic->uio_device_name = NULL;
+
+                       nic->flags &= ~NIC_UIO_NAME_MALLOC;
+               }
+       }
+
+       LOG_ERR(PFX "%s: nic closed", nic->log_name);
+error:
+       return;
+}
+
+/**
+ *  nic_iface_init() - This function is used to add an interface to the
+ *                     structure cnic_uio
+ *  @return 0 on success, <0 on failure
+ */
+nic_interface_t *nic_iface_init()
+{
+       nic_interface_t *nic_iface = malloc(sizeof(*nic_iface));
+       if (nic_iface == NULL) {
+               LOG_ERR("Could not allocate space for nic iface");
+               return NULL;
+       }
+
+       memset(nic_iface, 0, sizeof(*nic_iface));
+       nic_iface->next = NULL;
+       nic_iface->vlan_next = NULL;
+       nic_iface->iface_num = IFACE_NUM_INVALID;
+       nic_iface->request_type = IP_CONFIG_OFF;
+
+       return nic_iface;
+}
+
+/**
+ *  nic_add_nic_iface() - This function is used to add an interface to the
+ *                        nic structure
+ *  Called with nic_mutex held
+ *  @param nic - struct nic device to add the interface to
+ *  @param nic_iface - network interface used to add to the nic
+ *  @return 0 on success, <0 on failure
+ */
+int nic_add_nic_iface(nic_t *nic, nic_interface_t *nic_iface)
+{
+       nic_interface_t *current, *prev;
+
+       /* Make sure it doesn't already exist */
+       current = nic_find_nic_iface(nic, nic_iface->protocol,
+                                    nic_iface->vlan_id, nic_iface->iface_num,
+                                    nic_iface->request_type);
+       if (current) {
+               LOG_DEBUG(PFX "%s: nic interface for VLAN: %d, protocol: %d"
+                         " already exist", nic->log_name, nic_iface->vlan_id,
+                         nic_iface->protocol);
+               return 0;
+       }
+
+       prev = NULL;
+       current = nic->nic_iface;
+       while (current != NULL) {
+               if (current->protocol == nic_iface->protocol) {
+                       /* Replace parent */
+                       nic_iface->vlan_next = current;
+                       nic_iface->next = current->next;
+                       current->next = NULL;
+                       if (prev)
+                               prev->next = nic_iface;
+                       else
+                               nic->nic_iface = nic_iface;
+                       goto done;
+               }
+               prev = current;
+               current = current->next;
+       }
+       nic_iface->next = nic->nic_iface;
+       nic->nic_iface = nic_iface;
+done:
+       /* Set nic_interface common fields */
+       nic_iface->parent = nic;
+       memcpy(&nic_iface->ustack.uip_ethaddr.addr, nic->mac_addr, ETH_ALEN);
+       nic->num_of_nic_iface++;
+
+       LOG_INFO(PFX "%s: Added nic interface for VLAN: %d, protocol: %d",
+                nic->log_name, nic_iface->vlan_id, nic_iface->protocol);
+
+       return 0;
+}
+
+/******************************************************************************
+ * Routine to process interrupts from the NIC device
+ ******************************************************************************/
+/**
+ *  nic_process_intr() - Routine used to process interrupts from the hardware
+ *  @param nic - NIC hardware to process the interrupt on
+ *  @return 0 on success, <0 on failure
+ */
+int nic_process_intr(nic_t *nic, int discard_check)
+{
+       fd_set fdset;
+       int ret;
+       int count;
+       struct timeval tv;
+
+       /*  Simple sanity checks */
+       if (discard_check != 1 && nic->state != NIC_RUNNING) {
+               LOG_ERR(PFX "%s: Couldn't process interrupt 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;
+
+               if (strcmp(nic->ops->description, "qedi")) {
+                       LOG_DEBUG(PFX "%s: host:%d - calling clear_tx_intr from process_intr",
+                                 nic->log_name, nic->host_no);
+                       (*nic->ops->clear_tx_intr) (nic);
+               }
+
+               ret = 1;
+       }
+       pthread_mutex_unlock(&nic->nic_mutex);
+
+       return ret;
+}
+
+void prepare_ipv4_packet(nic_t *nic,
+                        nic_interface_t *nic_iface,
+                        struct uip_stack *ustack, packet_t *pkt)
+{
+       u16_t ipaddr[2];
+       arp_table_query_t arp_query;
+       dest_ipv4_addr_t dest_ipv4_addr;
+       struct arp_entry *tabptr;
+       int queue_rc;
+       int vlan_id = 0;
+
+       /* If the rx vlan tag is not stripped and vlan is present in the pkt,
+          manual stripping is required because tx is using hw vlan tag! */
+       if (pkt->network_layer == pkt->data_link_layer +
+                                 sizeof(struct uip_vlan_eth_hdr)) {
+               /* VLAN is detected in the pkt buf */
+               memcpy(pkt->data_link_layer + 12, pkt->network_layer - 2,
+                      pkt->buf_size - sizeof(struct uip_vlan_eth_hdr) + 2);
+       }
+       dest_ipv4_addr = uip_determine_dest_ipv4_addr(ustack, ipaddr);
+       if (dest_ipv4_addr == LOCAL_BROADCAST) {
+               uip_build_eth_header(ustack, ipaddr, NULL, pkt, vlan_id);
+               return;
+       }
+
+       arp_query = is_in_arp_table(ipaddr, &tabptr);
+
+       switch (arp_query) {
+       case IS_IN_ARP_TABLE:
+               uip_build_eth_header(ustack,
+                                    ipaddr, tabptr, pkt, vlan_id);
+               break;
+       case NOT_IN_ARP_TABLE:
+               queue_rc = nic_queue_tx_packet(nic, nic_iface, pkt);
+               if (queue_rc) {
+                       LOG_ERR("could not queue TX packet: %d", queue_rc);
+               } else {
+                       uip_build_arp_request(ustack, ipaddr);
+               }
+               break;
+       default:
+               LOG_ERR("Unknown arp state");
+               break;
+       }
+}
+
+void prepare_ipv6_packet(nic_t *nic,
+                        nic_interface_t *nic_iface,
+                        struct uip_stack *ustack, packet_t *pkt)
+{
+       struct uip_eth_hdr *eth;
+       struct uip_vlan_eth_hdr *eth_vlan;
+       int vlan_id = 0;
+
+       if (pkt->network_layer == pkt->data_link_layer +
+                                 sizeof(struct uip_vlan_eth_hdr)) {
+               /* VLAN is detected in the pkt buf */
+               memcpy(pkt->data_link_layer + 12, pkt->network_layer - 2,
+                      pkt->buf_size - sizeof(struct uip_vlan_eth_hdr) + 2);
+       }
+       eth = (struct uip_eth_hdr *)ustack->data_link_layer;
+       eth_vlan = (struct uip_vlan_eth_hdr *)ustack->data_link_layer;
+       if (vlan_id == 0) {
+               eth->type = htons(UIP_ETHTYPE_IPv6);
+       } else {
+               eth_vlan->tpid = htons(UIP_ETHTYPE_8021Q);
+               eth_vlan->vid = htons(vlan_id);
+               eth_vlan->type = htons(UIP_ETHTYPE_IPv6);
+       }
+}
+
+void prepare_ustack(nic_t *nic,
+                   nic_interface_t *nic_iface,
+                   struct uip_stack *ustack, struct packet *pkt)
+{
+       struct ether_header *eth = NULL;
+       ustack->uip_buf = pkt->buf;
+       ustack->uip_len = pkt->buf_size;
+
+       pkt->nic = nic;
+       pkt->nic_iface = nic_iface;
+
+       ustack->data_link_layer = pkt->buf;
+       /*  Adjust the network layer pointer depending if
+        *  there is a VLAN tag or not, or if the hardware
+        *  has stripped out the
+        *  VLAN tag */
+       ustack->network_layer = ustack->data_link_layer +
+                               sizeof(struct uip_eth_hdr);
+       /* Init buffer to be IPv6 */
+       if (nic_iface->ustack.ip_config == IPV6_CONFIG_DHCP ||
+           nic_iface->ustack.ip_config == IPV6_CONFIG_STATIC) {
+               eth = (struct ether_header *)ustack->data_link_layer;
+               eth->ether_type = htons(UIP_ETHTYPE_IPv6);
+       }
+}
+
+int do_timers_per_nic_iface(nic_t *nic, nic_interface_t *nic_iface,
+                           struct timer *arp_timer)
+{
+       packet_t *pkt;
+       struct uip_stack *ustack = &nic_iface->ustack;
+       int i;
+
+       pkt = get_next_free_packet(nic);
+       if (pkt == NULL)
+               return -EIO;
+
+       if (nic_iface->protocol == AF_INET) {
+               for (i = 0; i < UIP_UDP_CONNS; i++) {
+                       prepare_ustack(nic, nic_iface, ustack, pkt);
+
+                       uip_udp_periodic(ustack, i);
+                       /* If the above function invocation resulted
+                        * in data that should be sent out on the
+                        * network, the global variable uip_len is
+                        * set to a value > 0. */
+                       if (ustack->uip_len > 0) {
+                               pkt->buf_size = ustack->uip_len;
+
+                               prepare_ipv4_packet(nic, nic_iface, ustack,
+                                                   pkt);
+
+                               (*nic->ops->write) (nic, nic_iface, pkt);
+                               ustack->uip_len = 0;
+                       }
+               }
+       } else {
+               /* Added periodic poll for IPv6 NDP engine */
+               if (ustack->ndpc != NULL) {     /* If engine is active */
+                       prepare_ustack(nic, nic_iface, ustack, pkt);
+
+                       uip_ndp_periodic(ustack);
+                       /* If the above function invocation resulted
+                        * in data that should be sent out on the
+                        * network, the global variable uip_len is
+                        * set to a value > 0. */
+                       if (ustack->uip_len > 0) {
+                               pkt->buf_size = ustack->uip_len;
+                               prepare_ipv6_packet(nic, nic_iface, ustack,
+                                                   pkt);
+                               (*nic->ops->write) (nic, nic_iface, pkt);
+                               ustack->uip_len = 0;
+                       }
+               }
+       }
+       /* Call the ARP timer function every 10 seconds. */
+       if (timer_expired(arp_timer)) {
+               timer_reset(arp_timer);
+               uip_arp_timer();
+       }
+       put_packet_in_free_queue(pkt, nic);
+       return 0;
+}
+
+static int check_timers(nic_t *nic,
+                       struct timer *periodic_timer, struct timer *arp_timer)
+{
+       if (timer_expired(periodic_timer)) {
+               nic_interface_t *nic_iface, *vlan_iface;
+
+               timer_reset(periodic_timer);
+
+               pthread_mutex_lock(&nic->nic_mutex);
+
+               nic_iface = nic->nic_iface;
+               while (nic_iface != NULL) {
+                       do_timers_per_nic_iface(nic, nic_iface, arp_timer);
+                       vlan_iface = nic_iface->vlan_next;
+                       while (vlan_iface != NULL) {
+                               do_timers_per_nic_iface(nic, vlan_iface,
+                                                       arp_timer);
+                               vlan_iface = vlan_iface->vlan_next;
+                       }
+                       nic_iface = nic_iface->next;
+               }
+
+               pthread_mutex_unlock(&nic->nic_mutex);
+       }
+       return 0;
+}
+
+int process_packets(nic_t *nic,
+                   struct timer *periodic_timer,
+                   struct timer *arp_timer, nic_interface_t *nic_iface)
+{
+       int rc;
+       packet_t *pkt;
+
+       pkt = get_next_free_packet(nic);
+       if (pkt == NULL) {
+               LOG_DEBUG(PFX "%s: Couldn't get buffer for processing packet",
+                         nic->log_name);
+               return -ENOMEM;
+       }
+
+       pthread_mutex_lock(&nic->nic_mutex);
+       rc = (*nic->ops->read) (nic, pkt);
+       pthread_mutex_unlock(&nic->nic_mutex);
+
+       if ((rc != 0) && (pkt->buf_size > 0)) {
+               uint16_t type = 0;
+               int af_type = 0;
+               struct uip_stack *ustack;
+               uint16_t vlan_id;
+
+               pkt->data_link_layer = pkt->buf;
+
+               vlan_id = pkt->vlan_tag & 0xFFF;
+               if ((vlan_id == 0) ||
+                   (NIC_VLAN_STRIP_ENABLED & nic->flags)) {
+                       struct uip_eth_hdr *hdr = ETH_BUF(pkt->buf);
+                       type = ntohs(hdr->type);
+                       pkt->network_layer = pkt->data_link_layer +
+                                            sizeof(struct uip_eth_hdr);
+               } else {
+                       struct uip_vlan_eth_hdr *hdr = VLAN_ETH_BUF(pkt->buf);
+                       type = ntohs(hdr->type);
+                       pkt->network_layer = pkt->data_link_layer +
+                                            sizeof(struct uip_vlan_eth_hdr);
+               }
+
+               switch (type) {
+               case UIP_ETHTYPE_IPv6:
+                       af_type = AF_INET6;
+                       break;
+               case UIP_ETHTYPE_IPv4:
+               case UIP_ETHTYPE_ARP:
+                       af_type = AF_INET;
+                       LOG_DEBUG(PFX "%s: ARP or IPv4 vlan:0x%x ethertype:0x%x",
+                                  nic->log_name, vlan_id, type);
+                       break;
+               default:
+                       LOG_DEBUG(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_DEBUG(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;
+               LOG_DEBUG(PFX "%s: found nic iface, type=0x%x, bufsize=%d",
+                         nic->log_name, type, pkt->buf_size);
+
+               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) {
+                               pkt->buf_size = ustack->uip_len;
+                               prepare_ipv4_packet(nic, nic_iface,
+                                                   ustack, pkt);
+
+                               LOG_DEBUG(PFX "%s: write called after arp_ipin, uip_len=%d",
+                                         nic->log_name, ustack->uip_len);
+                               (*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) {
+                               pkt->buf_size = ustack->uip_len;
+                               LOG_DEBUG(PFX "%s: write called after arp_arpin, bufsize=%d",
+                                          nic->log_name, pkt->buf_size);
+                               (*nic->ops->write) (nic, nic_iface, pkt);
+                       }
+                       break;
+               }
+               ustack->uip_len = 0;
+               pthread_mutex_unlock(&nic->nic_mutex);
+       }
+
+done:
+       put_packet_in_free_queue(pkt, nic);
+
+       return rc;
+}
+
+static int process_dhcp_loop(nic_t *nic,
+                            nic_interface_t *nic_iface,
+                            struct timer *periodic_timer,
+                            struct timer *arp_timer)
+{
+       struct dhcpc_state *s;
+       struct ndpc_state *n;
+       int rc;
+       struct timeval start_time;
+       struct timeval current_time;
+       struct timeval wait_time;
+       struct timeval total_time;
+
+       /* 10s loop time to wait for DHCP */
+       switch (nic_iface->ustack.ip_config) {
+       case IPV4_CONFIG_DHCP:
+               wait_time.tv_sec = 10;
+               break;
+       case IPV6_CONFIG_DHCP:
+               wait_time.tv_sec = 15;
+               break;
+       case IPV6_CONFIG_STATIC:
+               wait_time.tv_sec = 4;
+               break;
+       default:
+               wait_time.tv_sec = 2;
+       }
+       wait_time.tv_usec = 0;
+
+       s = nic_iface->ustack.dhcpc;
+       n = nic_iface->ustack.ndpc;
+
+       if (gettimeofday(&start_time, NULL)) {
+               LOG_ERR(PFX "%s: Couldn't get time of day to start DHCP timer",
+                       nic->log_name);
+               return -EIO;
+       }
+
+       timeradd(&start_time, &wait_time, &total_time);
+
+       periodic_timer->start = periodic_timer->start -
+           periodic_timer->interval;
+
+       while ((event_loop_stop == 0) &&
+              (nic->flags & NIC_ENABLED) && !(nic->flags & NIC_GOING_DOWN)) {
+
+               if (nic_iface->ustack.ip_config == IPV4_CONFIG_DHCP) {
+                       if (s->state == STATE_CONFIG_RECEIVED)
+                               break;
+               }
+               if (nic_iface->ustack.ip_config == IPV6_CONFIG_DHCP ||
+                   nic_iface->ustack.ip_config == IPV6_CONFIG_STATIC) {
+                       if (n->state == NDPC_STATE_BACKGROUND_LOOP)
+                               break;
+               }
+
+               /*  Check the periodic and ARP timer */
+               check_timers(nic, periodic_timer, arp_timer);
+
+               rc = nic_process_intr(nic, 1);
+
+               while ((rc > 0) && (!(nic->flags & NIC_GOING_DOWN))) {
+                       rc = process_packets(nic,
+                                            periodic_timer,
+                                            arp_timer, nic_iface);
+               }
+
+               if (gettimeofday(&current_time, NULL)) {
+                       LOG_ERR(PFX "%s: Couldn't get current time for "
+                               "DHCP start", nic->log_name);
+                       return -EIO;
+               }
+
+               if (timercmp(&total_time, &current_time, <)) {
+                       LOG_ERR(PFX "%s: timeout waiting for DHCP/NDP",
+                               nic->log_name);
+                       if (nic_iface->ustack.ip_config == IPV6_CONFIG_DHCP ||
+                           nic_iface->ustack.ip_config == IPV6_CONFIG_STATIC)
+                               n->retry_count = IPV6_MAX_ROUTER_SOL_RETRY;
+                       return -EIO;
+               }
+       }
+
+       if (nic->flags & NIC_GOING_DOWN)
+               return -EIO;
+       else if (nic->flags & NIC_DISABLED)
+               return -EINVAL;
+       else
+               return 0;
+}
+
+/* Called with nic_mutex locked */
+static int do_acquisition(nic_t *nic, nic_interface_t *nic_iface,
+                         struct timer *periodic_timer, struct timer *arp_timer)
+{
+       struct in_addr addr;
+       struct in6_addr addr6;
+       char buf[INET6_ADDRSTRLEN];
+       int rc = -1;
+
+       /* New acquisition */
+       uip_init(&nic_iface->ustack, nic->flags & NIC_IPv6_ENABLED);
+       memcpy(&nic_iface->ustack.uip_ethaddr.addr, nic->mac_addr, ETH_ALEN);
+
+       LOG_INFO(PFX "%s: Initialized ip stack: VLAN: %d",
+                nic->log_name, nic_iface->vlan_id);
+
+       LOG_INFO(PFX "%s: mac: %02x:%02x:%02x:%02x:%02x:%02x",
+                nic->log_name,
+                nic_iface->mac_addr[0],
+                nic_iface->mac_addr[1],
+                nic_iface->mac_addr[2],
+                nic_iface->mac_addr[3],
+                nic_iface->mac_addr[4],
+                nic_iface->mac_addr[5]);
+
+       switch (nic_iface->ustack.ip_config) {
+       case IPV4_CONFIG_STATIC:
+               memcpy(&addr.s_addr, nic_iface->ustack.hostaddr,
+                      sizeof(addr.s_addr));
+
+               LOG_INFO(PFX "%s: Using IP address: %s",
+                        nic->log_name, inet_ntoa(addr));
+
+               memcpy(&addr.s_addr, nic_iface->ustack.netmask,
+                      sizeof(addr.s_addr));
+
+               LOG_INFO(PFX "%s: Using netmask: %s",
+                        nic->log_name, inet_ntoa(addr));
+
+               set_uip_stack(&nic_iface->ustack,
+                             NULL, NULL, NULL,
+                             nic_iface->mac_addr);
+               break;
+
+       case IPV4_CONFIG_DHCP:
+               set_uip_stack(&nic_iface->ustack,
+                             NULL, NULL, NULL,
+                             nic_iface->mac_addr);
+               if (dhcpc_init(nic, &nic_iface->ustack,
+                              nic_iface->mac_addr, ETH_ALEN)) {
+                       if (nic_iface->ustack.dhcpc) {
+                               LOG_DEBUG(PFX "%s: DHCPv4 engine already "
+                                         "initialized!", nic->log_name);
+                               goto skip;
+                       } else {
+                               LOG_DEBUG(PFX "%s: DHCPv4 engine failed "
+                                         "initialization!", nic->log_name);
+                               goto error;
+                       }
+               }
+               pthread_mutex_unlock(&nic->nic_mutex);
+               rc = process_dhcp_loop(nic, nic_iface, periodic_timer,
+                                      arp_timer);
+               pthread_mutex_lock(&nic->nic_mutex);
+
+               if (rc) {
+                       LOG_ERR(PFX "%s: DHCP failed", nic->log_name);
+                       /* For DHCPv4 failure, the ustack must be cleaned so
+                          it can re-acquire on the next iscsid request */
+                       uip_reset(&nic_iface->ustack);
+                       goto error;
+               }
+
+               if (nic->flags & NIC_DISABLED) {
+                       /* Break out of this loop */
+                       break;
+               }
+
+               LOG_INFO(PFX "%s: Initialized dhcp client", nic->log_name);
+               break;
+
+       case IPV6_CONFIG_DHCP:
+       case IPV6_CONFIG_STATIC:
+               if (ndpc_init(nic, &nic_iface->ustack, nic_iface->mac_addr,
+                             ETH_ALEN)) {
+                       LOG_DEBUG(PFX "%s: IPv6 engine already initialized!",
+                                 nic->log_name);
+                       goto skip;
+               }
+               pthread_mutex_unlock(&nic->nic_mutex);
+               rc = process_dhcp_loop(nic, nic_iface, periodic_timer,
+                                      arp_timer);
+               pthread_mutex_lock(&nic->nic_mutex);
+               if (rc) {
+                       /* Don't reset and allow to use RA and LL */
+                       LOG_ERR(PFX "%s: IPv6 DHCP/NDP failed", nic->log_name);
+               }
+               if (nic_iface->ustack.ip_config == IPV6_CONFIG_STATIC) {
+                       memcpy(&addr6.s6_addr, nic_iface->ustack.hostaddr6,
+                              sizeof(addr6.s6_addr));
+                       inet_ntop(AF_INET6, addr6.s6_addr, buf, sizeof(buf));
+                       LOG_INFO(PFX "%s: hostaddr IP: %s", nic->log_name, buf);
+                       memcpy(&addr6.s6_addr, nic_iface->ustack.netmask6,
+                              sizeof(addr6.s6_addr));
+                       inet_ntop(AF_INET6, addr6.s6_addr, buf, sizeof(buf));
+                       LOG_INFO(PFX "%s: netmask IP: %s", nic->log_name, buf);
+               }
+               break;
+
+       default:
+               LOG_INFO(PFX "%s: ipconfig = %d?", nic->log_name,
+                        nic_iface->ustack.ip_config);
+       }
+skip:
+       /* Mark acquisition done for this nic iface */
+       nic_iface->flags &= ~NIC_IFACE_ACQUIRE;
+
+       LOG_INFO(PFX "%s: enabled vlan %d protocol: %d", nic->log_name,
+                nic_iface->vlan_id, nic_iface->protocol);
+       return 0;
+
+error:
+       return -EIO;
+}
+
+
+void *nic_loop(void *arg)
+{
+       nic_t *nic = (nic_t *) arg;
+       int rc = -1;
+       sigset_t set;
+       struct timer periodic_timer, arp_timer;
+
+       sigfillset(&set);
+       rc = pthread_sigmask(SIG_BLOCK, &set, NULL);
+       if (rc != 0) {
+               /* TODO: determine if we need to exit this thread if we fail
+                * to set the signal mask */
+               LOG_ERR(PFX "%s: Couldn't set signal mask", nic->log_name);
+       }
+
+       /*  Signal the device to enable itself */
+       pthread_mutex_lock(&nic->nic_mutex);
+       pthread_cond_signal(&nic->nic_loop_started_cond);
+
+       /* nic_mutex must be locked */
+       while ((event_loop_stop == 0) &&
+              !(nic->flags & NIC_EXIT_MAIN_LOOP) &&
+              !(nic->flags & NIC_GOING_DOWN)) {
+               nic_interface_t *nic_iface, *vlan_iface;
+
+               if (nic->flags & NIC_DISABLED) {
+                       LOG_DEBUG(PFX "%s: Waiting to be enabled",
+                                 nic->log_name);
+
+                       /*  Wait for the device to be enabled */
+                       /* nic_mutex is already locked */
+                       pthread_cond_wait(&nic->enable_wait_cond,
+                                         &nic->nic_mutex);
+
+                       if (nic->state == NIC_EXIT) {
+                               pthread_mutex_unlock(&nic->nic_mutex);
+                               pthread_exit(NULL);
+                       }
+                       LOG_DEBUG(PFX "%s: is now enabled", nic->log_name);
+               }
+               /*  initialize the device to send/rec data */
+               rc = (*nic->ops->open) (nic);
+               if (rc != 0) {
+                       LOG_ERR(PFX "%s: Could not initialize CNIC UIO device",
+                               nic->log_name);
+
+                       if (rc == -ENOTSUP)
+                               nic->flags |= NIC_EXIT_MAIN_LOOP;
+                       else
+                               nic->flags &= ~NIC_ENABLED;
+
+                       /* Signal that the device enable is done */
+                       pthread_cond_broadcast(&nic->enable_done_cond);
+                       pthread_mutex_unlock(&nic->nic_mutex);
+                       goto dev_close;
+               }
+               nic_set_all_nic_iface_mac_to_parent(nic);
+               pthread_mutex_unlock(&nic->nic_mutex);
+
+               rc = alloc_free_queue(nic, 5);
+               if (rc != 5) {
+                       if (rc != 0) {
+                               LOG_WARN(PFX "%s: Allocated %d packets "
+                                        "instead of %d", nic->log_name, rc, 5);
+                       } else {
+                               LOG_ERR(PFX "%s: No packets allocated "
+                                       "instead of %d", nic->log_name, 5);
+                               /*  Signal that the device enable is done */
+                               pthread_cond_broadcast(&nic->enable_done_cond);
+                               goto dev_close;
+                       }
+               }
+               /* Indication for the nic_disable routine that the nic
+                  has started running */
+               nic->state = NIC_STARTED_RUNNING;
+
+               /*  Initialize the system clocks */
+               timer_set(&periodic_timer, CLOCK_SECOND / 2);
+               timer_set(&arp_timer, CLOCK_SECOND * 10);
+
+               /*  Prepare the stack for each of the VLAN interfaces */
+               pthread_mutex_lock(&nic->nic_mutex);
+
+               /* If DHCP fails, exit loop and restart the engine */
+               nic_iface = nic->nic_iface;
+               while (nic_iface != NULL) {
+                       if (nic_iface->flags & NIC_IFACE_ACQUIRE) {
+                               do_acquisition(nic, nic_iface,
+                                              &periodic_timer,
+                                              &arp_timer);
+                       }
+                       vlan_iface = nic_iface->vlan_next;
+                       while (vlan_iface != NULL) {
+                               if (vlan_iface->flags & NIC_IFACE_ACQUIRE) {
+                                       do_acquisition(nic, vlan_iface,
+                                                      &periodic_timer,
+                                                      &arp_timer);
+                               }
+                               vlan_iface = vlan_iface->next;
+                       }
+                       nic_iface = nic_iface->next;
+               }
+               if (nic->flags & NIC_DISABLED) {
+                       LOG_WARN(PFX "%s: nic was disabled during nic loop, "
+                                "closing flag 0x%x",
+                                nic->log_name, nic->flags);
+                       /*  Signal that the device enable is done */
+                       pthread_cond_broadcast(&nic->enable_done_cond);
+                       pthread_mutex_unlock(&nic->nic_mutex);
+                       goto dev_close_free;
+               }
+
+               /*  This is when we start the processing of packets */
+               nic->start_time = time(NULL);
+               nic->state = NIC_RUNNING;
+
+               nic->flags &= ~NIC_ENABLED_PENDING;
+
+               /*  Signal that the device enable is done */
+               pthread_cond_broadcast(&nic->enable_done_cond);
+
+               LOG_INFO(PFX "%s: entering main nic loop", nic->log_name);
+
+               while ((nic->state == NIC_RUNNING) &&
+                      (event_loop_stop == 0) &&
+                      !(nic->flags & NIC_GOING_DOWN)) {
+                       pthread_mutex_unlock(&nic->nic_mutex);
+                       /*  Check the periodic and ARP timer */
+                       check_timers(nic, &periodic_timer, &arp_timer);
+                       rc = nic_process_intr(nic, 0);
+                       while ((rc > 0) &&
+                              (nic->state == NIC_RUNNING) &&
+                              !(nic->flags & NIC_GOING_DOWN)) {
+                               rc = process_packets(nic,
+                                                    &periodic_timer,
+                                                    &arp_timer, NULL);
+                       }
+                       pthread_mutex_lock(&nic->nic_mutex);
+               }
+
+               LOG_INFO(PFX "%s: exited main processing loop", nic->log_name);
+
+dev_close_free:
+               free_free_queue(nic);
+dev_close:
+
+               if (nic->flags & NIC_GOING_DOWN) {
+                       nic_close(nic, 1, FREE_NO_STRINGS);
+
+                       nic->flags &= ~NIC_GOING_DOWN;
+               } else {
+                       pthread_mutex_destroy(&nic->xmit_mutex);
+                       pthread_mutex_init(&nic->xmit_mutex, NULL);
+               }
+               nic->pending_count = 0;
+
+               if (!(nic->flags & NIC_EXIT_MAIN_LOOP)) {
+                       /*  Signal we are done closing CNIC/UIO device */
+                       pthread_cond_broadcast(&nic->disable_wait_cond);
+               }
+       }
+       /* clean up the nic flags */
+       nic->flags &= ~NIC_ENABLED_PENDING;
+
+       pthread_mutex_unlock(&nic->nic_mutex);
+
+       LOG_INFO(PFX "%s: nic loop thread exited", nic->log_name);
+
+       nic->thread = INVALID_THREAD;
+
+       pthread_exit(NULL);
+}
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/nic.h b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/nic.h
new file mode 100644 (file)
index 0000000..2c41e6e
--- /dev/null
@@ -0,0 +1,407 @@
+/*
+ * 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 "timer.h"
+
+#include "iscsi_if.h"
+
+/*  Foward declarations */
+struct nic_ops;
+struct nic_lib_handle;
+struct packet;
+struct nic_op;
+
+extern pthread_mutex_t nic_lib_list_mutex;
+extern struct nic_lib_handle *nic_lib_list;
+
+/*  Used to store a list of active cnic devices */
+extern pthread_mutex_t nic_list_mutex;
+extern struct nic *nic_list;
+
+extern void *nl_process_handle_thread(void *arg);
+
+/*******************************************************************************
+ *  Constants
+ ******************************************************************************/
+#define MAX_PCI_DEVICE_ENTRIES 64      /* Maxium number of pci_device_id
+                                          entries a hw library may contain */
+
+#define FREE_CONFIG_NAME       0x0001
+#define FREE_UIO_NAME          0x0002
+#define FREE_ALL_STRINGS       (FREE_CONFIG_NAME | FREE_UIO_NAME)
+#define FREE_NO_STRINGS                0x0000
+
+/******************************************************************************
+ * Enumerations
+ ******************************************************************************/
+typedef enum {
+       ALLOW_GRACEFUL_SHUTDOWN = 1,
+       FORCE_SHUTDOWN = 2,
+} NIC_SHUTDOWN_T;
+
+/*******************************************************************************
+ * Structure used to hold PCI vendor, device, subvendor and subdevice ID's
+ ******************************************************************************/
+struct pci_device_id {
+       const uint32_t vendor, device;  /* Vendor and device ID or PCI_ANY_ID */
+       const uint32_t subvendor, subdevice;    /* Subsystem ID's/PCI_ANY_ID */
+       const char *device_name;        /* Data private to the driver */
+};
+
+/******************************************************************************
+ * NIC statistics structure
+ ******************************************************************************/
+struct nic_stats {
+       uint64_t interrupts;
+       uint64_t missed_interrupts;
+
+       struct {
+               uint64_t packets;
+               uint64_t bytes;
+       } tx;
+
+       struct {
+               uint64_t packets;
+               uint64_t bytes;
+       } rx;
+};
+
+/******************************************************************************
+ * NIC interface structure
+ ******************************************************************************/
+typedef struct nic_interface {
+       struct nic_interface *vlan_next;
+       struct nic_interface *next;
+       struct nic *parent;
+
+       uint16_t protocol;
+       uint16_t flags;
+#define NIC_IFACE_PERSIST      (1<<0)
+#define NIC_IFACE_ACQUIRE      (1<<1)
+#define NIC_IFACE_PATHREQ_WAIT1        (1<<2)
+#define NIC_IFACE_PATHREQ_WAIT2 (1<<3)
+#define NIC_IFACE_PATHREQ_WAIT (NIC_IFACE_PATHREQ_WAIT1 | \
+                                NIC_IFACE_PATHREQ_WAIT2)
+       uint8_t mac_addr[ETH_ALEN];
+       uint8_t vlan_priority;
+       uint16_t vlan_id;
+#define NO_VLAN                0x8000
+
+       uint16_t mtu;
+       time_t start_time;
+
+       struct uip_stack ustack;
+
+#define IFACE_NUM_PRESENT (1<<0)
+#define IFACE_NUM_INVALID -1
+       int iface_num;
+       int request_type;
+} nic_interface_t;
+
+/******************************************************************************
+ * NIC lib operations structure
+ ******************************************************************************/
+struct nic_lib_ops {
+       /*  Used to get the NIC library name */
+       void (*get_library_name) (char **library_name,
+                                 size_t *library_name_size);
+
+       /*  Used to get to the PCI table supported by the NIC library */
+       void (*get_pci_table) (struct pci_device_id **table,
+                              uint32_t *entries);
+
+       /*  Used to get the version of this NIC library */
+       void (*get_library_version) (char **version_string,
+                                    size_t *version_string_size);
+
+       /*  Used to get the NIC library build date */
+       void (*get_build_date) (char **build_date_string,
+                               size_t *build_date_string_size);
+
+       /*  Used to get the transport name assoicated with this library */
+       void (*get_transport_name) (char **transport_name,
+                                   size_t *transport_name_size);
+
+       /*  Used to get the uio name assoicated with this library */
+       void (*get_uio_name) (char **uio_name, size_t *uio_name_size);
+
+};
+
+/*******************************************************************************
+ * NIC op table definition
+ ******************************************************************************/
+typedef struct nic_ops {
+       struct nic_lib_ops lib_ops;
+
+       char *description;
+       int (*open) (struct nic *);
+       int (*close) (struct nic *, NIC_SHUTDOWN_T);
+       int (*read) (struct nic *, struct packet *);
+       int (*write) (struct nic *, nic_interface_t *, struct packet *);
+       void *(*get_tx_pkt) (struct nic *);
+       void (*start_xmit) (struct nic *, size_t, u16_t vlan_id);
+       int (*clear_tx_intr) (struct nic *);
+       int (*handle_iscsi_path_req) (struct nic *,
+                                     int,
+                                     struct iscsi_uevent *ev,
+                                     struct iscsi_path *path,
+                                     nic_interface_t *nic_iface);
+} net_ops_t;
+
+typedef struct nic_lib_handle {
+       struct nic_lib_handle *next;
+
+       pthread_mutex_t mutex;
+       struct nic_ops *ops;
+} nic_lib_handle_t;
+
+typedef struct nic {
+       struct nic *next;
+
+       uint32_t flags;
+#define NIC_UNITIALIZED                0x0001
+#define NIC_INITIALIZED                0x0002
+#define NIC_ENABLED            0x0004
+#define NIC_DISABLED           0x0008
+#define NIC_IPv6_ENABLED       0x0010
+#define NIC_ADDED_MULICAST     0x0020
+#define NIC_LONG_SLEEP         0x0040
+#define NIC_PATHREQ_WAIT       0x0080
+
+#define NIC_VLAN_STRIP_ENABLED 0x0100
+#define NIC_MSIX_ENABLED       0x0200
+#define NIC_TX_HAS_SENT                0x0400
+#define NIC_ENABLED_PENDING    0x0800
+
+#define NIC_UIO_NAME_MALLOC    0x1000
+#define NIC_CONFIG_NAME_MALLOC 0x2000
+#define NIC_EXIT_MAIN_LOOP     0x4000
+#define NIC_GOING_DOWN         0x8000
+#define NIC_RESET_UIP          0x10000
+
+       uint16_t state;
+#define NIC_STOPPED            0x0001
+#define NIC_STARTED_RUNNING    0x0002
+#define NIC_RUNNING            0x0004
+#define NIC_EXIT               0x0010
+
+       int fd;                 /* Holds the file descriptor to UIO */
+       uint16_t uio_minor;     /* Holds the UIO minor number */
+
+       uint32_t host_no;       /* Holds the associated host number */
+
+       char *library_name;     /* Name of the library to assoicate with */
+       char *log_name;         /* Human friendly name used in the log
+                                  file                                 */
+       char *config_device_name;       /* Name read from the XML configuration
+                                          file                         */
+       char eth_device_name[IFNAMSIZ]; /* Network interface name       */
+       char *uio_device_name;  /* UIO device name                      */
+
+       uint32_t intr_count;    /* Total UIO interrupt count            */
+
+       int page_size;
+
+       /* Held for nic ops manipulation */
+       pthread_mutex_t nic_mutex;
+
+       /*  iSCSI ring ethernet MAC address */
+       __u8 mac_addr[ETH_ALEN];
+
+       /*  Used to manage the network interfaces of this device */
+       __u32 num_of_nic_iface;
+       nic_interface_t *nic_iface;
+
+       /*  Wait for the device to be enabled */
+       pthread_cond_t enable_wait_cond;
+
+       /*  Wait for the device to be finished enabled */
+       pthread_cond_t enable_done_cond;
+
+       /*  Wait for the nic loop to start */
+       pthread_cond_t nic_loop_started_cond;
+
+       /*  Wait for the device to be disabled */
+       pthread_cond_t disable_wait_cond;
+
+       /* Held when transmitting */
+       pthread_mutex_t xmit_mutex;
+
+       /* The thread this device is running on */
+       pthread_t thread;
+
+       /* The thread used to enable the device */
+       pthread_t enable_thread;
+
+       /* Statistical Information on this device */
+       time_t start_time;
+       struct nic_stats stats;
+
+       /*  Number of retrys from iscsid */
+       uint32_t pending_count;
+       uint32_t pathreq_pending_count;
+
+#define DEFAULT_RX_POLL_USEC   100     /* usec */
+       /* options enabled by the user */
+       uint32_t rx_poll_usec;
+
+       /*  Used to hold hardware specific data */
+       void *priv;
+
+       /*  Used to hold the TX packets that are needed to be sent */
+       struct packet *tx_packet_queue;
+
+       /* Mutex to protect the list of free packets */
+       pthread_mutex_t free_packet_queue_mutex;
+
+       /*  Used to hold the free packets that are needed to be sent */
+       struct packet *free_packet_queue;
+
+       /*  Points to the NIC library */
+       nic_lib_handle_t *nic_library;
+
+       /*  Points to the PCI table entry */
+       struct pci_device_id *pci_id;
+
+       /*  Used to process the interrupt */
+       int (*process_intr) (struct nic *nic);
+
+       struct nic_ops *ops;
+
+       /* NL processing parameters */
+       pthread_t nl_process_thread;
+       pthread_cond_t nl_process_cond;
+       pthread_cond_t nl_process_if_down_cond;
+       pthread_mutex_t nl_process_mutex;
+       int nl_process_if_down;
+       int nl_process_head;
+       int nl_process_tail;
+#define NIC_NL_PROCESS_MAX_RING_SIZE        128
+#define NIC_NL_PROCESS_LAST_ENTRY           (NIC_NL_PROCESS_MAX_RING_SIZE - 1)
+#define NIC_NL_PROCESS_NEXT_ENTRY(x) ((x + 1) & NIC_NL_PROCESS_MAX_RING_SIZE)
+       void *nl_process_ring[NIC_NL_PROCESS_MAX_RING_SIZE];
+
+       /* The thread used to perform ping */
+       pthread_t ping_thread;
+       uint64_t transport_handle;
+} nic_t;
+
+/******************************************************************************
+ * Function Prototypes
+ *****************************************************************************/
+int load_all_nic_libraries();
+
+nic_t *nic_init();
+void nic_add(nic_t *nic);
+int nic_remove(nic_t *nic);
+
+int nic_add_nic_iface(nic_t *nic, nic_interface_t *nic_iface);
+int nic_process_intr(nic_t *nic, int discard_check);
+
+nic_interface_t *nic_iface_init();
+
+typedef enum {
+       NIC_LIBRARY_EXSITS = 1,
+       NIC_LIBRARY_DOESNT_EXIST = 2,
+} NIC_LIBRARY_EXIST_T;
+
+NIC_LIBRARY_EXIST_T does_nic_uio_name_exist(char *name,
+                                           nic_lib_handle_t **handle);
+NIC_LIBRARY_EXIST_T does_nic_library_exist(char *name,
+                                          nic_lib_handle_t **handle);
+
+/*******************************************************************************
+ *  Packet management utility functions
+ ******************************************************************************/
+struct packet *get_next_tx_packet(nic_t *nic);
+struct packet *get_next_free_packet(nic_t *nic);
+void put_packet_in_tx_queue(struct packet *pkt, nic_t *nic);
+void put_packet_in_free_queue(struct packet *pkt, nic_t *nic);
+
+int unload_all_nic_libraries();
+void nic_close(nic_t *nic, NIC_SHUTDOWN_T graceful, int clean);
+
+/*  Use this function to fill in minor number and uio, and eth names */
+int nic_fill_name(nic_t *nic);
+
+int enable_multicast(nic_t *nic);
+int disable_multicast(nic_t *nic);
+
+void nic_set_all_nic_iface_mac_to_parent(nic_t *nic);
+int find_nic_lib_using_pci_id(uint32_t vendor, uint32_t device,
+                             uint32_t subvendor, uint32_t subdevice,
+                             nic_lib_handle_t **handle,
+                             struct pci_device_id **pci_entry);
+
+void *nic_loop(void *arg);
+
+int nic_packet_capture(struct nic *, struct packet *pkt);
+
+int process_packets(nic_t *nic,
+                   struct timer *periodic_timer,
+                   struct timer *arp_timer, nic_interface_t *nic_iface);
+
+void prepare_ustack(nic_t *nic,
+                   nic_interface_t *nic_iface,
+                   struct uip_stack *ustack, struct packet *pkt);
+
+void prepare_ipv4_packet(nic_t *nic,
+                        nic_interface_t *nic_iface,
+                        struct uip_stack *ustack, struct packet *pkt);
+
+void prepare_ipv6_packet(nic_t *nic,
+                        nic_interface_t *nic_iface,
+                        struct uip_stack *ustack, struct packet *pkt);
+
+#endif /* __NIC_H__ */
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/nic_id.c b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/nic_id.c
new file mode 100644 (file)
index 0000000..6da0a38
--- /dev/null
@@ -0,0 +1,364 @@
+/*
+ * Copyright (c) 2009-2011, Broadcom Corporation
+ * Copyright (c) 2014, QLogic Corporation
+ *
+ * Written by:  Benjamin Li  (benli@broadcom.com)
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed by Adam Dunkels.
+ * 4. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * nic_id.c - Using sysfs to determine the PCI vendor, device, subvendor and
+ *            subdevice ID's
+ *
+ */
+#include <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;
+       size_t name_size;
+
+       rc = get_vendor(nic, &vendor);
+       if (rc != 0) {
+               LOG_ERR(PFX "%s: Could not get vendor id [0x%x]",
+                       nic->log_name, rc);
+               return rc;
+       }
+
+       rc = get_subvendor(nic, &subvendor);
+       if (rc != 0) {
+               LOG_ERR(PFX "%s: Could not get subvendor id [0x%x]",
+                       nic->log_name, rc);
+               return rc;
+       }
+
+       rc = get_device(nic, &device);
+       if (rc != 0) {
+               LOG_ERR(PFX "%s: Could not get device id [0x%x]",
+                       nic->log_name, rc);
+               return rc;
+       }
+
+       rc = get_subdevice(nic, &subdevice);
+       if (rc != 0) {
+               LOG_ERR(PFX "%s: Could not get subdevice id [0x%x]",
+                       nic->log_name, rc);
+               return rc;
+       }
+
+       get_bus_slot_func_num(nic, &pci_bus, &pci_slot, &pci_func);
+
+       LOG_DEBUG(PFX "%s: Looking for device vendor: "
+                 "0x%x subvendor: 0x%x device: 0x%x subdevice: 0x%x",
+                 nic->log_name, vendor, subvendor, device, subdevice);
+
+       rc = find_nic_lib_using_pci_id(vendor, device, subvendor, subdevice,
+                                      &handle, &pci_entry);
+
+       if (rc != 0) {
+               LOG_WARN(PFX "%s: Couldn't find proper NIC library",
+                        nic->log_name);
+               return rc;
+       }
+
+       nic->nic_library = handle;
+       nic->pci_id = pci_entry;
+
+       /*  Prepare the NIC library op table */
+       nic->ops = handle->ops;
+       (*nic->ops->lib_ops.get_library_name) (&nic->library_name, &name_size);
+
+       return 0;
+}
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/nic_id.h b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/nic_id.h
new file mode 100644 (file)
index 0000000..340580f
--- /dev/null
@@ -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/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/nic_nl.c b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/nic_nl.c
new file mode 100644 (file)
index 0000000..dee462e
--- /dev/null
@@ -0,0 +1,680 @@
+/*
+ * 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 <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 = 0;
+       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;
+
+               pthread_mutex_lock(&nic->nl_process_mutex);
+               rc = pthread_cond_wait(&nic->nl_process_cond,
+                                      &nic->nl_process_mutex);
+               if (rc != 0) {
+                       pthread_mutex_unlock(&nic->nl_process_mutex);
+                       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 = 0;
+       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 rc;
+}
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/nic_nl.h b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/nic_nl.h
new file mode 100644 (file)
index 0000000..c68d81c
--- /dev/null
@@ -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/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/nic_utils.c b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/nic_utils.c
new file mode 100644 (file)
index 0000000..ef24814
--- /dev/null
@@ -0,0 +1,1813 @@
+/*
+ * 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_netdev_template[] =
+       "/sys/class/iscsi_host/host%d/netdev";
+static const char cnic_uio_sysfs_resc_template[] =
+       "/sys/class/uio/uio%i/device/resource%i";
+static const char iscsi_transport_handle_template[] =
+       "/sys/class/iscsi_transport/%s/handle";
+static const char host_pfx[] = "host";
+
+/**
+ *  manually_trigger_uio_event() - If the uio file node doesn't exist then
+ *                                 try to retrigger udev to create the file
+ *                                 node by touch the uevent file in sysfs
+ *  @param nic - the nic to trigger on
+ *  @param uio_minor - UIO the minor number to use
+ *  @return 0 on success
+ */
+int manually_trigger_uio_event(nic_t *nic, int uio_minor)
+{
+       int fd;
+       char uio_uevent_path[sizeof(uio_uevent_path_template) + 10];
+       char enable_str[] = "online";
+       int rc;
+       size_t bytes_wrote;
+
+       rc = sprintf(uio_uevent_path, uio_uevent_path_template, uio_minor);
+       if (rc < 0) {
+               LOG_ERR(PFX "%s: Could not build uio uevent path",
+                       nic->log_name);
+               return -EIO;
+       }
+
+       LOG_DEBUG(PFX "%s: triggering UIO uevent path: %s",
+                 nic->log_name, uio_uevent_path);
+
+       fd = open(uio_uevent_path, O_WRONLY);
+       if (fd == -1) {
+               LOG_ERR(PFX "%s: Could not open uio uevent path: %s [%s]",
+                       nic->log_name, uio_uevent_path, strerror(errno));
+               return -EIO;
+       }
+
+       bytes_wrote = write(fd, enable_str, sizeof(enable_str));
+       if (bytes_wrote != sizeof(enable_str)) {
+               LOG_ERR(PFX "%s: Could write to uio uevent path: %s [%s]",
+                       nic->log_name, uio_uevent_path, strerror(errno));
+               rc = -EIO;
+       } else
+               rc = 0;
+
+       close(fd);
+       return rc;
+}
+
+static int wait_for_file_node_timed(nic_t *nic, char *filepath, int seconds)
+{
+       struct timeval start_time;
+       struct timeval wait_time;
+       struct timeval total_time;
+       struct timespec sleep_req, sleep_rem;
+
+       sleep_req.tv_sec = 0;
+       sleep_req.tv_nsec = 250000000;
+
+       wait_time.tv_sec = seconds;
+       wait_time.tv_usec = 0;
+
+       if (gettimeofday(&start_time, NULL)) {
+               LOG_ERR(PFX "%s: Couldn't gettimeofday() during watch file: %s"
+                       "[%s]", nic->log_name, filepath, strerror(errno));
+               return -EIO;
+       }
+
+       timeradd(&start_time, &wait_time, &total_time);
+
+       while (1) {
+               struct timeval current_time;
+               struct stat file_stat;
+
+               /*  Check if the file node exists */
+               if (stat(filepath, &file_stat) == 0)
+                       return 0;
+
+               if (gettimeofday(&current_time, NULL)) {
+                       LOG_ERR(PFX "%s: Couldn't get current time for "
+                               "watching file: %s [%s]",
+                               nic->log_name, filepath, strerror(errno));
+                       return -EIO;
+               }
+
+               /*  Timeout has excceded return -ETIME */
+               if (timercmp(&total_time, &current_time, <)) {
+                       LOG_ERR(PFX "%s: timeout waiting %d secs for file: %s",
+                               nic->log_name, seconds, filepath);
+                       return -ETIME;
+               }
+
+               nanosleep(&sleep_req, &sleep_rem);
+       }
+}
+
+/******************************************************************************
+ *  Autodiscovery of iscsi_hosts
+ *****************************************************************************/
+static int filter_host_name(const struct dirent *entry)
+{
+       if ((memcmp(entry->d_name, "host", 4) == 0))
+               return 1;
+       else
+               return 0;
+}
+
+int nic_discover_iscsi_hosts()
+{
+       struct dirent **files;
+       int count;
+       int i;
+       int rc;
+
+       count = scandir(base_iscsi_host_name, &files, filter_host_name,
+                       alphasort);
+
+       switch (count) {
+       case 0:
+               /*  Currently there are no iSCSI hosts */
+               rc = 0;
+               break;
+
+       case -1:
+               LOG_WARN(PFX "Error when scanning path: %s[%s]",
+                        base_iscsi_host_name, strerror(errno));
+               rc = -EINVAL;
+               break;
+
+       default:
+               /*  There are iSCSI hosts */
+               pthread_mutex_lock(&nic_list_mutex);
+               for (i = 0; i < count; i++) {
+                       int host_no;
+                       char *raw = NULL;
+                       uint32_t raw_size = 0;
+                       char temp_path[sizeof(iscsi_host_path_netdev_template) +
+                                      8];
+                       rc = sscanf(files[i]->d_name, host_template, &host_no);
+                       nic_t *nic;
+
+                       LOG_INFO(PFX "Found host[%d]: %s",
+                                host_no, files[i]->d_name);
+
+                       /*  Build the path to determine netdev name */
+                       snprintf(temp_path, sizeof(temp_path),
+                                iscsi_host_path_netdev_template, host_no);
+
+                       rc = capture_file(&raw, &raw_size, temp_path);
+                       if (rc != 0)
+                               continue;
+
+                       rc = from_host_no_find_associated_eth_device(host_no,
+                                                                    &nic);
+                       if (rc != 0) {
+                               /*  Normalize the string */
+                               if (raw[raw_size - 1] == '\n')
+                                       raw[raw_size - 1] = '\0';
+
+                               nic = nic_init();
+                               if (nic == NULL) {
+                                       LOG_ERR(PFX "Couldn't allocate "
+                                               "space for NIC %s "
+                                               "during scan", raw);
+
+                                       free(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;
+                               nic->host_no = host_no;
+
+                               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(ifr.ifr_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;
+}
+
+/**
+ *  from_uio_find_associated_host() - Given the uio minor number
+ *      this function will try to find the assoicated iscsi host
+ *  @param uio_minor - minor number of the UIO device
+ *  @param name - char buffer which will be filled if successful
+ *  @param name_size - size of the name buffer
+ *  @return >0 minor number <0 an error
+ */
+static int from_uio_find_associated_host(nic_t *nic, int uio_minor,
+                                        char *name, size_t name_size)
+{
+       char *path;
+       int rc;
+       int count;
+       struct dirent **files;
+       char *parsed_name;
+       int i;
+       int path_iterator;
+       char *search_paths[] = { "/sys/class/uio/uio%i/device/" };
+       int path_to[] = { 5, 1 };
+       int (*search_filters[]) (const struct dirent *) = { filter_host_name, };
+       char *(*extract_name[]) (struct dirent **files) = {  extract_none, };
+       int extract_name_offset[] = { 0 };
+
+       path = malloc(PATH_MAX);
+       if (!path) {
+               LOG_ERR(PFX "Could not allocate memory for path");
+               rc = -ENOMEM;
+               goto error;
+       }
+
+       for (path_iterator = 0;
+            path_iterator < sizeof(search_paths) / sizeof(search_paths[0]);
+            path_iterator++) {
+               /*  Build the path to determine uio name */
+               rc = sprintf(path, search_paths[path_iterator], uio_minor);
+
+               wait_for_file_node_timed(nic, path, path_to[path_iterator]);
+
+               count = scandir(path, &files,
+                               search_filters[path_iterator], alphasort);
+
+               switch (count) {
+               case 1: {
+                       char *parsed_src;
+                       size_t parsed_size;
+
+                       parsed_name = (*extract_name[path_iterator]) (files);
+                       if (!parsed_name) {
+                               LOG_WARN(PFX "Couldn't find delimiter in: %s",
+                                        files[0]->d_name);
+
+                               break;
+                       }
+
+                       parsed_src = parsed_name + extract_name_offset[path_iterator];
+                       parsed_size = strlen(parsed_src);
+                       if (parsed_size >= name_size) {
+                               LOG_WARN(PFX "uio device name too long: %s (max %d)",
+                                       parsed_src, (int)name_size - 1);
+                               rc = -EINVAL;
+                       } else {
+                               strncpy(name, parsed_src, name_size);
+                               rc = 0;
+                       }
+
+                       free(files[0]);
+                       free(files);
+
+                       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;
+               }
+
+               if (!memcmp(host_pfx, nic->config_device_name,
+                           strlen(host_pfx))) {
+                       rc = from_uio_find_associated_host(nic, uio_minor,
+                                                          eth_name,
+                                                          sizeof(eth_name));
+               } else {
+                       rc = from_uio_find_associated_eth_device(nic, uio_minor,
+                                                                eth_name,
+                                                                sizeof(eth_name));
+               }
+               if (rc != 0) {
+                       LOG_WARN("uio minor: %d not valid [%D]", uio_minor, rc);
+                       continue;
+               }
+
+               if (strncmp(eth_name, interface_name, sizeof(eth_name)) == 0) {
+                       memcpy(nic->eth_device_name,
+                              eth_name, sizeof(nic->eth_device_name));
+
+                       LOG_INFO(PFX "%s associated with uio%d",
+                                nic->eth_device_name, uio_minor);
+
+                       rc = uio_minor;
+                       goto done;
+               }
+       }
+
+       LOG_WARN("Could not find assoicate uio device with %s", interface_name);
+
+       rc = -EINVAL;
+done:
+       if (path != NULL)
+               free(path);
+
+       for (i = 0; i < count; i++)
+               free(files[i]);
+       free(files);
+
+       return rc;
+
+}
+
+/**
+ *  nic_verify_uio_sysfs_name() - Using the name entry in sysfs it will try to
+ *      match the NIC library name
+ *  @param nic - The NIC hardware to check
+ *
+ */
+int nic_verify_uio_sysfs_name(nic_t *nic)
+{
+       char *raw = NULL, *raw_tmp;
+       uint32_t raw_size = 0;
+       char temp_path[sizeof(nic_uio_sysfs_name_tempate) + 8];
+       int rc = 0;
+       nic_lib_handle_t *handle = NULL;
+       size_t name_size;
+
+
+       /*  Build the path to determine uio name */
+       snprintf(temp_path, sizeof(temp_path),
+                nic_uio_sysfs_name_tempate, nic->uio_minor);
+
+       rc = capture_file(&raw, &raw_size, temp_path);
+       if (rc != 0)
+               goto error;
+
+       /* sanitize name string by replacing newline with null termination */
+       raw_tmp = raw;
+       while (*raw_tmp != '\n' && raw_size--)
+               raw_tmp++;
+       *raw_tmp = '\0';
+
+       /*  If the nic library is not set then check if there is a library
+        *  which matches the uio sysfs name */
+       if (nic->nic_library == NULL) {
+               NIC_LIBRARY_EXIST_T exist;
+
+               exist = does_nic_uio_name_exist(raw, &handle);
+               if (exist == NIC_LIBRARY_DOESNT_EXIST) {
+                       LOG_ERR(PFX "%s: could not find library for uio name: %s",
+                               nic->log_name, raw);
+                       rc = -EINVAL;
+                       goto error;
+               }
+
+               /* fill the lib info */
+               nic->nic_library = handle;
+               nic->ops = handle->ops;
+               (*nic->ops->lib_ops.get_library_name) (&nic->library_name,
+                                                      &name_size);
+       } else {
+               /*  Get the uio sysfs name from the NIC library */
+               (*nic->ops->lib_ops.get_uio_name) (&raw_tmp, &name_size);
+
+               if (strncmp(raw, raw_tmp, name_size) != 0) {
+                       LOG_ERR(PFX "%s: uio names not equal: "
+                               "expecting %s got %s from %s",
+                               nic->log_name, raw, raw_tmp, temp_path);
+                       rc = -EINVAL;
+                       goto error;
+               }
+       }
+
+       LOG_INFO(PFX "%s: Verified uio name %s with library %s",
+                nic->log_name, raw, nic->library_name);
+
+error:
+       if (raw)
+               free(raw);
+
+       return rc;
+}
+
+/**
+ * nic_fill_name() - This will initialize all the hardware resources underneath
+ *                   a struct cnic_uio device
+ * @param nic - The nic device to attach the hardware with
+ * @return 0 on success, on failure a errno will be returned
+ */
+int nic_fill_name(nic_t *nic)
+{
+       int rc;
+
+       if ((nic->config_device_name != NULL) &&
+           (memcmp(uio_base_dir, nic->config_device_name,
+                   sizeof(uio_base_dir) - 1) == 0)) {
+               uint16_t uio_minor;
+               char eth_name[sizeof(nic->eth_device_name)];
+
+               wait_for_file_node_timed(nic, nic->config_device_name, 5);
+
+               /*  Determine the minor number for the UIO device */
+               rc = sscanf(nic->config_device_name, uio_udev_path_template,
+                           &uio_minor);
+               if (rc != 1) {
+                       LOG_WARN(PFX "%s: Could not parse for minor number",
+                                nic->uio_device_name);
+                       return -EINVAL;
+               } else
+                       nic->uio_minor = uio_minor;
+
+               nic->uio_device_name = nic->config_device_name;
+
+               /*  Determine the assoicated physical network interface */
+               rc = from_uio_find_associated_eth_device(nic,
+                                                        nic->uio_minor,
+                                                        eth_name,
+                                                        sizeof(eth_name));
+               if (rc != 0) {
+                       LOG_WARN(PFX "%s: Couldn't find associated eth device",
+                                nic->uio_device_name);
+               } else {
+                       memcpy(nic->eth_device_name,
+                              eth_name, sizeof(eth_name));
+               }
+
+               LOG_INFO(PFX "%s: configured for uio device for %s",
+                        nic->log_name, nic->uio_device_name);
+
+       } else {
+               LOG_INFO(PFX "looking for uio device for %s",
+                        nic->config_device_name);
+
+               rc = from_phys_name_find_assoicated_uio_device(nic);
+               if (rc < 0) {
+                       LOG_ERR(PFX "Could not determine UIO name for %s",
+                               nic->config_device_name);
+
+                       return -rc;
+               }
+
+               nic->uio_minor = rc;
+
+               if (nic->flags & NIC_UIO_NAME_MALLOC)
+                       free(nic->uio_device_name);
+
+               nic->uio_device_name =
+                   malloc(sizeof(uio_udev_path_template) + 8);
+               if (nic->uio_device_name == NULL) {
+                       LOG_INFO(PFX "%s: Couldn't malloc space for uio name",
+                                nic->log_name);
+                       return -ENOMEM;
+               }
+
+               snprintf(nic->uio_device_name,
+                        sizeof(uio_udev_path_template) + 8,
+                        uio_udev_path_template, nic->uio_minor);
+
+               nic->flags |= NIC_UIO_NAME_MALLOC;
+       }
+
+       return 0;
+}
+
+void cnic_get_sysfs_pci_resource_path(nic_t *nic, int resc_no,
+                                     char *sys_path, size_t size)
+{
+       /*  Build the path to sysfs pci resource */
+       snprintf(sys_path, size,
+                cnic_uio_sysfs_resc_template, nic->uio_minor, resc_no);
+
+}
+
+void prepare_library(nic_t *nic)
+{
+       int rc;
+       NIC_LIBRARY_EXIST_T exist;
+       nic_lib_handle_t *handle = NULL;
+
+       nic_fill_name(nic);
+
+       /* No assoicated library, we can skip it */
+       if (nic->library_name != NULL) {
+               /*  Check that we have the proper NIC library loaded */
+               exist = does_nic_library_exist(nic->library_name, &handle);
+               if (exist == NIC_LIBRARY_DOESNT_EXIST) {
+                       LOG_ERR(PFX "NIC library doesn't exists: %s",
+                               nic->library_name);
+                       goto error;
+               } else if (handle && (nic->nic_library == handle) &&
+                         (nic->ops == handle->ops)) {
+                       LOG_INFO("%s: Have NIC library '%s'",
+                                nic->log_name, nic->library_name);
+               }
+       }
+
+       /*  Verify the NIC library to use */
+       rc = nic_verify_uio_sysfs_name(nic);
+       if (rc != 0) {
+               /*  Determine the NIC library to use based on the PCI Id */
+               rc = find_set_nic_lib(nic);
+               if (rc != 0) {
+                       LOG_ERR(PFX "%s: Couldn't find NIC library",
+                               nic->log_name);
+                       goto error;
+               }
+
+       }
+
+       LOG_INFO("%s: found NIC with library '%s'",
+                nic->log_name, nic->library_name);
+error:
+       return;
+}
+
+void prepare_nic_thread(nic_t *nic)
+{
+       pthread_attr_t attr;
+       int rc;
+
+       pthread_mutex_lock(&nic->nic_mutex);
+       if (nic->thread == INVALID_THREAD) {
+               struct timespec ts;
+               struct timeval tp;
+
+               LOG_INFO(PFX "%s: spinning up thread for nic", nic->log_name);
+
+               /*  Try to spin up the nic thread */
+               pthread_attr_init(&attr);
+               pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+               rc = pthread_create(&nic->thread, &attr, nic_loop, nic);
+               if (rc != 0) {
+                       LOG_ERR(PFX "%s: Couldn't create thread for nic",
+                               nic->log_name);
+                       goto error;
+               }
+
+               /* Convert from timeval to timespec */
+               rc = gettimeofday(&tp, NULL);
+               ts.tv_sec = tp.tv_sec;
+               ts.tv_nsec = tp.tv_usec * 1000;
+               ts.tv_sec += 5; /*  TODO: hardcoded wait for 5 seconds */
+
+               /*  Wait for the nic loop thread to to running */
+               rc = pthread_cond_timedwait(&nic->nic_loop_started_cond,
+                                           &nic->nic_mutex, &ts);
+
+               LOG_INFO("Created nic thread: %s", nic->log_name);
+       }
+
+
+error:
+       pthread_mutex_unlock(&nic->nic_mutex);
+       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)
+               free(raw);
+
+       return rc;
+}
+
+int get_iscsi_transport_handle(nic_t *nic, uint64_t *handle)
+{
+       char *raw = NULL;
+       uint32_t raw_size = 0;
+       ssize_t elements_read;
+       char temp_path[sizeof(iscsi_transport_handle_template) + 8];
+       int rc;
+
+       /*  Capture RX buffer size */
+       snprintf(temp_path, sizeof(temp_path),
+                iscsi_transport_handle_template, nic->library_name);
+
+       rc = capture_file(&raw, &raw_size, temp_path);
+       if (rc != 0)
+               goto error;
+
+       elements_read = sscanf(raw, "%" PRIu64, handle);
+       if (elements_read != 1) {
+               LOG_ERR(PFX "%s: Couldn't parse transport handle from %s",
+                       nic->log_name, temp_path);
+               rc = -EIO;
+               goto error;
+       }
+
+       rc = 0;
+error:
+       if (raw != NULL)
+               free(raw);
+
+       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) {
+               LOG_DEBUG(PFX "%s: incoming protocol: %d, vlan_id:%d iface_num: %d, request_type: %d",
+                         nic->log_name, protocol, vlan_id, iface_num,  request_type);
+               LOG_DEBUG(PFX "%s: host:%d iface_num: 0x%x VLAN: %d protocol: %d",
+                         nic->log_name, nic->host_no, current->iface_num, current->vlan_id, current->protocol);
+               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/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/nic_utils.h b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/nic_utils.h
new file mode 100644 (file)
index 0000000..e4cf5c1
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * 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);
+
+int get_iscsi_transport_handle(nic_t *nic, uint64_t *handle);
+
+#endif /* __NIC_UTILS_H__ */
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/nic_vlan.c b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/nic_vlan.c
new file mode 100644 (file)
index 0000000..eb33381
--- /dev/null
@@ -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/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/nic_vlan.h b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/nic_vlan.h
new file mode 100644 (file)
index 0000000..610f721
--- /dev/null
@@ -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/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/options.h b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/options.h
new file mode 100644 (file)
index 0000000..873a98a
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * 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 (pthread_t)-1
+#define INVALID_HOST_NO        -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/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/packet.c b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/packet.c
new file mode 100644 (file)
index 0000000..3ce2c6b
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2009-2011, Broadcom Corporation
+ * Copyright (c) 2014, QLogic Corporation
+ *
+ * Written by:  Benjamin Li  (benli@broadcom.com)
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed by Adam Dunkels.
+ * 4. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * packet.c - packet management
+ *
+ */
+#include <errno.h>
+#include <stdio.h>
+#include <string.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;
+       }
+       memset(pkt, 0, max_buf_size + sizeof(struct packet));
+
+       priv = malloc(priv_size);
+       if (priv == NULL) {
+               LOG_ERR("Could not allocate any memory for private structure");
+               goto free_pkt;
+       }
+       memset(priv, 0, priv_size);
+       pkt->max_buf_size = max_buf_size;
+       pkt->priv = priv;
+
+       return pkt;
+
+free_pkt:
+       free(pkt);
+
+       return NULL;
+}
+
+void free_packet(struct packet *pkt)
+{
+       if (pkt->priv != NULL)
+               free(pkt->priv);
+
+       free(pkt);
+}
+
+/**
+ *  reset_packet() - This will reset the packet fields to default values
+ *  @param pkt - the packet to reset
+ */
+void reset_packet(packet_t *pkt)
+{
+       pkt->next = NULL;
+
+       pkt->flags = 0;
+       pkt->vlan_tag = 0;
+
+       pkt->buf_size = 0;
+
+       pkt->data_link_layer = NULL;
+       pkt->network_layer = NULL;
+}
+
+int alloc_free_queue(nic_t *nic, size_t num_of_packets)
+{
+       int i;
+
+       pthread_mutex_lock(&nic->free_packet_queue_mutex);
+       for (i = 0; i < num_of_packets; i++) {
+               packet_t *pkt;
+
+               pkt = alloc_packet(STD_MTU_SIZE, STD_MTU_SIZE);
+               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/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/packet.h b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/packet.h
new file mode 100644 (file)
index 0000000..19d1db9
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * 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"
+
+#define        STD_MTU_SIZE    1500
+
+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/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/ping.c b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/ping.c
new file mode 100644 (file)
index 0000000..58a6d14
--- /dev/null
@@ -0,0 +1,518 @@
+/*
+ * Copyright (c) 2015, QLogic Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed by Adam Dunkels.
+ * 4. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ping.c - Ping implementation for iscsiuio using ICMP/ICMPv6
+ *
+ */
+#include <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 "iscsi_if.h"
+
+#include "uip.h"
+#include "uip_arp.h"
+#include "uip_eth.h"
+#include "dhcpc.h"
+#include "ipv6_ndpc.h"
+#include "ipv6.h"
+
+#include "logger.h"
+#include "nic.h"
+#include "nic_utils.h"
+#include "options.h"
+#include "packet.h"
+#include "bnx2.h"
+#include "bnx2x.h"
+#include "cnic.h"
+#include "ping.h"
+
+#define PFX "ping "
+
+static void fill_payload_data(struct uip_stack *ustack)
+{
+       if (ustack->uip_slen)
+               memset(ustack->uip_appdata, 'A', ustack->uip_slen);
+}
+
+static int prepare_icmpv4_req_pkt(struct ping_conf *png_c, struct packet *pkt,
+                                 uip_ip4addr_t *dst_addr)
+{
+       nic_interface_t *nic_iface = png_c->nic_iface;
+       struct uip_stack *ustack = &nic_iface->ustack;
+       struct uip_ipv4_hdr *ipv4_hdr = NULL;
+       struct uip_icmpv4_hdr *icmpv4_hdr = NULL;
+       u16_t uip_iph_len = 0;
+       u16_t icmpv4_hdr_len = 0;
+       u16_t uip_ip_icmph_len = 0;
+       int mtu = 1500;
+       int rc = 0;
+
+       uip_iph_len = UIP_IPv4_H_LEN;
+       icmpv4_hdr_len = sizeof(*icmpv4_hdr);
+       uip_ip_icmph_len = uip_iph_len + icmpv4_hdr_len;
+
+       ipv4_hdr = (struct uip_ipv4_hdr *)ustack->network_layer;
+
+       icmpv4_hdr = (struct uip_icmpv4_hdr *) (ustack->network_layer +
+                                               sizeof(struct uip_ipv4_hdr));
+
+       /* fill IP header */
+       ipv4_hdr->vhl = 0x45;
+       ipv4_hdr->tos = 0;
+       ++ustack->ipid;
+       ipv4_hdr->ipid[0] = ustack->ipid >> 8;
+       ipv4_hdr->ipid[1] = ustack->ipid & 0xff;
+       ipv4_hdr->ipoffset[0] = 0;
+       ipv4_hdr->ipoffset[1] = 0;
+       ipv4_hdr->ttl = UIP_TTL;
+       ipv4_hdr->proto = UIP_PROTO_ICMP;
+       uip_ip4addr_copy(ipv4_hdr->srcipaddr, ustack->hostaddr);
+       uip_ip4addr_copy(ipv4_hdr->destipaddr, dst_addr);
+
+       LOG_INFO(PFX "src ipaddr: %d.%d.%d.%d",
+                uip_ipaddr1(ipv4_hdr->srcipaddr),
+                uip_ipaddr2(ipv4_hdr->srcipaddr),
+                uip_ipaddr3(ipv4_hdr->srcipaddr),
+                uip_ipaddr4(ipv4_hdr->srcipaddr));
+
+       LOG_INFO(PFX "dest ipaddr: %d.%d.%d.%d",
+                uip_ipaddr1(ipv4_hdr->destipaddr),
+                uip_ipaddr2(ipv4_hdr->destipaddr),
+                uip_ipaddr3(ipv4_hdr->destipaddr),
+                uip_ipaddr4(ipv4_hdr->destipaddr));
+
+       /* fill ICMP header */
+       icmpv4_hdr->type = ICMP_ECHO;
+       icmpv4_hdr->icode = 0;
+       icmpv4_hdr->id = getpid() & 0xffff;
+       png_c->id = icmpv4_hdr->id;
+       icmpv4_hdr->seqno = ustack->ipid;
+       png_c->seqno =icmpv4_hdr->seqno;
+
+       /* appdata and sappdata point to the icmp payload */
+       ustack->uip_appdata = ustack->network_layer + uip_ip_icmph_len;
+       ustack->uip_sappdata = ustack->uip_appdata;
+
+       if (nic_iface->mtu)
+               mtu = nic_iface->mtu;
+
+       if ((mtu - uip_ip_icmph_len) > png_c->datalen) {
+               ustack->uip_slen = png_c->datalen;
+       } else {
+               png_c->state = ISCSI_PING_OVERSIZE_PACKET;
+               LOG_ERR(PFX "MTU=%d, payload=%d\n",
+                       mtu, png_c->datalen);
+               rc = -EINVAL;
+               goto done;
+       }
+
+       fill_payload_data(ustack);
+
+       /* Calculate ICMP checksum. */
+       icmpv4_hdr->icmpchksum = 0;
+       icmpv4_hdr->icmpchksum = ~(uip_chksum((u16_t *)icmpv4_hdr,
+                                             icmpv4_hdr_len +
+                                             ustack->uip_slen));
+       if (icmpv4_hdr->icmpchksum == 0)
+               icmpv4_hdr->icmpchksum = 0xffff;
+
+       /* IPv4 total length = IPv4 HLEN + ICMP HLEN + Payload len */
+       ustack->uip_len = uip_ip_icmph_len + ustack->uip_slen;
+       ipv4_hdr->len[0] = (ustack->uip_len >> 8);
+       ipv4_hdr->len[1] = (ustack->uip_len & 0xff);
+
+       /* Calculate IP checksum. */
+       ipv4_hdr->ipchksum = 0;
+       ipv4_hdr->ipchksum = ~(uip_ipchksum(ustack));
+       if (ipv4_hdr->ipchksum == 0)
+               ipv4_hdr->ipchksum = 0xffff;
+
+        ++ustack->stats.ip.sent;
+        /* Return and let the caller do the actual transmission. */
+        ustack->uip_flags = 0;
+
+done:
+       return rc;
+}
+
+static void prepare_icmpv6_req_pkt(struct ping_conf *png_c, struct packet *pkt,
+                                  uip_ip6addr_t *dst_addr,
+                                  uip_ip6addr_t *src_addr)
+{
+       nic_interface_t *nic_iface = png_c->nic_iface;
+       struct uip_stack *ustack = &nic_iface->ustack;
+       struct uip_ipv6_hdr *ipv6_hdr = NULL;
+       uip_icmp_echo_hdr_t *icmp_echo_hdr = NULL;
+       u16_t uip_iph_len = 0;
+       u16_t icmp_echo_hdr_len = 0;
+       u16_t uip_ip_icmph_len = 0;
+       char ipbuf[INET6_ADDRSTRLEN] = {0};
+
+       uip_iph_len = UIP_IPv6_H_LEN;
+       icmp_echo_hdr_len = sizeof(*icmp_echo_hdr);
+       uip_ip_icmph_len = uip_iph_len + icmp_echo_hdr_len;
+
+       ipv6_hdr = (struct uip_ipv6_hdr *)ustack->network_layer;
+
+       icmp_echo_hdr = (uip_icmp_echo_hdr_t *) (ustack->network_layer +
+                                                sizeof(struct uip_ipv6_hdr));
+
+       /* fill IPv6 header */
+       ipv6_hdr->vtc = 0x60;
+       ipv6_hdr->tcflow = 0;
+       ipv6_hdr->flow = 0;
+       ipv6_hdr->proto = UIP_PROTO_ICMP6;
+       ipv6_hdr->ttl = UIP_TTL;
+       uip_ip6addr_copy(ipv6_hdr->srcipaddr, src_addr);
+       uip_ip6addr_copy(ipv6_hdr->destipaddr, dst_addr);
+
+       memset(ipbuf, 0, sizeof(ipbuf));
+       if (inet_ntop(AF_INET6, &ipv6_hdr->srcipaddr, ipbuf, INET6_ADDRSTRLEN))
+               LOG_INFO(PFX "src ipaddr=%s", ipbuf);
+
+       memset(ipbuf, 0, sizeof(ipbuf));
+       if (inet_ntop(AF_INET6, &ipv6_hdr->destipaddr, ipbuf, INET6_ADDRSTRLEN))
+               LOG_INFO(PFX "dest ipaddr=%s", ipbuf);
+
+       /* fill ICMP header */
+       icmp_echo_hdr->type = ICMPV6_ECHO_REQ;
+       icmp_echo_hdr->icode = 0;
+       icmp_echo_hdr->id = HOST_TO_NET16(getpid() & 0xffff);
+       png_c->id = icmp_echo_hdr->id;
+       ++ustack->ipid;
+       icmp_echo_hdr->seqno = HOST_TO_NET16(ustack->ipid);
+       png_c->seqno = icmp_echo_hdr->seqno;
+
+       /* appdata and sappdata point to the icmp payload */
+       ustack->uip_appdata = ustack->network_layer + uip_ip_icmph_len;
+       ustack->uip_sappdata = ustack->uip_appdata;
+       ustack->uip_slen = png_c->datalen;
+
+       fill_payload_data(ustack);
+
+       /* Total length = ETH HLEN + IPv6 HLEN + ICMP HLEN + Data len */
+       ustack->uip_len =  UIP_LLH_LEN + uip_ip_icmph_len + ustack->uip_slen;
+       /* IPv6 payload len */
+       ipv6_hdr->len = HOST_TO_NET16(icmp_echo_hdr_len + ustack->uip_slen);
+
+       /* Calculate ICMP checksum. */
+       icmp_echo_hdr->icmpchksum = 0;
+       icmp_echo_hdr->icmpchksum = ~(uip_icmp6chksum(ustack));
+
+        ++ustack->stats.ip.sent;
+        /* Return and let the caller do the actual transmission. */
+        ustack->uip_flags = 0;
+       return;
+}
+
+static int chk_arp_entry_for_dst_addr(nic_t *nic, nic_interface_t *nic_iface,
+                                     void *addr)
+{
+       struct iscsi_path path;
+       uip_ip4addr_t dst_addr4;
+       uip_ip6addr_t dst_addr6;
+
+       if (nic_iface->protocol == AF_INET) {
+               memcpy(dst_addr4, addr, sizeof(uip_ip4addr_t));
+               memcpy(&path.dst.v4_addr, dst_addr4, sizeof(struct in_addr));
+               path.ip_addr_len = 4;
+       } else {
+               memcpy(dst_addr6, addr, sizeof(uip_ip6addr_t));
+               memcpy(&path.dst.v6_addr, dst_addr6, sizeof(struct in6_addr));
+               path.ip_addr_len = 16;
+       }
+
+       return cnic_handle_iscsi_path_req(nic, 0, NULL, &path, nic_iface);
+}
+
+static int fill_icmpv6_eth_hdr(struct uip_stack *ustack,
+                               uip_ip6addr_t *dst_addr6)
+{
+       struct uip_eth_hdr *eth;
+       __u8 mac_addr[6];
+       struct ndpc_reqptr req_ptr;
+       int rc = 0;
+       int ret = 0;
+
+       eth = (struct uip_eth_hdr *)ustack->data_link_layer;
+       memcpy(eth->src.addr, ustack->uip_ethaddr.addr, sizeof(eth->src.addr));
+
+       memset(mac_addr, 0, sizeof(mac_addr));
+       req_ptr.eth = (void *)mac_addr;
+       req_ptr.ipv6 = (void *)dst_addr6;
+
+       ret = ndpc_request(ustack, &req_ptr, &rc, CHECK_ARP_TABLE);
+       if (ret) {
+               LOG_DEBUG(PFX "ndpc request failed");
+               rc = ret;
+       } else if (rc) {
+               memcpy(eth->dest.addr, mac_addr, sizeof(eth->dest.addr));
+               LOG_DEBUG(PFX "ipv6 arp entry present");
+               rc = 0;
+       } else {
+               LOG_DEBUG(PFX "ipv6 arp entry not present");
+               rc = -EAGAIN;
+       }
+
+       return rc;
+}
+
+static int determine_src_ipv6_addr(nic_interface_t *nic_iface,
+                                  uip_ip6addr_t *dst_addr6,
+                                  uip_ip6addr_t *src_addr6)
+{
+       struct in6_addr *addr;
+       int rc = 0;
+       int ret = 0;
+
+       if (nic_iface->ustack.ip_config == IPV6_CONFIG_STATIC) {
+               memcpy(src_addr6, &nic_iface->ustack.hostaddr6,
+                      sizeof(uip_ip6addr_t));
+               goto done;
+       }
+
+       ret = ndpc_request(&nic_iface->ustack, dst_addr6,
+                        &rc, CHECK_LINK_LOCAL_ADDR);
+       if (ret) {
+               LOG_DEBUG(PFX "Check LL failed");
+               rc = ret;
+               goto done;
+       }
+
+       if (rc) {
+               LOG_DEBUG(PFX "Use LL");
+               /* Get link local IPv6 address */
+               addr = (struct in6_addr *)&nic_iface->ustack.linklocal6;
+               rc = 0;
+       } else {
+               LOG_DEBUG(PFX "Use Best matched");
+               ret = ndpc_request(&nic_iface->ustack,
+                                dst_addr6,
+                                &addr, GET_HOST_ADDR);
+               if (ret) {
+                       LOG_DEBUG(PFX "Use Best matched failed");
+                       rc = ret;
+                       goto done;
+               }
+               if (addr == NULL) {
+                       LOG_DEBUG(PFX "No Best matched found");
+                       rc = -EINVAL;
+                       goto done;
+               }
+       }
+
+       /* Got the best matched src IP address */
+       memcpy(src_addr6, addr, sizeof(struct in6_addr));
+
+done:
+       return rc;
+}
+
+void ping_init(struct ping_conf *png_c, void *addr, u16_t type, int datalen)
+{
+       png_c->dst_addr = addr;
+       png_c->proto = type;
+       png_c->state = PING_INIT_STATE;
+       png_c->datalen = datalen;
+       return;
+}
+
+int do_ping_from_nic_iface(struct ping_conf *png_c)
+{
+       packet_t *pkt;
+       nic_interface_t *nic_iface = png_c->nic_iface;
+       nic_t *nic = nic_iface->parent;
+       struct uip_stack *ustack = &nic_iface->ustack;
+       uip_ip4addr_t dst_addr4;
+       uip_ip6addr_t dst_addr6;
+       uip_ip6addr_t src_addr6;
+       struct timer ping_timer;
+       int rc = 0;
+
+       memset(dst_addr4, 0, sizeof(uip_ip4addr_t));
+       memset(dst_addr6, 0, sizeof(uip_ip6addr_t));
+       memset(src_addr6, 0, sizeof(uip_ip6addr_t));
+
+       if (nic_iface->protocol == AF_INET)
+               memcpy(dst_addr4, png_c->dst_addr, sizeof(uip_ip4addr_t));
+       else
+               memcpy(dst_addr6, png_c->dst_addr, sizeof(uip_ip6addr_t));
+
+       rc = chk_arp_entry_for_dst_addr(nic, nic_iface, png_c->dst_addr);
+
+       if (rc && (nic_iface->protocol == AF_INET)) {
+               png_c->state = ISCSI_PING_NO_ARP_RECEIVED;
+               LOG_ERR(PFX "ARP failure for IPv4 dest addr");
+               goto done;
+       } else if ((rc < 1) && (nic_iface->protocol == AF_INET6)) {
+               png_c->state = ISCSI_PING_NO_ARP_RECEIVED;
+               LOG_ERR(PFX "ARP failure for IPv6 dest addr");
+               goto done;
+       } else if (rc < 0) {
+               LOG_ERR(PFX "ARP failure");
+               goto done;
+       }
+
+       pthread_mutex_lock(&nic->nic_mutex);
+       pkt = get_next_free_packet(nic);
+       if (pkt == NULL) {
+               pthread_mutex_unlock(&nic->nic_mutex);
+               LOG_ERR(PFX "Unable to get a free packet buffer");
+               rc = -EIO;
+               goto done;
+       }
+
+       prepare_ustack(nic, nic_iface, ustack, pkt);
+
+       if (nic_iface->protocol == AF_INET) {
+               rc = prepare_icmpv4_req_pkt(png_c, pkt, &dst_addr4);
+               if (rc)
+                       goto put_pkt;
+
+               /* If the above function invocation resulted
+                * in data that should be sent out on the
+                * network, the global variable uip_len is
+                * set to a value > 0. */
+               if (ustack->uip_len > 0) {
+                       pkt->buf_size = ustack->uip_len;
+
+                       prepare_ipv4_packet(nic, nic_iface, ustack, pkt);
+
+                       LOG_DEBUG(PFX "Send ICMP echo request");
+                       (*nic->ops->write) (nic, nic_iface, pkt);
+                       ustack->uip_len = 0;
+               }
+       } else {
+               rc = determine_src_ipv6_addr(nic_iface, &dst_addr6, &src_addr6);
+               if (rc)
+                       goto put_pkt;
+
+               prepare_icmpv6_req_pkt(png_c, pkt, &dst_addr6, &src_addr6);
+
+               /* If the above function invocation resulted
+                * in data that should be sent out on the
+                * network, the global variable uip_len is
+                * set to a value > 0. */
+               if (ustack->uip_len > 0) {
+                       pkt->buf_size = ustack->uip_len;
+
+                       prepare_ipv6_packet(nic, nic_iface, ustack, pkt);
+                       rc = fill_icmpv6_eth_hdr(ustack, &dst_addr6);
+                       if (rc) {
+                               ustack->uip_len = 0;
+                               goto put_pkt;
+                       }
+
+                       LOG_DEBUG(PFX "Send ICMPv6 echo request");
+                       (*nic->ops->write) (nic, nic_iface, pkt);
+                       ustack->uip_len = 0;
+               }
+       }
+
+put_pkt:
+       put_packet_in_free_queue(pkt, nic);
+       pthread_mutex_unlock(&nic->nic_mutex);
+
+       if (rc) {
+               LOG_DEBUG(PFX "Ping request not transmitted");
+               goto done;
+       }
+
+       timer_set(&ping_timer, CLOCK_SECOND * 10);
+
+       while ((event_loop_stop == 0) &&
+              (nic->flags & NIC_ENABLED) && !(nic->flags & NIC_GOING_DOWN)) {
+
+               rc = nic_process_intr(nic, 1);
+
+               while ((rc > 0) && (!(nic->flags & NIC_GOING_DOWN))) {
+                       rc = process_packets(nic, NULL, NULL, nic_iface);
+               }
+
+               if (!rc && (png_c->state == ISCSI_PING_SUCCESS)) {
+                       LOG_INFO(PFX "PING successful!");
+                       break;
+               }
+
+               if (timer_expired(&ping_timer)) {
+                       png_c->state = ISCSI_PING_TIMEOUT;
+                       LOG_ERR(PFX "PING timeout");
+                       rc = -EIO;
+                       break;
+               }
+       }
+
+done:
+       return rc;
+}
+
+int process_icmp_packet(uip_icmp_echo_hdr_t *icmp_hdr,
+                       struct uip_stack *ustack)
+{
+       struct ping_conf *png_c = (struct ping_conf *)ustack->ping_conf;
+       int rc = 0;
+
+       LOG_INFO(PFX "Verify ICMP echo reply");
+
+       if ((icmp_hdr->type == ICMPV6_ECHO_REPLY &&
+            png_c->proto == AF_INET6) ||
+            (icmp_hdr->type == ICMP_ECHO_REPLY &&
+             png_c->proto == AF_INET)) {
+
+               if ((icmp_hdr->icode == 0) &&
+                   (icmp_hdr->id == png_c->id) &&
+                   (icmp_hdr->seqno == png_c->seqno)) {
+                               png_c->state = ISCSI_PING_SUCCESS;
+               } else {
+                       rc = 1;
+               }
+       } else {
+               rc = 1;
+       }
+
+       if (rc) {
+               LOG_INFO(PFX "ICMP echo reply verification failed!");
+       } else {
+               LOG_INFO(PFX "ICMP echo reply OK");
+       }
+
+       return rc;
+}
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/ping.h b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/ping.h
new file mode 100644 (file)
index 0000000..82ace6f
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2015, QLogic Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed by Adam Dunkels.
+ * 4. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ping.h - PING header file
+ *
+ */
+
+#ifndef __PING_H__
+#define __PING_H__
+
+#include "nic_nl.h"
+#include "uip.h"
+
+#define ICMP_ECHO_REPLY 0
+#define ICMP_ECHO       8
+
+#define ICMPV6_ECHO_REQ                128
+#define ICMPV6_ECHO_REPLY      129
+
+#define DEF_ICMP_PAYLOAD       32
+#define DEF_ICMPV6_PAYLOAD     16
+
+#define PING_INIT_STATE (-1)
+
+struct ping_conf
+{
+       nic_t *nic;
+       nic_interface_t *nic_iface;
+       void *data;
+       int state;
+       void *dst_addr;
+       u16_t proto;
+       u16_t id;
+       u16_t seqno;
+       u16_t datalen;
+};
+
+void ping_init(struct ping_conf *png_c, void *addr, u16_t type, int datalen);
+
+int do_ping_from_nic_iface(struct ping_conf *png_c);
+
+int process_icmp_packet(uip_icmp_echo_hdr_t *icmp_hdr,
+                       struct uip_stack *ustack);
+
+#endif /* __PING_H__ */
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/uip-conf.h b/pkgs/open-iscsi/open-iscsi-2.1.8/iscsiuio/src/unix/uip-conf.h
new file mode 100644 (file)
index 0000000..e6e11a5
--- /dev/null
@@ -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/pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/Makefile b/pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/Makefile
new file mode 100644 (file)
index 0000000..0d215fc
--- /dev/null
@@ -0,0 +1,125 @@
+# Makefile
+#
+# Copyright (C) 2017 Red Hat, Inc.
+# Gris Ge <fge@redhat.com>
+#
+
+ifeq ($(TOPDIR),)
+       TOPDIR = ..
+endif
+
+DESTDIR ?=
+prefix ?= /usr
+INSTALL ?= install
+exec_prefix =
+etcdir = /etc
+SBINDIR ?= $(exec_prefix)/sbin
+DBROOT ?= $(etcdir)/iscsi
+
+ifndef LIB_DIR
+       ifeq ($(shell test -d /lib64 && echo 1),1)
+               LIB_DIR=$(prefix)/lib64
+       else
+               LIB_DIR=$(prefix)/lib
+       endif
+endif
+
+INCLUDE_DIR ?= $(prefix)/include
+PKGCONF_DIR ?= $(LIB_DIR)/pkgconfig
+MAN_DIR = $(prefix)/share/man
+
+PKG_CONFIG ?= /usr/bin/pkg-config
+
+LIBISCSI_USR_DIR=$(TOPDIR)/libopeniscsiusr
+
+LIBISCSI_USR_VERSION_MAJOR=0
+LIBISCSI_USR_VERSION=0.2.0
+SONAME=$(LIBISCSI_USR_VERSION)
+DEVLIB = libopeniscsiusr.so
+LIBS = $(DEVLIB).$(SONAME)
+LIBS_MAJOR = $(DEVLIB).$(LIBISCSI_USR_VERSION_MAJOR)
+PKGFILE = libopeniscsiusr.pc
+HEADERS = libopeniscsiusr/libopeniscsiusr.h \
+         libopeniscsiusr/libopeniscsiusr_common.h \
+         libopeniscsiusr/libopeniscsiusr_session.h \
+         libopeniscsiusr/libopeniscsiusr_iface.h \
+         libopeniscsiusr/libopeniscsiusr_node.h
+TESTS = tests/test_context tests/test_session tests/test_iface tests/test_node
+EXTRA_MAN_FILE = libopeniscsiusr.h.3
+
+OBJS = context.o misc.o session.o sysfs.o iface.o idbm.o node.o default.o
+
+CFLAGS ?= -O2 -g
+CFLAGS += -Wall -Werror -Wextra -fvisibility=hidden -fPIC
+CFLAGS += $(shell $(PKG_CONFIG) --cflags libkmod)
+CFLAGS += -DSBINDIR=\"$(SBINDIR)\"
+CFLAGS += -DISCSI_DB_ROOT=\"$(DBROOT)\"
+CFLAGS += -DISCSI_VERSION_STR=\"$(ISCSI_VERSION_STR)\"
+
+LDFLAGS += $(shell $(PKG_CONFIG) --libs libkmod)
+
+LIBADD =
+
+all: $(LIBS) $(LIBS_MAJOR) $(TESTS) doc
+
+$(LIBS): $(OBJS)
+       $(CC) $(CFLAGS) -shared -Wl,-soname=$@ -o $@ $(OBJS) $(LDFLAGS) $(LIBADD)
+       ln -sf $@ $(DEVLIB)
+
+$(LIBS_MAJOR): $(LIBS)
+       ln -sf $(LIBS) $@
+
+clean:
+       $(RM) vgcore* core *.a *.o *.so *.so.* $(TESTS)
+       $(RM) -r docs/man
+
+distclean: ;
+
+$(TESTS): $(LIBS)
+$(TESTS): CFLAGS += -I$(TOPDIR)/libopeniscsiusr -g
+$(TESTS): LDFLAGS += $(LIBADD) -L$(TOPDIR)/libopeniscsiusr -lopeniscsiusr
+
+check: $(LIBS) $(TESTS)
+       sudo env LD_LIBRARY_PATH=$(LIBISCSI_USR_DIR) TESTS="$(TESTS)" \
+               tests/runtest.sh || exit 1;
+
+install: install_libs install_docs install_pkg_files
+
+install_libs: $(LIBS) $(LIBS_MAJOR)
+       $(INSTALL) -d $(DESTDIR)$(LIB_DIR)/
+       $(INSTALL) -d $(DESTDIR)$(INCLUDE_DIR)/
+       $(INSTALL) $(LIBS) $(DESTDIR)$(LIB_DIR)/
+       ln -sf $(LIBS) $(DESTDIR)$(LIB_DIR)/$(DEVLIB)
+       ln -sf $(LIBS) $(DESTDIR)$(LIB_DIR)/$(LIBS_MAJOR)
+       $(INSTALL) -m 644 $(HEADERS) $(DESTDIR)$(INCLUDE_DIR)/
+
+install_docs: doc
+       $(INSTALL) -d $(DESTDIR)$(MAN_DIR)/man3
+       $(INSTALL) -m 644 docs/man/*.3 $(DESTDIR)$(MAN_DIR)/man3/
+
+install_pkg_files:
+       $(INSTALL) -m 644 -D $(PKGFILE).in $(DESTDIR)$(PKGCONF_DIR)/$(PKGFILE)
+       perl -i -pe 's|__VERSION__|$(LIBISCSI_USR_VERSION)|g' \
+               $(DESTDIR)$(PKGCONF_DIR)/$(PKGFILE)
+       perl -i -pe 's|__LIB_DIR__|$(LIB_DIR)|g' \
+               $(DESTDIR)$(PKGCONF_DIR)/$(PKGFILE)
+       perl -i -pe 's|__INCLUDE_DIR__|$(INCLUDE_DIR)|g' \
+               $(DESTDIR)$(PKGCONF_DIR)/$(PKGFILE)
+
+doc: docs/man/$(EXTRA_MAN_FILE)
+
+# install the static man page, and generate lots of lib man pages
+# note: the last line just prints out the man page names
+docs/man/$(EXTRA_MAN_FILE): $(HEADERS)
+       $(INSTALL) -v -m 644 -D docs/$(EXTRA_MAN_FILE) $@
+       @echo generating library man pages ...
+       @for h in $(HEADERS); do \
+           for f in `docs/list-man-pages.sh $$h`; do \
+               docs/kernel-doc -module libopeniscsiusr \
+                       -man -function $$f $$h >docs/man/$$f.3 ; \
+           done; \
+       done
+       find docs/man -type f -name \*[0-9]
+
+.PHONY: all install clean distclean doc install_pkg_files install_docs \
+       install_libs check
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/TODO b/pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/TODO
new file mode 100644 (file)
index 0000000..21f3893
--- /dev/null
@@ -0,0 +1,3 @@
+TODO:
+ * Add more debug message.
+ * Support of SYSFS_PATH environment.
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/context.c b/pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/context.c
new file mode 100644 (file)
index 0000000..c5e869f
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Gris Ge <fge@redhat.com>
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <assert.h>
+
+#include "libopeniscsiusr/libopeniscsiusr.h"
+#include "misc.h"
+#include "context.h"
+
+_iscsi_getter_func_gen(iscsi_context, log_priority, int);
+
+_iscsi_getter_func_gen(iscsi_context, userdata, void *);
+
+struct iscsi_context *iscsi_context_new(void)
+{
+       struct iscsi_context *ctx = NULL;
+
+       ctx = (struct iscsi_context *) malloc(sizeof(struct iscsi_context));
+
+       if (ctx == NULL)
+               return NULL;
+
+       ctx->log_func = _iscsi_log_stderr;
+       ctx->log_priority = LIBISCSI_LOG_PRIORITY_DEFAULT;
+       ctx->userdata = NULL;
+       ctx->db = _idbm_new();
+       if (ctx->db == NULL) {
+               free(ctx);
+               return NULL;
+       }
+
+       return ctx;
+}
+
+void iscsi_context_free(struct iscsi_context *ctx)
+{
+       if (ctx == NULL)
+               return;
+
+       if (ctx->db)
+               _idbm_free(ctx->db);
+
+       free(ctx);
+}
+
+void iscsi_context_log_priority_set(struct iscsi_context *ctx, int priority)
+{
+       assert(ctx != NULL);
+       ctx->log_priority = priority;
+}
+
+void iscsi_context_log_func_set
+       (struct iscsi_context *ctx,
+        void (*log_func)(struct iscsi_context *ctx, int priority,
+                         const char *file, int line, const char *func_name,
+                         const char *format, va_list args))
+{
+       assert(ctx != NULL);
+       ctx->log_func = log_func;
+}
+
+void iscsi_context_userdata_set(struct iscsi_context *ctx, void *userdata)
+{
+       assert(ctx != NULL);
+       ctx->userdata = userdata;
+}
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/context.h b/pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/context.h
new file mode 100644 (file)
index 0000000..a7093a8
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2017-2018 Red Hat, Inc.
+ *
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Gris Ge <fge@redhat.com>
+ */
+#ifndef __ISCSI_USR_CONTEXT_H__
+#define __ISCSI_USR_CONTEXT_H__
+
+#include "idbm.h"
+#include <stdarg.h>
+
+struct iscsi_context {
+       void (*log_func)(struct iscsi_context *ctx, int priority,
+                        const char *file, int line, const char *func_name,
+                        const char *format, va_list args);
+       int log_priority;
+       void *userdata;
+       struct idbm *db;
+};
+
+
+#endif /* End of __ISCSI_USR_CONTEXT_H__ */
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/default.c b/pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/default.c
new file mode 100644 (file)
index 0000000..d3b3da3
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2017-2018 Red Hat, Inc.
+ *
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Gris Ge <fge@redhat.com>
+ */
+
+#include <string.h>
+
+#include "libopeniscsiusr/libopeniscsiusr.h"
+#include "default.h"
+#include "iface.h"
+#include "node.h"
+
+#define CONFIG_DIGEST_NEVER    0
+
+static void default_session_op_cfg(struct iscsi_session_op_cfg *op_cfg)
+{
+       op_cfg->InitialR2T = 0;
+       op_cfg->ImmediateData = 1;
+       op_cfg->FirstBurstLength = DEF_INI_FIRST_BURST_LEN;
+       op_cfg->MaxBurstLength = DEF_INI_MAX_BURST_LEN;
+       op_cfg->DefaultTime2Wait = ISCSI_DEF_TIME2WAIT;
+       op_cfg->DefaultTime2Retain = 0;
+       op_cfg->MaxConnections = 1;
+       op_cfg->MaxOutstandingR2T = 1;
+       op_cfg->ERL = 0;
+       op_cfg->FastAbort = 1;
+}
+
+static void default_conn_op_cfg(struct iscsi_conn_op_cfg *op_cfg)
+{
+       op_cfg->MaxXmitDataSegmentLength = 0;
+       op_cfg->MaxRecvDataSegmentLength = DEF_INI_MAX_RECV_SEG_LEN;
+       op_cfg->HeaderDigest = DIGEST_NEVER;
+       op_cfg->DataDigest = DIGEST_NEVER;
+       op_cfg->IFMarker = 0;
+       op_cfg->OFMarker = 0;
+}
+
+/*
+ * default is to use tcp through whatever the network layer
+ * selects for us with the /etc/iscsi/initiatorname.iscsi iname.
+ */
+static void default_iface(struct iscsi_iface *iface)
+{
+       snprintf(iface->transport_name,
+                sizeof(iface->transport_name)/sizeof(char),
+                DEFAULT_TRANSPORT);
+
+       if (!strlen(iface->name))
+               snprintf(iface->name, sizeof(iface->name)/sizeof(char),
+                        DEFAULT_IFACENAME);
+}
+
+void _default_node(struct iscsi_node *node)
+{
+       node->tpgt = PORTAL_GROUP_TAG_UNKNOWN;
+       node->disc_type = DISCOVERY_TYPE_STATIC;
+       node->leading_login = 0;
+       node->session.cmds_max = CMDS_MAX;
+       node->session.xmit_thread_priority = XMIT_THREAD_PRIORITY;
+       node->session.initial_cmdsn = 0;
+       node->session.queue_depth = QUEUE_DEPTH;
+       node->session.nr_sessions = 1;
+       node->session.initial_login_retry_max = DEF_INITIAL_LOGIN_RETRIES_MAX;
+       node->session.reopen_max = DEF_SESSION_REOPEN_MAX;
+       node->session.auth.authmethod = 0;
+       /* TYPE_INT_LIST fields should be initialized to ~0 to indicate unset values */
+       memset(node->session.auth.chap_algs, ~0, sizeof(node->session.auth.chap_algs));
+       node->session.auth.chap_algs[0] = ISCSI_AUTH_CHAP_ALG_MD5;
+       node->session.auth.password_length = 0;
+       node->session.auth.password_in_length = 0;
+       node->session.err_tmo.abort_timeout = DEF_ABORT_TIMEO;
+       node->session.err_tmo.lu_reset_timeout = DEF_LU_RESET_TIMEO;
+       node->session.err_tmo.tgt_reset_timeout = DEF_TGT_RESET_TIMEO;
+       node->session.err_tmo.host_reset_timeout = DEF_HOST_RESET_TIMEO;
+       node->session.tmo.replacement_timeout = DEF_REPLACEMENT_TIMEO;
+       node->session.se = NULL;
+       node->session.sid = 0;
+       node->session.multiple = 0;
+       node->session.scan = DEF_INITIAL_SCAN;
+
+       default_session_op_cfg(&node->session.op_cfg);
+
+       node->conn.startup = ISCSI_STARTUP_MANUAL;
+       node->conn.port = ISCSI_DEFAULT_PORT;
+       node->conn.tcp.window_size = TCP_WINDOW_SIZE;
+       node->conn.tcp.type_of_service = 0;
+       node->conn.tmo.login_timeout= DEF_LOGIN_TIMEO;
+       node->conn.tmo.logout_timeout= DEF_LOGOUT_TIMEO;
+       node->conn.tmo.auth_timeout = 45;
+       node->conn.tmo.noop_out_interval = DEF_NOOP_OUT_INTERVAL;
+       node->conn.tmo.noop_out_timeout = DEF_NOOP_OUT_TIMEO;
+
+       default_conn_op_cfg(&node->conn.op_cfg);
+
+       default_iface(&node->iface);
+}
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/default.h b/pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/default.h
new file mode 100644 (file)
index 0000000..ba49bf1
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2017-2018 Red Hat, Inc.
+ *
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Gris Ge <fge@redhat.com>
+ */
+
+#ifndef __ISCSI_USR_DEFAULT_H__
+#define __ISCSI_USR_DEFAULT_H__
+
+#include "libopeniscsiusr/libopeniscsiusr_common.h"
+#include "rfc.h"
+#include "idbm.h"
+
+#define PORTAL_GROUP_TAG_UNKNOWN       -1
+/* q depths */
+#define CMDS_MAX                       128
+#define QUEUE_DEPTH                    32
+
+/* system */
+#define XMIT_THREAD_PRIORITY           -20
+
+/* login retries */
+#define DEF_INITIAL_LOGIN_RETRIES_MAX  4
+
+/* autoscan enabled */
+#define DEF_INITIAL_SCAN               INIT_SCAN_AUTO
+
+/*
+ * Default initiator settings. These may not be the same as
+ * in the RFC. See libopeniscsiusr/libopeniscsiusr_rfc.h for those.
+ */
+/* timeouts in seconds */
+#define DEF_LOGIN_TIMEO                        30
+#define DEF_LOGOUT_TIMEO               15
+#define DEF_NOOP_OUT_INTERVAL          5
+#define DEF_NOOP_OUT_TIMEO             5
+#define DEF_REPLACEMENT_TIMEO          120
+
+#define DEF_ABORT_TIMEO                        15
+#define DEF_LU_RESET_TIMEO             30
+#define DEF_TGT_RESET_TIMEO            30
+#define DEF_HOST_RESET_TIMEO           60
+
+/* session reopen max retries */
+#define        DEF_SESSION_REOPEN_MAX          0
+
+/* default window size */
+#define TCP_WINDOW_SIZE                        (512 * 1024)
+
+/* data and segment lengths in bytes */
+#define DEF_INI_FIRST_BURST_LEN                262144
+#define DEF_INI_MAX_BURST_LEN          16776192
+#define DEF_INI_MAX_RECV_SEG_LEN       262144
+
+#define DEFAULT_TRANSPORT      "tcp"
+#define DEFAULT_IFACENAME      "default"
+#define DEFAULT_NETDEV         "default"
+#define DEFAULT_IPADDRESS      "default"
+#define DEFAULT_HWADDRESS      "default"
+
+void __DLL_LOCAL _default_node(struct iscsi_node *node);
+
+#endif /* End of __ISCSI_USR_DEFAULT_H__ */
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/docs/kernel-doc b/pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/docs/kernel-doc
new file mode 100755 (executable)
index 0000000..75b68a8
--- /dev/null
@@ -0,0 +1,3229 @@
+#!/usr/bin/env perl
+
+use warnings;
+use strict;
+
+## Copyright (c) 1998 Michael Zucchi, All Rights Reserved        ##
+## Copyright (C) 2000, 1  Tim Waugh <twaugh@redhat.com>          ##
+## Copyright (C) 2001  Simon Huggins                             ##
+## Copyright (C) 2005-2012  Randy Dunlap                         ##
+## Copyright (C) 2012  Dan Luedtke                               ##
+##                                                              ##
+## #define enhancements by Armin Kuster <akuster@mvista.com>    ##
+## Copyright (c) 2000 MontaVista Software, Inc.                         ##
+##                                                              ##
+## This software falls under the GNU General Public License.     ##
+## Please read the COPYING file for more information             ##
+
+# 18/01/2001 -         Cleanups
+#              Functions prototyped as foo(void) same as foo()
+#              Stop eval'ing where we don't need to.
+# -- huggie@earth.li
+
+# 27/06/2001 -  Allowed whitespace after initial "/**" and
+#               allowed comments before function declarations.
+# -- Christian Kreibich <ck@whoop.org>
+
+# Still to do:
+#      - add perldoc documentation
+#      - Look more closely at some of the scarier bits :)
+
+# 26/05/2001 -         Support for separate source and object trees.
+#              Return error code.
+#              Keith Owens <kaos@ocs.com.au>
+
+# 23/09/2001 - Added support for typedefs, structs, enums and unions
+#              Support for Context section; can be terminated using empty line
+#              Small fixes (like spaces vs. \s in regex)
+# -- Tim Jansen <tim@tjansen.de>
+
+# 25/07/2012 - Added support for HTML5
+# -- Dan Luedtke <mail@danrl.de>
+
+sub usage {
+    my $message = <<"EOF";
+Usage: $0 [OPTION ...] FILE ...
+
+Read C language source or header FILEs, extract embedded documentation comments,
+and print formatted documentation to standard output.
+
+The documentation comments are identified by "/**" opening comment mark. See
+Documentation/kernel-doc-nano-HOWTO.txt for the documentation comment syntax.
+
+Output format selection (mutually exclusive):
+  -docbook             Output DocBook format.
+  -html                        Output HTML format.
+  -html5               Output HTML5 format.
+  -list                        Output symbol list format. This is for use by docproc.
+  -man                 Output troff manual page format. This is the default.
+  -rst                 Output reStructuredText format.
+  -text                        Output plain text format.
+
+Output selection (mutually exclusive):
+  -export              Only output documentation for symbols that have been
+                       exported using EXPORT_SYMBOL() or EXPORT_SYMBOL_GPL()
+                        in any input FILE or -export-file FILE.
+  -internal            Only output documentation for symbols that have NOT been
+                       exported using EXPORT_SYMBOL() or EXPORT_SYMBOL_GPL()
+                        in any input FILE or -export-file FILE.
+  -function NAME       Only output documentation for the given function(s)
+                       or DOC: section title(s). All other functions and DOC:
+                       sections are ignored. May be specified multiple times.
+  -nofunction NAME     Do NOT output documentation for the given function(s);
+                       only output documentation for the other functions and
+                       DOC: sections. May be specified multiple times.
+
+Output selection modifiers:
+  -no-doc-sections     Do not output DOC: sections.
+  -enable-lineno        Enable output of #define LINENO lines. Only works with
+                        reStructuredText format.
+  -export-file FILE     Specify an additional FILE in which to look for
+                        EXPORT_SYMBOL() and EXPORT_SYMBOL_GPL(). To be used with
+                        -export or -internal. May be specified multiple times.
+
+Other parameters:
+  -v                   Verbose output, more warnings and other information.
+  -h                   Print this help.
+
+EOF
+    print $message;
+    exit 1;
+}
+
+#
+# format of comments.
+# In the following table, (...)? signifies optional structure.
+#                         (...)* signifies 0 or more structure elements
+# /**
+#  * function_name(:)? (- short description)?
+# (* @parameterx: (description of parameter x)?)*
+# (* a blank line)?
+#  * (Description:)? (Description of function)?
+#  * (section header: (section description)? )*
+#  (*)?*/
+#
+# So .. the trivial example would be:
+#
+# /**
+#  * my_function
+#  */
+#
+# If the Description: header tag is omitted, then there must be a blank line
+# after the last parameter specification.
+# e.g.
+# /**
+#  * my_function - does my stuff
+#  * @my_arg: its mine damnit
+#  *
+#  * Does my stuff explained.
+#  */
+#
+#  or, could also use:
+# /**
+#  * my_function - does my stuff
+#  * @my_arg: its mine damnit
+#  * Description: Does my stuff explained.
+#  */
+# etc.
+#
+# Besides functions you can also write documentation for structs, unions,
+# enums and typedefs. Instead of the function name you must write the name
+# of the declaration;  the struct/union/enum/typedef must always precede
+# the name. Nesting of declarations is not supported.
+# Use the argument mechanism to document members or constants.
+# e.g.
+# /**
+#  * struct my_struct - short description
+#  * @a: first member
+#  * @b: second member
+#  *
+#  * Longer description
+#  */
+# struct my_struct {
+#     int a;
+#     int b;
+# /* private: */
+#     int c;
+# };
+#
+# All descriptions can be multiline, except the short function description.
+#
+# For really longs structs, you can also describe arguments inside the
+# body of the struct.
+# eg.
+# /**
+#  * struct my_struct - short description
+#  * @a: first member
+#  * @b: second member
+#  *
+#  * Longer description
+#  */
+# struct my_struct {
+#     int a;
+#     int b;
+#     /**
+#      * @c: This is longer description of C
+#      *
+#      * You can use paragraphs to describe arguments
+#      * using this method.
+#      */
+#     int c;
+# };
+#
+# This should be use only for struct/enum members.
+#
+# You can also add additional sections. When documenting kernel functions you
+# should document the "Context:" of the function, e.g. whether the functions
+# can be called form interrupts. Unlike other sections you can end it with an
+# empty line.
+# A non-void function should have a "Return:" section describing the return
+# value(s).
+# Example-sections should contain the string EXAMPLE so that they are marked
+# appropriately in DocBook.
+#
+# Example:
+# /**
+#  * user_function - function that can only be called in user context
+#  * @a: some argument
+#  * Context: !in_interrupt()
+#  *
+#  * Some description
+#  * Example:
+#  *    user_function(22);
+#  */
+# ...
+#
+#
+# All descriptive text is further processed, scanning for the following special
+# patterns, which are highlighted appropriately.
+#
+# 'funcname()' - function
+# '$ENVVAR' - environmental variable
+# '&struct_name' - name of a structure (up to two words including 'struct')
+# '&struct_name.member' - name of a structure member
+# '@parameter' - name of a parameter
+# '%CONST' - name of a constant.
+# '``LITERAL``' - literal string without any spaces on it.
+
+## init lots of data
+
+my $errors = 0;
+my $warnings = 0;
+my $anon_struct_union = 0;
+
+# match expressions used to find embedded type information
+my $type_constant = '\b``([^\`]+)``\b';
+my $type_constant2 = '\%([-_\w]+)';
+my $type_func = '(\w+)\(\)';
+my $type_param = '\@(\w+(\.\.\.)?)';
+my $type_fp_param = '\@(\w+)\(\)';  # Special RST handling for func ptr params
+my $type_env = '(\$\w+)';
+my $type_enum = '\&(enum\s*([_\w]+))';
+my $type_struct = '\&(struct\s*([_\w]+))';
+my $type_typedef = '\&(typedef\s*([_\w]+))';
+my $type_union = '\&(union\s*([_\w]+))';
+my $type_member = '\&([_\w]+)(\.|->)([_\w]+)';
+my $type_fallback = '\&([_\w]+)';
+my $type_enum_xml = '\&amp;(enum\s*([_\w]+))';
+my $type_struct_xml = '\&amp;(struct\s*([_\w]+))';
+my $type_typedef_xml = '\&amp;(typedef\s*([_\w]+))';
+my $type_union_xml = '\&amp;(union\s*([_\w]+))';
+my $type_member_xml = '\&amp;([_\w]+)(\.|-\&gt;)([_\w]+)';
+my $type_fallback_xml = '\&amp([_\w]+)';
+my $type_member_func = $type_member . '\(\)';
+
+# Output conversion substitutions.
+#  One for each output format
+
+# these work fairly well
+my @highlights_html = (
+                       [$type_constant, "<i>\$1</i>"],
+                       [$type_constant2, "<i>\$1</i>"],
+                       [$type_func, "<b>\$1</b>"],
+                       [$type_enum_xml, "<i>\$1</i>"],
+                       [$type_struct_xml, "<i>\$1</i>"],
+                       [$type_typedef_xml, "<i>\$1</i>"],
+                       [$type_union_xml, "<i>\$1</i>"],
+                       [$type_env, "<b><i>\$1</i></b>"],
+                       [$type_param, "<tt><b>\$1</b></tt>"],
+                       [$type_member_xml, "<tt><i>\$1</i>\$2\$3</tt>"],
+                       [$type_fallback_xml, "<i>\$1</i>"]
+                      );
+my $local_lt = "\\\\\\\\lt:";
+my $local_gt = "\\\\\\\\gt:";
+my $blankline_html = $local_lt . "p" . $local_gt;      # was "<p>"
+
+# html version 5
+my @highlights_html5 = (
+                        [$type_constant, "<span class=\"const\">\$1</span>"],
+                        [$type_constant2, "<span class=\"const\">\$1</span>"],
+                        [$type_func, "<span class=\"func\">\$1</span>"],
+                        [$type_enum_xml, "<span class=\"enum\">\$1</span>"],
+                        [$type_struct_xml, "<span class=\"struct\">\$1</span>"],
+                        [$type_typedef_xml, "<span class=\"typedef\">\$1</span>"],
+                        [$type_union_xml, "<span class=\"union\">\$1</span>"],
+                        [$type_env, "<span class=\"env\">\$1</span>"],
+                        [$type_param, "<span class=\"param\">\$1</span>]"],
+                        [$type_member_xml, "<span class=\"literal\"><span class=\"struct\">\$1</span>\$2<span class=\"member\">\$3</span></span>"],
+                        [$type_fallback_xml, "<span class=\"struct\">\$1</span>"]
+                      );
+my $blankline_html5 = $local_lt . "br /" . $local_gt;
+
+# XML, docbook format
+my @highlights_xml = (
+                      ["([^=])\\\"([^\\\"<]+)\\\"", "\$1<quote>\$2</quote>"],
+                      [$type_constant, "<constant>\$1</constant>"],
+                      [$type_constant2, "<constant>\$1</constant>"],
+                      [$type_enum_xml, "<type>\$1</type>"],
+                      [$type_struct_xml, "<structname>\$1</structname>"],
+                      [$type_typedef_xml, "<type>\$1</type>"],
+                      [$type_union_xml, "<structname>\$1</structname>"],
+                      [$type_param, "<parameter>\$1</parameter>"],
+                      [$type_func, "<function>\$1</function>"],
+                      [$type_env, "<envar>\$1</envar>"],
+                      [$type_member_xml, "<literal><structname>\$1</structname>\$2<structfield>\$3</structfield></literal>"],
+                      [$type_fallback_xml, "<structname>\$1</structname>"]
+                    );
+my $blankline_xml = $local_lt . "/para" . $local_gt . $local_lt . "para" . $local_gt . "\n";
+
+# gnome, docbook format
+my @highlights_gnome = (
+                        [$type_constant, "<replaceable class=\"option\">\$1</replaceable>"],
+                        [$type_constant2, "<replaceable class=\"option\">\$1</replaceable>"],
+                        [$type_func, "<function>\$1</function>"],
+                        [$type_enum, "<type>\$1</type>"],
+                        [$type_struct, "<structname>\$1</structname>"],
+                        [$type_typedef, "<type>\$1</type>"],
+                        [$type_union, "<structname>\$1</structname>"],
+                        [$type_env, "<envar>\$1</envar>"],
+                        [$type_param, "<parameter>\$1</parameter>" ],
+                        [$type_member, "<literal><structname>\$1</structname>\$2<structfield>\$3</structfield></literal>"],
+                        [$type_fallback, "<structname>\$1</structname>"]
+                      );
+my $blankline_gnome = "</para><para>\n";
+
+# these are pretty rough
+my @highlights_man = (
+                      [$type_constant, "\$1"],
+                      [$type_constant2, "\$1"],
+                      [$type_func, "\\\\fB\$1\\\\fP"],
+                      [$type_enum, "\\\\fI\$1\\\\fP"],
+                      [$type_struct, "\\\\fI\$1\\\\fP"],
+                      [$type_typedef, "\\\\fI\$1\\\\fP"],
+                      [$type_union, "\\\\fI\$1\\\\fP"],
+                      [$type_param, "\\\\fI\$1\\\\fP"],
+                      [$type_member, "\\\\fI\$1\$2\$3\\\\fP"],
+                      [$type_fallback, "\\\\fI\$1\\\\fP"]
+                    );
+my $blankline_man = "";
+
+# text-mode
+my @highlights_text = (
+                       [$type_constant, "\$1"],
+                       [$type_constant2, "\$1"],
+                       [$type_func, "\$1"],
+                       [$type_enum, "\$1"],
+                       [$type_struct, "\$1"],
+                       [$type_typedef, "\$1"],
+                       [$type_union, "\$1"],
+                       [$type_param, "\$1"],
+                       [$type_member, "\$1\$2\$3"],
+                       [$type_fallback, "\$1"]
+                     );
+my $blankline_text = "";
+
+# rst-mode
+my @highlights_rst = (
+                       [$type_constant, "``\$1``"],
+                       [$type_constant2, "``\$1``"],
+                       # Note: need to escape () to avoid func matching later
+                       [$type_member_func, "\\:c\\:type\\:`\$1\$2\$3\\\\(\\\\) <\$1>`"],
+                       [$type_member, "\\:c\\:type\\:`\$1\$2\$3 <\$1>`"],
+                      [$type_fp_param, "**\$1\\\\(\\\\)**"],
+                       [$type_func, "\\:c\\:func\\:`\$1()`"],
+                       [$type_enum, "\\:c\\:type\\:`\$1 <\$2>`"],
+                       [$type_struct, "\\:c\\:type\\:`\$1 <\$2>`"],
+                       [$type_typedef, "\\:c\\:type\\:`\$1 <\$2>`"],
+                       [$type_union, "\\:c\\:type\\:`\$1 <\$2>`"],
+                       # in rst this can refer to any type
+                       [$type_fallback, "\\:c\\:type\\:`\$1`"],
+                       [$type_param, "**\$1**"]
+                     );
+my $blankline_rst = "\n";
+
+# list mode
+my @highlights_list = (
+                       [$type_constant, "\$1"],
+                       [$type_constant2, "\$1"],
+                       [$type_func, "\$1"],
+                       [$type_enum, "\$1"],
+                       [$type_struct, "\$1"],
+                       [$type_typedef, "\$1"],
+                       [$type_union, "\$1"],
+                       [$type_param, "\$1"],
+                       [$type_member, "\$1"],
+                       [$type_fallback, "\$1"]
+                     );
+my $blankline_list = "";
+
+# read arguments
+if ($#ARGV == -1) {
+    usage();
+}
+
+my $kernelversion;
+my $dohighlight = "";
+
+my $verbose = 0;
+my $output_mode = "man";
+my $output_preformatted = 0;
+my $no_doc_sections = 0;
+my $enable_lineno = 0;
+my @highlights = @highlights_man;
+my $blankline = $blankline_man;
+my $modulename = "Kernel API";
+
+use constant {
+    OUTPUT_ALL          => 0, # output all symbols and doc sections
+    OUTPUT_INCLUDE      => 1, # output only specified symbols
+    OUTPUT_EXCLUDE      => 2, # output everything except specified symbols
+    OUTPUT_EXPORTED     => 3, # output exported symbols
+    OUTPUT_INTERNAL     => 4, # output non-exported symbols
+};
+my $output_selection = OUTPUT_ALL;
+my $show_not_found = 0;
+
+my @export_file_list;
+
+my @build_time;
+if (defined($ENV{'KBUILD_BUILD_TIMESTAMP'}) &&
+    (my $seconds = `date -d"${ENV{'KBUILD_BUILD_TIMESTAMP'}}" +%s`) ne '') {
+    @build_time = gmtime($seconds);
+} else {
+    @build_time = localtime;
+}
+
+my $man_date = ('January', 'February', 'March', 'April', 'May', 'June',
+               'July', 'August', 'September', 'October',
+               'November', 'December')[$build_time[4]] .
+  " " . ($build_time[5]+1900);
+
+# Essentially these are globals.
+# They probably want to be tidied up, made more localised or something.
+# CAVEAT EMPTOR!  Some of the others I localised may not want to be, which
+# could cause "use of undefined value" or other bugs.
+my ($function, %function_table, %parametertypes, $declaration_purpose);
+my $declaration_start_line;
+my ($type, $declaration_name, $return_type);
+my ($newsection, $newcontents, $prototype, $brcount, %source_map);
+
+if (defined($ENV{'KBUILD_VERBOSE'})) {
+       $verbose = "$ENV{'KBUILD_VERBOSE'}";
+}
+
+# Generated docbook code is inserted in a template at a point where
+# docbook v3.1 requires a non-zero sequence of RefEntry's; see:
+# http://www.oasis-open.org/docbook/documentation/reference/html/refentry.html
+# We keep track of number of generated entries and generate a dummy
+# if needs be to ensure the expanded template can be postprocessed
+# into html.
+my $section_counter = 0;
+
+my $lineprefix="";
+
+# Parser states
+use constant {
+    STATE_NORMAL        => 0, # normal code
+    STATE_NAME          => 1, # looking for function name
+    STATE_FIELD         => 2, # scanning field start
+    STATE_PROTO         => 3, # scanning prototype
+    STATE_DOCBLOCK      => 4, # documentation block
+    STATE_INLINE        => 5, # gathering documentation outside main block
+};
+my $state;
+my $in_doc_sect;
+
+# Inline documentation state
+use constant {
+    STATE_INLINE_NA     => 0, # not applicable ($state != STATE_INLINE)
+    STATE_INLINE_NAME   => 1, # looking for member name (@foo:)
+    STATE_INLINE_TEXT   => 2, # looking for member documentation
+    STATE_INLINE_END    => 3, # done
+    STATE_INLINE_ERROR  => 4, # error - Comment without header was found.
+                              # Spit a warning as it's not
+                              # proper kernel-doc and ignore the rest.
+};
+my $inline_doc_state;
+
+#declaration types: can be
+# 'function', 'struct', 'union', 'enum', 'typedef'
+my $decl_type;
+
+my $doc_start = '^/\*\*\s*$'; # Allow whitespace at end of comment start.
+my $doc_end = '\*/';
+my $doc_com = '\s*\*\s*';
+my $doc_com_body = '\s*\* ?';
+my $doc_decl = $doc_com . '(\w+)';
+# @params and a strictly limited set of supported section names
+my $doc_sect = $doc_com . 
+    '\s*(\@[.\w]+|\@\.\.\.|description|context|returns?|notes?|examples?)\s*:(.*)';
+my $doc_content = $doc_com_body . '(.*)';
+my $doc_block = $doc_com . 'DOC:\s*(.*)?';
+my $doc_inline_start = '^\s*/\*\*\s*$';
+my $doc_inline_sect = '\s*\*\s*(@[\w\s]+):(.*)';
+my $doc_inline_end = '^\s*\*/\s*$';
+my $doc_inline_oneline = '^\s*/\*\*\s*(@[\w\s]+):\s*(.*)\s*\*/\s*$';
+my $export_symbol = '^\s*EXPORT_SYMBOL(_GPL)?\s*\(\s*(\w+)\s*\)\s*;';
+
+my %parameterdescs;
+my %parameterdesc_start_lines;
+my @parameterlist;
+my %sections;
+my @sectionlist;
+my %section_start_lines;
+my $sectcheck;
+my $struct_actual;
+
+my $contents = "";
+my $new_start_line = 0;
+
+# the canonical section names. see also $doc_sect above.
+my $section_default = "Description";   # default section
+my $section_intro = "Introduction";
+my $section = $section_default;
+my $section_context = "Context";
+my $section_return = "Return";
+
+my $undescribed = "-- undescribed --";
+
+reset_state();
+
+while ($ARGV[0] =~ m/^-(.*)/) {
+    my $cmd = shift @ARGV;
+    if ($cmd eq "-html") {
+       $output_mode = "html";
+       @highlights = @highlights_html;
+       $blankline = $blankline_html;
+    } elsif ($cmd eq "-html5") {
+       $output_mode = "html5";
+       @highlights = @highlights_html5;
+       $blankline = $blankline_html5;
+    } elsif ($cmd eq "-man") {
+       $output_mode = "man";
+       @highlights = @highlights_man;
+       $blankline = $blankline_man;
+    } elsif ($cmd eq "-text") {
+       $output_mode = "text";
+       @highlights = @highlights_text;
+       $blankline = $blankline_text;
+    } elsif ($cmd eq "-rst") {
+       $output_mode = "rst";
+       @highlights = @highlights_rst;
+       $blankline = $blankline_rst;
+    } elsif ($cmd eq "-docbook") {
+       $output_mode = "xml";
+       @highlights = @highlights_xml;
+       $blankline = $blankline_xml;
+    } elsif ($cmd eq "-list") {
+       $output_mode = "list";
+       @highlights = @highlights_list;
+       $blankline = $blankline_list;
+    } elsif ($cmd eq "-gnome") {
+       $output_mode = "gnome";
+       @highlights = @highlights_gnome;
+       $blankline = $blankline_gnome;
+    } elsif ($cmd eq "-module") { # not needed for XML, inherits from calling document
+       $modulename = shift @ARGV;
+    } elsif ($cmd eq "-function") { # to only output specific functions
+       $output_selection = OUTPUT_INCLUDE;
+       $function = shift @ARGV;
+       $function_table{$function} = 1;
+    } elsif ($cmd eq "-nofunction") { # output all except specific functions
+       $output_selection = OUTPUT_EXCLUDE;
+       $function = shift @ARGV;
+       $function_table{$function} = 1;
+    } elsif ($cmd eq "-export") { # only exported symbols
+       $output_selection = OUTPUT_EXPORTED;
+       %function_table = ();
+    } elsif ($cmd eq "-internal") { # only non-exported symbols
+       $output_selection = OUTPUT_INTERNAL;
+       %function_table = ();
+    } elsif ($cmd eq "-export-file") {
+       my $file = shift @ARGV;
+       push(@export_file_list, $file);
+    } elsif ($cmd eq "-v") {
+       $verbose = 1;
+    } elsif (($cmd eq "-h") || ($cmd eq "--help")) {
+       usage();
+    } elsif ($cmd eq '-no-doc-sections') {
+           $no_doc_sections = 1;
+    } elsif ($cmd eq '-enable-lineno') {
+           $enable_lineno = 1;
+    } elsif ($cmd eq '-show-not-found') {
+       $show_not_found = 1;
+    }
+}
+
+# continue execution near EOF;
+
+# get kernel version from env
+sub get_kernel_version() {
+    my $version = 'unknown kernel version';
+
+    if (defined($ENV{'KERNELVERSION'})) {
+       $version = $ENV{'KERNELVERSION'};
+    }
+    return $version;
+}
+
+#
+sub print_lineno {
+    my $lineno = shift;
+    if ($enable_lineno && defined($lineno)) {
+        print "#define LINENO " . $lineno . "\n";
+    }
+}
+##
+# dumps section contents to arrays/hashes intended for that purpose.
+#
+sub dump_section {
+    my $file = shift;
+    my $name = shift;
+    my $contents = join "\n", @_;
+
+    if ($name =~ m/$type_param/) {
+       $name = $1;
+       $parameterdescs{$name} = $contents;
+       $sectcheck = $sectcheck . $name . " ";
+        $parameterdesc_start_lines{$name} = $new_start_line;
+        $new_start_line = 0;
+    } elsif ($name eq "@\.\.\.") {
+       $name = "...";
+       $parameterdescs{$name} = $contents;
+       $sectcheck = $sectcheck . $name . " ";
+        $parameterdesc_start_lines{$name} = $new_start_line;
+        $new_start_line = 0;
+    } else {
+       if (defined($sections{$name}) && ($sections{$name} ne "")) {
+           # Only warn on user specified duplicate section names.
+           if ($name ne $section_default) {
+               print STDERR "${file}:$.: warning: duplicate section name '$name'\n";
+               ++$warnings;
+           }
+           $sections{$name} .= $contents;
+       } else {
+           $sections{$name} = $contents;
+           push @sectionlist, $name;
+            $section_start_lines{$name} = $new_start_line;
+            $new_start_line = 0;
+       }
+    }
+}
+
+##
+# dump DOC: section after checking that it should go out
+#
+sub dump_doc_section {
+    my $file = shift;
+    my $name = shift;
+    my $contents = join "\n", @_;
+
+    if ($no_doc_sections) {
+        return;
+    }
+
+    if (($output_selection == OUTPUT_ALL) ||
+       ($output_selection == OUTPUT_INCLUDE &&
+        defined($function_table{$name})) ||
+       ($output_selection == OUTPUT_EXCLUDE &&
+        !defined($function_table{$name})))
+    {
+       dump_section($file, $name, $contents);
+       output_blockhead({'sectionlist' => \@sectionlist,
+                         'sections' => \%sections,
+                         'module' => $modulename,
+                         'content-only' => ($output_selection != OUTPUT_ALL), });
+    }
+}
+
+##
+# output function
+#
+# parameterdescs, a hash.
+#  function => "function name"
+#  parameterlist => @list of parameters
+#  parameterdescs => %parameter descriptions
+#  sectionlist => @list of sections
+#  sections => %section descriptions
+#
+
+sub output_highlight {
+    my $contents = join "\n",@_;
+    my $line;
+
+#   DEBUG
+#   if (!defined $contents) {
+#      use Carp;
+#      confess "output_highlight got called with no args?\n";
+#   }
+
+    if ($output_mode eq "html" || $output_mode eq "html5" ||
+       $output_mode eq "xml") {
+       $contents = local_unescape($contents);
+       # convert data read & converted thru xml_escape() into &xyz; format:
+       $contents =~ s/\\\\\\/\&/g;
+    }
+#   print STDERR "contents b4:$contents\n";
+    eval $dohighlight;
+    die $@ if $@;
+#   print STDERR "contents af:$contents\n";
+
+#   strip whitespaces when generating html5
+    if ($output_mode eq "html5") {
+       $contents =~ s/^\s+//;
+       $contents =~ s/\s+$//;
+    }
+    foreach $line (split "\n", $contents) {
+       if (! $output_preformatted) {
+           $line =~ s/^\s*//;
+       }
+       if ($line eq ""){
+           if (! $output_preformatted) {
+               print $lineprefix, local_unescape($blankline);
+           }
+       } else {
+           $line =~ s/\\\\\\/\&/g;
+           if ($output_mode eq "man" && substr($line, 0, 1) eq ".") {
+               print "\\&$line";
+           } else {
+               print $lineprefix, $line;
+           }
+       }
+       print "\n";
+    }
+}
+
+# output sections in html
+sub output_section_html(%) {
+    my %args = %{$_[0]};
+    my $section;
+
+    foreach $section (@{$args{'sectionlist'}}) {
+       print "<h3>$section</h3>\n";
+       print "<blockquote>\n";
+       output_highlight($args{'sections'}{$section});
+       print "</blockquote>\n";
+    }
+}
+
+# output enum in html
+sub output_enum_html(%) {
+    my %args = %{$_[0]};
+    my ($parameter);
+    my $count;
+    print "<h2>enum " . $args{'enum'} . "</h2>\n";
+
+    print "<b>enum " . $args{'enum'} . "</b> {<br>\n";
+    $count = 0;
+    foreach $parameter (@{$args{'parameterlist'}}) {
+       print " <b>" . $parameter . "</b>";
+       if ($count != $#{$args{'parameterlist'}}) {
+           $count++;
+           print ",\n";
+       }
+       print "<br>";
+    }
+    print "};<br>\n";
+
+    print "<h3>Constants</h3>\n";
+    print "<dl>\n";
+    foreach $parameter (@{$args{'parameterlist'}}) {
+       print "<dt><b>" . $parameter . "</b>\n";
+       print "<dd>";
+       output_highlight($args{'parameterdescs'}{$parameter});
+    }
+    print "</dl>\n";
+    output_section_html(@_);
+    print "<hr>\n";
+}
+
+# output typedef in html
+sub output_typedef_html(%) {
+    my %args = %{$_[0]};
+    my ($parameter);
+    my $count;
+    print "<h2>typedef " . $args{'typedef'} . "</h2>\n";
+
+    print "<b>typedef " . $args{'typedef'} . "</b>\n";
+    output_section_html(@_);
+    print "<hr>\n";
+}
+
+# output struct in html
+sub output_struct_html(%) {
+    my %args = %{$_[0]};
+    my ($parameter);
+
+    print "<h2>" . $args{'type'} . " " . $args{'struct'} . " - " . $args{'purpose'} . "</h2>\n";
+    print "<b>" . $args{'type'} . " " . $args{'struct'} . "</b> {<br>\n";
+    foreach $parameter (@{$args{'parameterlist'}}) {
+       if ($parameter =~ /^#/) {
+               print "$parameter<br>\n";
+               next;
+       }
+       my $parameter_name = $parameter;
+       $parameter_name =~ s/\[.*//;
+
+       ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
+       $type = $args{'parametertypes'}{$parameter};
+       if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
+           # pointer-to-function
+           print "&nbsp; &nbsp; <i>$1</i><b>$parameter</b>) <i>($2)</i>;<br>\n";
+       } elsif ($type =~ m/^(.*?)\s*(:.*)/) {
+           # bitfield
+           print "&nbsp; &nbsp; <i>$1</i> <b>$parameter</b>$2;<br>\n";
+       } else {
+           print "&nbsp; &nbsp; <i>$type</i> <b>$parameter</b>;<br>\n";
+       }
+    }
+    print "};<br>\n";
+
+    print "<h3>Members</h3>\n";
+    print "<dl>\n";
+    foreach $parameter (@{$args{'parameterlist'}}) {
+       ($parameter =~ /^#/) && next;
+
+       my $parameter_name = $parameter;
+       $parameter_name =~ s/\[.*//;
+
+       ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
+       print "<dt><b>" . $parameter . "</b>\n";
+       print "<dd>";
+       output_highlight($args{'parameterdescs'}{$parameter_name});
+    }
+    print "</dl>\n";
+    output_section_html(@_);
+    print "<hr>\n";
+}
+
+# output function in html
+sub output_function_html(%) {
+    my %args = %{$_[0]};
+    my ($parameter, $section);
+    my $count;
+
+    print "<h2>" . $args{'function'} . " - " . $args{'purpose'} . "</h2>\n";
+    print "<i>" . $args{'functiontype'} . "</i>\n";
+    print "<b>" . $args{'function'} . "</b>\n";
+    print "(";
+    $count = 0;
+    foreach $parameter (@{$args{'parameterlist'}}) {
+       $type = $args{'parametertypes'}{$parameter};
+       if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
+           # pointer-to-function
+           print "<i>$1</i><b>$parameter</b>) <i>($2)</i>";
+       } else {
+           print "<i>" . $type . "</i> <b>" . $parameter . "</b>";
+       }
+       if ($count != $#{$args{'parameterlist'}}) {
+           $count++;
+           print ",\n";
+       }
+    }
+    print ")\n";
+
+    print "<h3>Arguments</h3>\n";
+    print "<dl>\n";
+    foreach $parameter (@{$args{'parameterlist'}}) {
+       my $parameter_name = $parameter;
+       $parameter_name =~ s/\[.*//;
+
+       ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
+       print "<dt><b>" . $parameter . "</b>\n";
+       print "<dd>";
+       output_highlight($args{'parameterdescs'}{$parameter_name});
+    }
+    print "</dl>\n";
+    output_section_html(@_);
+    print "<hr>\n";
+}
+
+# output DOC: block header in html
+sub output_blockhead_html(%) {
+    my %args = %{$_[0]};
+    my ($parameter, $section);
+    my $count;
+
+    foreach $section (@{$args{'sectionlist'}}) {
+       print "<h3>$section</h3>\n";
+       print "<ul>\n";
+       output_highlight($args{'sections'}{$section});
+       print "</ul>\n";
+    }
+    print "<hr>\n";
+}
+
+# output sections in html5
+sub output_section_html5(%) {
+    my %args = %{$_[0]};
+    my $section;
+
+    foreach $section (@{$args{'sectionlist'}}) {
+       print "<section>\n";
+       print "<h1>$section</h1>\n";
+       print "<p>\n";
+       output_highlight($args{'sections'}{$section});
+       print "</p>\n";
+       print "</section>\n";
+    }
+}
+
+# output enum in html5
+sub output_enum_html5(%) {
+    my %args = %{$_[0]};
+    my ($parameter);
+    my $count;
+    my $html5id;
+
+    $html5id = $args{'enum'};
+    $html5id =~ s/[^a-zA-Z0-9\-]+/_/g;
+    print "<article class=\"enum\" id=\"enum:". $html5id . "\">";
+    print "<h1>enum " . $args{'enum'} . "</h1>\n";
+    print "<ol class=\"code\">\n";
+    print "<li>";
+    print "<span class=\"keyword\">enum</span> ";
+    print "<span class=\"identifier\">" . $args{'enum'} . "</span> {";
+    print "</li>\n";
+    $count = 0;
+    foreach $parameter (@{$args{'parameterlist'}}) {
+       print "<li class=\"indent\">";
+       print "<span class=\"param\">" . $parameter . "</span>";
+       if ($count != $#{$args{'parameterlist'}}) {
+           $count++;
+           print ",";
+       }
+       print "</li>\n";
+    }
+    print "<li>};</li>\n";
+    print "</ol>\n";
+
+    print "<section>\n";
+    print "<h1>Constants</h1>\n";
+    print "<dl>\n";
+    foreach $parameter (@{$args{'parameterlist'}}) {
+       print "<dt>" . $parameter . "</dt>\n";
+       print "<dd>";
+       output_highlight($args{'parameterdescs'}{$parameter});
+       print "</dd>\n";
+    }
+    print "</dl>\n";
+    print "</section>\n";
+    output_section_html5(@_);
+    print "</article>\n";
+}
+
+# output typedef in html5
+sub output_typedef_html5(%) {
+    my %args = %{$_[0]};
+    my ($parameter);
+    my $count;
+    my $html5id;
+
+    $html5id = $args{'typedef'};
+    $html5id =~ s/[^a-zA-Z0-9\-]+/_/g;
+    print "<article class=\"typedef\" id=\"typedef:" . $html5id . "\">\n";
+    print "<h1>typedef " . $args{'typedef'} . "</h1>\n";
+
+    print "<ol class=\"code\">\n";
+    print "<li>";
+    print "<span class=\"keyword\">typedef</span> ";
+    print "<span class=\"identifier\">" . $args{'typedef'} . "</span>";
+    print "</li>\n";
+    print "</ol>\n";
+    output_section_html5(@_);
+    print "</article>\n";
+}
+
+# output struct in html5
+sub output_struct_html5(%) {
+    my %args = %{$_[0]};
+    my ($parameter);
+    my $html5id;
+
+    $html5id = $args{'struct'};
+    $html5id =~ s/[^a-zA-Z0-9\-]+/_/g;
+    print "<article class=\"struct\" id=\"struct:" . $html5id . "\">\n";
+    print "<hgroup>\n";
+    print "<h1>" . $args{'type'} . " " . $args{'struct'} . "</h1>";
+    print "<h2>". $args{'purpose'} . "</h2>\n";
+    print "</hgroup>\n";
+    print "<ol class=\"code\">\n";
+    print "<li>";
+    print "<span class=\"type\">" . $args{'type'} . "</span> ";
+    print "<span class=\"identifier\">" . $args{'struct'} . "</span> {";
+    print "</li>\n";
+    foreach $parameter (@{$args{'parameterlist'}}) {
+       print "<li class=\"indent\">";
+       if ($parameter =~ /^#/) {
+               print "<span class=\"param\">" . $parameter ."</span>\n";
+               print "</li>\n";
+               next;
+       }
+       my $parameter_name = $parameter;
+       $parameter_name =~ s/\[.*//;
+
+       ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
+       $type = $args{'parametertypes'}{$parameter};
+       if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
+           # pointer-to-function
+           print "<span class=\"type\">$1</span> ";
+           print "<span class=\"param\">$parameter</span>";
+           print "<span class=\"type\">)</span> ";
+           print "(<span class=\"args\">$2</span>);";
+       } elsif ($type =~ m/^(.*?)\s*(:.*)/) {
+           # bitfield
+           print "<span class=\"type\">$1</span> ";
+           print "<span class=\"param\">$parameter</span>";
+           print "<span class=\"bits\">$2</span>;";
+       } else {
+           print "<span class=\"type\">$type</span> ";
+           print "<span class=\"param\">$parameter</span>;";
+       }
+       print "</li>\n";
+    }
+    print "<li>};</li>\n";
+    print "</ol>\n";
+
+    print "<section>\n";
+    print "<h1>Members</h1>\n";
+    print "<dl>\n";
+    foreach $parameter (@{$args{'parameterlist'}}) {
+       ($parameter =~ /^#/) && next;
+
+       my $parameter_name = $parameter;
+       $parameter_name =~ s/\[.*//;
+
+       ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
+       print "<dt>" . $parameter . "</dt>\n";
+       print "<dd>";
+       output_highlight($args{'parameterdescs'}{$parameter_name});
+       print "</dd>\n";
+    }
+    print "</dl>\n";
+    print "</section>\n";
+    output_section_html5(@_);
+    print "</article>\n";
+}
+
+# output function in html5
+sub output_function_html5(%) {
+    my %args = %{$_[0]};
+    my ($parameter, $section);
+    my $count;
+    my $html5id;
+
+    $html5id = $args{'function'};
+    $html5id =~ s/[^a-zA-Z0-9\-]+/_/g;
+    print "<article class=\"function\" id=\"func:". $html5id . "\">\n";
+    print "<hgroup>\n";
+    print "<h1>" . $args{'function'} . "</h1>";
+    print "<h2>" . $args{'purpose'} . "</h2>\n";
+    print "</hgroup>\n";
+    print "<ol class=\"code\">\n";
+    print "<li>";
+    print "<span class=\"type\">" . $args{'functiontype'} . "</span> ";
+    print "<span class=\"identifier\">" . $args{'function'} . "</span> (";
+    print "</li>";
+    $count = 0;
+    foreach $parameter (@{$args{'parameterlist'}}) {
+       print "<li class=\"indent\">";
+       $type = $args{'parametertypes'}{$parameter};
+       if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
+           # pointer-to-function
+           print "<span class=\"type\">$1</span> ";
+           print "<span class=\"param\">$parameter</span>";
+           print "<span class=\"type\">)</span> ";
+           print "(<span class=\"args\">$2</span>)";
+       } else {
+           print "<span class=\"type\">$type</span> ";
+           print "<span class=\"param\">$parameter</span>";
+       }
+       if ($count != $#{$args{'parameterlist'}}) {
+           $count++;
+           print ",";
+       }
+       print "</li>\n";
+    }
+    print "<li>)</li>\n";
+    print "</ol>\n";
+
+    print "<section>\n";
+    print "<h1>Arguments</h1>\n";
+    print "<p>\n";
+    print "<dl>\n";
+    foreach $parameter (@{$args{'parameterlist'}}) {
+       my $parameter_name = $parameter;
+       $parameter_name =~ s/\[.*//;
+
+       ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
+       print "<dt>" . $parameter . "</dt>\n";
+       print "<dd>";
+       output_highlight($args{'parameterdescs'}{$parameter_name});
+       print "</dd>\n";
+    }
+    print "</dl>\n";
+    print "</section>\n";
+    output_section_html5(@_);
+    print "</article>\n";
+}
+
+# output DOC: block header in html5
+sub output_blockhead_html5(%) {
+    my %args = %{$_[0]};
+    my ($parameter, $section);
+    my $count;
+    my $html5id;
+
+    foreach $section (@{$args{'sectionlist'}}) {
+       $html5id = $section;
+       $html5id =~ s/[^a-zA-Z0-9\-]+/_/g;
+       print "<article class=\"doc\" id=\"doc:". $html5id . "\">\n";
+       print "<h1>$section</h1>\n";
+       print "<p>\n";
+       output_highlight($args{'sections'}{$section});
+       print "</p>\n";
+    }
+    print "</article>\n";
+}
+
+sub output_section_xml(%) {
+    my %args = %{$_[0]};
+    my $section;
+    # print out each section
+    $lineprefix="   ";
+    foreach $section (@{$args{'sectionlist'}}) {
+       print "<refsect1>\n";
+       print "<title>$section</title>\n";
+       if ($section =~ m/EXAMPLE/i) {
+           print "<informalexample><programlisting>\n";
+           $output_preformatted = 1;
+       } else {
+           print "<para>\n";
+       }
+       output_highlight($args{'sections'}{$section});
+       $output_preformatted = 0;
+       if ($section =~ m/EXAMPLE/i) {
+           print "</programlisting></informalexample>\n";
+       } else {
+           print "</para>\n";
+       }
+       print "</refsect1>\n";
+    }
+}
+
+# output function in XML DocBook
+sub output_function_xml(%) {
+    my %args = %{$_[0]};
+    my ($parameter, $section);
+    my $count;
+    my $id;
+
+    $id = "API-" . $args{'function'};
+    $id =~ s/[^A-Za-z0-9]/-/g;
+
+    print "<refentry id=\"$id\">\n";
+    print "<refentryinfo>\n";
+    print " <title>LINUX</title>\n";
+    print " <productname>API Manual</productname>\n";
+    print " <date>$man_date</date>\n";
+    print "</refentryinfo>\n";
+    print "<refmeta>\n";
+    print " <refentrytitle><phrase>" . $args{'function'} . "</phrase></refentrytitle>\n";
+    print " <manvolnum>3</manvolnum>\n";
+    print " <refmiscinfo class=\"version\">" . $kernelversion . "</refmiscinfo>\n";
+    print "</refmeta>\n";
+    print "<refnamediv>\n";
+    print " <refname>" . $args{'function'} . "</refname>\n";
+    print " <refpurpose>\n";
+    print "  ";
+    output_highlight ($args{'purpose'});
+    print " </refpurpose>\n";
+    print "</refnamediv>\n";
+
+    print "<refsynopsisdiv>\n";
+    print " <title>Synopsis</title>\n";
+    print "  <funcsynopsis><funcprototype>\n";
+    print "   <funcdef>" . $args{'functiontype'} . " ";
+    print "<function>" . $args{'function'} . " </function></funcdef>\n";
+
+    $count = 0;
+    if ($#{$args{'parameterlist'}} >= 0) {
+       foreach $parameter (@{$args{'parameterlist'}}) {
+           $type = $args{'parametertypes'}{$parameter};
+           if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
+               # pointer-to-function
+               print "   <paramdef>$1<parameter>$parameter</parameter>)\n";
+               print "     <funcparams>$2</funcparams></paramdef>\n";
+           } else {
+               print "   <paramdef>" . $type;
+               print " <parameter>$parameter</parameter></paramdef>\n";
+           }
+       }
+    } else {
+       print "  <void/>\n";
+    }
+    print "  </funcprototype></funcsynopsis>\n";
+    print "</refsynopsisdiv>\n";
+
+    # print parameters
+    print "<refsect1>\n <title>Arguments</title>\n";
+    if ($#{$args{'parameterlist'}} >= 0) {
+       print " <variablelist>\n";
+       foreach $parameter (@{$args{'parameterlist'}}) {
+           my $parameter_name = $parameter;
+           $parameter_name =~ s/\[.*//;
+           $type = $args{'parametertypes'}{$parameter};
+
+           print "  <varlistentry>\n   <term><parameter>$type $parameter</parameter></term>\n";
+           print "   <listitem>\n    <para>\n";
+           $lineprefix="     ";
+           output_highlight($args{'parameterdescs'}{$parameter_name});
+           print "    </para>\n   </listitem>\n  </varlistentry>\n";
+       }
+       print " </variablelist>\n";
+    } else {
+       print " <para>\n  None\n </para>\n";
+    }
+    print "</refsect1>\n";
+
+    output_section_xml(@_);
+    print "</refentry>\n\n";
+}
+
+# output struct in XML DocBook
+sub output_struct_xml(%) {
+    my %args = %{$_[0]};
+    my ($parameter, $section);
+    my $id;
+
+    $id = "API-struct-" . $args{'struct'};
+    $id =~ s/[^A-Za-z0-9]/-/g;
+
+    print "<refentry id=\"$id\">\n";
+    print "<refentryinfo>\n";
+    print " <title>LINUX</title>\n";
+    print " <productname>API Manual</productname>\n";
+    print " <date>$man_date</date>\n";
+    print "</refentryinfo>\n";
+    print "<refmeta>\n";
+    print " <refentrytitle><phrase>" . $args{'type'} . " " . $args{'struct'} . "</phrase></refentrytitle>\n";
+    print " <manvolnum>3</manvolnum>\n";
+    print " <refmiscinfo class=\"version\">" . $kernelversion . "</refmiscinfo>\n";
+    print "</refmeta>\n";
+    print "<refnamediv>\n";
+    print " <refname>" . $args{'type'} . " " . $args{'struct'} . "</refname>\n";
+    print " <refpurpose>\n";
+    print "  ";
+    output_highlight ($args{'purpose'});
+    print " </refpurpose>\n";
+    print "</refnamediv>\n";
+
+    print "<refsynopsisdiv>\n";
+    print " <title>Synopsis</title>\n";
+    print "  <programlisting>\n";
+    print $args{'type'} . " " . $args{'struct'} . " {\n";
+    foreach $parameter (@{$args{'parameterlist'}}) {
+       if ($parameter =~ /^#/) {
+           my $prm = $parameter;
+           # convert data read & converted thru xml_escape() into &xyz; format:
+           # This allows us to have #define macros interspersed in a struct.
+           $prm =~ s/\\\\\\/\&/g;
+           print "$prm\n";
+           next;
+       }
+
+       my $parameter_name = $parameter;
+       $parameter_name =~ s/\[.*//;
+
+       defined($args{'parameterdescs'}{$parameter_name}) || next;
+       ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
+       $type = $args{'parametertypes'}{$parameter};
+       if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
+           # pointer-to-function
+           print "  $1 $parameter) ($2);\n";
+       } elsif ($type =~ m/^(.*?)\s*(:.*)/) {
+           # bitfield
+           print "  $1 $parameter$2;\n";
+       } else {
+           print "  " . $type . " " . $parameter . ";\n";
+       }
+    }
+    print "};";
+    print "  </programlisting>\n";
+    print "</refsynopsisdiv>\n";
+
+    print " <refsect1>\n";
+    print "  <title>Members</title>\n";
+
+    if ($#{$args{'parameterlist'}} >= 0) {
+    print "  <variablelist>\n";
+    foreach $parameter (@{$args{'parameterlist'}}) {
+      ($parameter =~ /^#/) && next;
+
+      my $parameter_name = $parameter;
+      $parameter_name =~ s/\[.*//;
+
+      defined($args{'parameterdescs'}{$parameter_name}) || next;
+      ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
+      $type = $args{'parametertypes'}{$parameter};
+      print "    <varlistentry>";
+      print "      <term><literal>$type $parameter</literal></term>\n";
+      print "      <listitem><para>\n";
+      output_highlight($args{'parameterdescs'}{$parameter_name});
+      print "      </para></listitem>\n";
+      print "    </varlistentry>\n";
+    }
+    print "  </variablelist>\n";
+    } else {
+       print " <para>\n  None\n </para>\n";
+    }
+    print " </refsect1>\n";
+
+    output_section_xml(@_);
+
+    print "</refentry>\n\n";
+}
+
+# output enum in XML DocBook
+sub output_enum_xml(%) {
+    my %args = %{$_[0]};
+    my ($parameter, $section);
+    my $count;
+    my $id;
+
+    $id = "API-enum-" . $args{'enum'};
+    $id =~ s/[^A-Za-z0-9]/-/g;
+
+    print "<refentry id=\"$id\">\n";
+    print "<refentryinfo>\n";
+    print " <title>LINUX</title>\n";
+    print " <productname>API Manual</productname>\n";
+    print " <date>$man_date</date>\n";
+    print "</refentryinfo>\n";
+    print "<refmeta>\n";
+    print " <refentrytitle><phrase>enum " . $args{'enum'} . "</phrase></refentrytitle>\n";
+    print " <manvolnum>3</manvolnum>\n";
+    print " <refmiscinfo class=\"version\">" . $kernelversion . "</refmiscinfo>\n";
+    print "</refmeta>\n";
+    print "<refnamediv>\n";
+    print " <refname>enum " . $args{'enum'} . "</refname>\n";
+    print " <refpurpose>\n";
+    print "  ";
+    output_highlight ($args{'purpose'});
+    print " </refpurpose>\n";
+    print "</refnamediv>\n";
+
+    print "<refsynopsisdiv>\n";
+    print " <title>Synopsis</title>\n";
+    print "  <programlisting>\n";
+    print "enum " . $args{'enum'} . " {\n";
+    $count = 0;
+    foreach $parameter (@{$args{'parameterlist'}}) {
+       print "  $parameter";
+       if ($count != $#{$args{'parameterlist'}}) {
+           $count++;
+           print ",";
+       }
+       print "\n";
+    }
+    print "};";
+    print "  </programlisting>\n";
+    print "</refsynopsisdiv>\n";
+
+    print "<refsect1>\n";
+    print " <title>Constants</title>\n";
+    print "  <variablelist>\n";
+    foreach $parameter (@{$args{'parameterlist'}}) {
+      my $parameter_name = $parameter;
+      $parameter_name =~ s/\[.*//;
+
+      print "    <varlistentry>";
+      print "      <term>$parameter</term>\n";
+      print "      <listitem><para>\n";
+      output_highlight($args{'parameterdescs'}{$parameter_name});
+      print "      </para></listitem>\n";
+      print "    </varlistentry>\n";
+    }
+    print "  </variablelist>\n";
+    print "</refsect1>\n";
+
+    output_section_xml(@_);
+
+    print "</refentry>\n\n";
+}
+
+# output typedef in XML DocBook
+sub output_typedef_xml(%) {
+    my %args = %{$_[0]};
+    my ($parameter, $section);
+    my $id;
+
+    $id = "API-typedef-" . $args{'typedef'};
+    $id =~ s/[^A-Za-z0-9]/-/g;
+
+    print "<refentry id=\"$id\">\n";
+    print "<refentryinfo>\n";
+    print " <title>LINUX</title>\n";
+    print " <productname>API Manual</productname>\n";
+    print " <date>$man_date</date>\n";
+    print "</refentryinfo>\n";
+    print "<refmeta>\n";
+    print " <refentrytitle><phrase>typedef " . $args{'typedef'} . "</phrase></refentrytitle>\n";
+    print " <manvolnum>3</manvolnum>\n";
+    print "</refmeta>\n";
+    print "<refnamediv>\n";
+    print " <refname>typedef " . $args{'typedef'} . "</refname>\n";
+    print " <refpurpose>\n";
+    print "  ";
+    output_highlight ($args{'purpose'});
+    print " </refpurpose>\n";
+    print "</refnamediv>\n";
+
+    print "<refsynopsisdiv>\n";
+    print " <title>Synopsis</title>\n";
+    print "  <synopsis>typedef " . $args{'typedef'} . ";</synopsis>\n";
+    print "</refsynopsisdiv>\n";
+
+    output_section_xml(@_);
+
+    print "</refentry>\n\n";
+}
+
+# output in XML DocBook
+sub output_blockhead_xml(%) {
+    my %args = %{$_[0]};
+    my ($parameter, $section);
+    my $count;
+
+    my $id = $args{'module'};
+    $id =~ s/[^A-Za-z0-9]/-/g;
+
+    # print out each section
+    $lineprefix="   ";
+    foreach $section (@{$args{'sectionlist'}}) {
+       if (!$args{'content-only'}) {
+               print "<refsect1>\n <title>$section</title>\n";
+       }
+       if ($section =~ m/EXAMPLE/i) {
+           print "<example><para>\n";
+           $output_preformatted = 1;
+       } else {
+           print "<para>\n";
+       }
+       output_highlight($args{'sections'}{$section});
+       $output_preformatted = 0;
+       if ($section =~ m/EXAMPLE/i) {
+           print "</para></example>\n";
+       } else {
+           print "</para>";
+       }
+       if (!$args{'content-only'}) {
+               print "\n</refsect1>\n";
+       }
+    }
+
+    print "\n\n";
+}
+
+# output in XML DocBook
+sub output_function_gnome {
+    my %args = %{$_[0]};
+    my ($parameter, $section);
+    my $count;
+    my $id;
+
+    $id = $args{'module'} . "-" . $args{'function'};
+    $id =~ s/[^A-Za-z0-9]/-/g;
+
+    print "<sect2>\n";
+    print " <title id=\"$id\">" . $args{'function'} . "</title>\n";
+
+    print "  <funcsynopsis>\n";
+    print "   <funcdef>" . $args{'functiontype'} . " ";
+    print "<function>" . $args{'function'} . " ";
+    print "</function></funcdef>\n";
+
+    $count = 0;
+    if ($#{$args{'parameterlist'}} >= 0) {
+       foreach $parameter (@{$args{'parameterlist'}}) {
+           $type = $args{'parametertypes'}{$parameter};
+           if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
+               # pointer-to-function
+               print "   <paramdef>$1 <parameter>$parameter</parameter>)\n";
+               print "     <funcparams>$2</funcparams></paramdef>\n";
+           } else {
+               print "   <paramdef>" . $type;
+               print " <parameter>$parameter</parameter></paramdef>\n";
+           }
+       }
+    } else {
+       print "  <void>\n";
+    }
+    print "  </funcsynopsis>\n";
+    if ($#{$args{'parameterlist'}} >= 0) {
+       print " <informaltable pgwide=\"1\" frame=\"none\" role=\"params\">\n";
+       print "<tgroup cols=\"2\">\n";
+       print "<colspec colwidth=\"2*\">\n";
+       print "<colspec colwidth=\"8*\">\n";
+       print "<tbody>\n";
+       foreach $parameter (@{$args{'parameterlist'}}) {
+           my $parameter_name = $parameter;
+           $parameter_name =~ s/\[.*//;
+
+           print "  <row><entry align=\"right\"><parameter>$parameter</parameter></entry>\n";
+           print "   <entry>\n";
+           $lineprefix="     ";
+           output_highlight($args{'parameterdescs'}{$parameter_name});
+           print "    </entry></row>\n";
+       }
+       print " </tbody></tgroup></informaltable>\n";
+    } else {
+       print " <para>\n  None\n </para>\n";
+    }
+
+    # print out each section
+    $lineprefix="   ";
+    foreach $section (@{$args{'sectionlist'}}) {
+       print "<simplesect>\n <title>$section</title>\n";
+       if ($section =~ m/EXAMPLE/i) {
+           print "<example><programlisting>\n";
+           $output_preformatted = 1;
+       } else {
+       }
+       print "<para>\n";
+       output_highlight($args{'sections'}{$section});
+       $output_preformatted = 0;
+       print "</para>\n";
+       if ($section =~ m/EXAMPLE/i) {
+           print "</programlisting></example>\n";
+       } else {
+       }
+       print " </simplesect>\n";
+    }
+
+    print "</sect2>\n\n";
+}
+
+##
+# output function in man
+sub output_function_man(%) {
+    my %args = %{$_[0]};
+    my ($parameter, $section);
+    my $count;
+
+    print ".TH \"$args{'function'}\" 3 \"$args{'function'}\" \"$man_date\" \"API Manual\" LINUX\n";
+
+    print ".SH NAME\n";
+    print $args{'function'} . " \\- " . $args{'purpose'} . "\n";
+
+    print ".SH SYNOPSIS\n";
+    if ($args{'functiontype'} ne "") {
+       $args{'functiontype'} =~ s/__DLL_EXPORT\s*//g;
+       print ".B \"" . $args{'functiontype'} . "\" " . $args{'function'} . "\n";
+    } else {
+       print ".B \"" . $args{'function'} . "\n";
+    }
+    $count = 0;
+    my $parenth = "(";
+    my $post = ",";
+    foreach my $parameter (@{$args{'parameterlist'}}) {
+       if ($count == $#{$args{'parameterlist'}}) {
+           $post = ");";
+       }
+       $type = $args{'parametertypes'}{$parameter};
+       if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
+           # pointer-to-function
+           print ".BI \"" . $parenth . $1 . "\" " . $parameter . " \") (" . $2 . ")" . $post . "\"\n";
+       } else {
+           $type =~ s/([^\*])$/$1 /;
+           print ".BI \"" . $parenth . $type . "\" " . $parameter . " \"" . $post . "\"\n";
+       }
+       $count++;
+       $parenth = "";
+    }
+
+    print ".SH ARGUMENTS\n";
+    foreach $parameter (@{$args{'parameterlist'}}) {
+       my $parameter_name = $parameter;
+       $parameter_name =~ s/\[.*//;
+
+       print ".IP \"" . $parameter . "\" 12\n";
+       output_highlight($args{'parameterdescs'}{$parameter_name});
+    }
+    foreach $section (@{$args{'sectionlist'}}) {
+       print ".SH \"", uc $section, "\"\n";
+       output_highlight($args{'sections'}{$section});
+    }
+}
+
+##
+# output enum in man
+sub output_enum_man(%) {
+    my %args = %{$_[0]};
+    my ($parameter, $section);
+    my $count;
+
+    print ".TH \"$args{'module'}\" 3 \"enum $args{'enum'}\" \"$man_date\" \"API Manual\" LINUX\n";
+
+    print ".SH NAME\n";
+    print "enum " . $args{'enum'} . " \\- " . $args{'purpose'} . "\n";
+
+    print ".SH SYNOPSIS\n";
+    print "enum " . $args{'enum'} . " {\n";
+    $count = 0;
+    foreach my $parameter (@{$args{'parameterlist'}}) {
+       print ".br\n.BI \"    $parameter\"\n";
+       if ($count == $#{$args{'parameterlist'}}) {
+           print "\n};\n";
+           last;
+       }
+       else {
+           print ", \n.br\n";
+       }
+       $count++;
+    }
+
+    print ".SH Constants\n";
+    foreach $parameter (@{$args{'parameterlist'}}) {
+       my $parameter_name = $parameter;
+       $parameter_name =~ s/\[.*//;
+
+       print ".IP \"" . $parameter . "\" 12\n";
+       output_highlight($args{'parameterdescs'}{$parameter_name});
+    }
+    foreach $section (@{$args{'sectionlist'}}) {
+       print ".SH \"$section\"\n";
+       output_highlight($args{'sections'}{$section});
+    }
+}
+
+##
+# output struct in man
+sub output_struct_man(%) {
+    my %args = %{$_[0]};
+    my ($parameter, $section);
+
+    print ".TH \"$args{'module'}\" 3 \"" . $args{'type'} . " " . $args{'struct'} . "\" \"$man_date\" \"API Manual\" LINUX\n";
+
+    print ".SH NAME\n";
+    print $args{'type'} . " " . $args{'struct'} . " \\- " . $args{'purpose'} . "\n";
+
+    print ".SH SYNOPSIS\n";
+    print $args{'type'} . " " . $args{'struct'} . " {\n.br\n";
+
+    foreach my $parameter (@{$args{'parameterlist'}}) {
+       if ($parameter =~ /^#/) {
+           print ".BI \"$parameter\"\n.br\n";
+           next;
+       }
+       my $parameter_name = $parameter;
+       $parameter_name =~ s/\[.*//;
+
+       ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
+       $type = $args{'parametertypes'}{$parameter};
+       if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
+           # pointer-to-function
+           print ".BI \"    " . $1 . "\" " . $parameter . " \") (" . $2 . ")" . "\"\n;\n";
+       } elsif ($type =~ m/^(.*?)\s*(:.*)/) {
+           # bitfield
+           print ".BI \"    " . $1 . "\ \" " . $parameter . $2 . " \"" . "\"\n;\n";
+       } else {
+           $type =~ s/([^\*])$/$1 /;
+           print ".BI \"    " . $type . "\" " . $parameter . " \"" . "\"\n;\n";
+       }
+       print "\n.br\n";
+    }
+    print "};\n.br\n";
+
+    print ".SH Members\n";
+    foreach $parameter (@{$args{'parameterlist'}}) {
+       ($parameter =~ /^#/) && next;
+
+       my $parameter_name = $parameter;
+       $parameter_name =~ s/\[.*//;
+
+       ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
+       print ".IP \"" . $parameter . "\" 12\n";
+       output_highlight($args{'parameterdescs'}{$parameter_name});
+    }
+    foreach $section (@{$args{'sectionlist'}}) {
+       print ".SH \"$section\"\n";
+       output_highlight($args{'sections'}{$section});
+    }
+}
+
+##
+# output typedef in man
+sub output_typedef_man(%) {
+    my %args = %{$_[0]};
+    my ($parameter, $section);
+
+    print ".TH \"$args{'module'}\" 3 \"$args{'typedef'}\" \"$man_date\" \"API Manual\" LINUX\n";
+
+    print ".SH NAME\n";
+    print "typedef " . $args{'typedef'} . " \\- " . $args{'purpose'} . "\n";
+
+    foreach $section (@{$args{'sectionlist'}}) {
+       print ".SH \"$section\"\n";
+       output_highlight($args{'sections'}{$section});
+    }
+}
+
+sub output_blockhead_man(%) {
+    my %args = %{$_[0]};
+    my ($parameter, $section);
+    my $count;
+
+    print ".TH \"$args{'module'}\" 3 \"$args{'module'}\" \"$man_date\" \"API Manual\" LINUX\n";
+
+    foreach $section (@{$args{'sectionlist'}}) {
+       print ".SH \"$section\"\n";
+       output_highlight($args{'sections'}{$section});
+    }
+}
+
+##
+# output in text
+sub output_function_text(%) {
+    my %args = %{$_[0]};
+    my ($parameter, $section);
+    my $start;
+
+    print "Name:\n\n";
+    print $args{'function'} . " - " . $args{'purpose'} . "\n";
+
+    print "\nSynopsis:\n\n";
+    if ($args{'functiontype'} ne "") {
+       $start = $args{'functiontype'} . " " . $args{'function'} . " (";
+    } else {
+       $start = $args{'function'} . " (";
+    }
+    print $start;
+
+    my $count = 0;
+    foreach my $parameter (@{$args{'parameterlist'}}) {
+       $type = $args{'parametertypes'}{$parameter};
+       if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
+           # pointer-to-function
+           print $1 . $parameter . ") (" . $2;
+       } else {
+           print $type . " " . $parameter;
+       }
+       if ($count != $#{$args{'parameterlist'}}) {
+           $count++;
+           print ",\n";
+           print " " x length($start);
+       } else {
+           print ");\n\n";
+       }
+    }
+
+    print "Arguments:\n\n";
+    foreach $parameter (@{$args{'parameterlist'}}) {
+       my $parameter_name = $parameter;
+       $parameter_name =~ s/\[.*//;
+
+       print $parameter . "\n\t" . $args{'parameterdescs'}{$parameter_name} . "\n";
+    }
+    output_section_text(@_);
+}
+
+#output sections in text
+sub output_section_text(%) {
+    my %args = %{$_[0]};
+    my $section;
+
+    print "\n";
+    foreach $section (@{$args{'sectionlist'}}) {
+       print "$section:\n\n";
+       output_highlight($args{'sections'}{$section});
+    }
+    print "\n\n";
+}
+
+# output enum in text
+sub output_enum_text(%) {
+    my %args = %{$_[0]};
+    my ($parameter);
+    my $count;
+    print "Enum:\n\n";
+
+    print "enum " . $args{'enum'} . " - " . $args{'purpose'} . "\n\n";
+    print "enum " . $args{'enum'} . " {\n";
+    $count = 0;
+    foreach $parameter (@{$args{'parameterlist'}}) {
+       print "\t$parameter";
+       if ($count != $#{$args{'parameterlist'}}) {
+           $count++;
+           print ",";
+       }
+       print "\n";
+    }
+    print "};\n\n";
+
+    print "Constants:\n\n";
+    foreach $parameter (@{$args{'parameterlist'}}) {
+       print "$parameter\n\t";
+       print $args{'parameterdescs'}{$parameter} . "\n";
+    }
+
+    output_section_text(@_);
+}
+
+# output typedef in text
+sub output_typedef_text(%) {
+    my %args = %{$_[0]};
+    my ($parameter);
+    my $count;
+    print "Typedef:\n\n";
+
+    print "typedef " . $args{'typedef'} . " - " . $args{'purpose'} . "\n";
+    output_section_text(@_);
+}
+
+# output struct as text
+sub output_struct_text(%) {
+    my %args = %{$_[0]};
+    my ($parameter);
+
+    print $args{'type'} . " " . $args{'struct'} . " - " . $args{'purpose'} . "\n\n";
+    print $args{'type'} . " " . $args{'struct'} . " {\n";
+    foreach $parameter (@{$args{'parameterlist'}}) {
+       if ($parameter =~ /^#/) {
+           print "$parameter\n";
+           next;
+       }
+
+       my $parameter_name = $parameter;
+       $parameter_name =~ s/\[.*//;
+
+       ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
+       $type = $args{'parametertypes'}{$parameter};
+       if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
+           # pointer-to-function
+           print "\t$1 $parameter) ($2);\n";
+       } elsif ($type =~ m/^(.*?)\s*(:.*)/) {
+           # bitfield
+           print "\t$1 $parameter$2;\n";
+       } else {
+           print "\t" . $type . " " . $parameter . ";\n";
+       }
+    }
+    print "};\n\n";
+
+    print "Members:\n\n";
+    foreach $parameter (@{$args{'parameterlist'}}) {
+       ($parameter =~ /^#/) && next;
+
+       my $parameter_name = $parameter;
+       $parameter_name =~ s/\[.*//;
+
+       ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
+       print "$parameter\n\t";
+       print $args{'parameterdescs'}{$parameter_name} . "\n";
+    }
+    print "\n";
+    output_section_text(@_);
+}
+
+sub output_blockhead_text(%) {
+    my %args = %{$_[0]};
+    my ($parameter, $section);
+
+    foreach $section (@{$args{'sectionlist'}}) {
+       print " $section:\n";
+       print "    -> ";
+       output_highlight($args{'sections'}{$section});
+    }
+}
+
+##
+# output in restructured text
+#
+
+#
+# This could use some work; it's used to output the DOC: sections, and
+# starts by putting out the name of the doc section itself, but that tends
+# to duplicate a header already in the template file.
+#
+sub output_blockhead_rst(%) {
+    my %args = %{$_[0]};
+    my ($parameter, $section);
+
+    foreach $section (@{$args{'sectionlist'}}) {
+       if ($output_selection != OUTPUT_INCLUDE) {
+           print "**$section**\n\n";
+       }
+        print_lineno($section_start_lines{$section});
+       output_highlight_rst($args{'sections'}{$section});
+       print "\n";
+    }
+}
+
+sub output_highlight_rst {
+    my $contents = join "\n",@_;
+    my $line;
+
+    # undo the evil effects of xml_escape() earlier
+    $contents = xml_unescape($contents);
+
+    eval $dohighlight;
+    die $@ if $@;
+
+    foreach $line (split "\n", $contents) {
+       print $lineprefix . $line . "\n";
+    }
+}
+
+sub output_function_rst(%) {
+    my %args = %{$_[0]};
+    my ($parameter, $section);
+    my $oldprefix = $lineprefix;
+    my $start = "";
+
+    if ($args{'typedef'}) {
+       print ".. c:type:: ". $args{'function'} . "\n\n";
+       print_lineno($declaration_start_line);
+       print "   **Typedef**: ";
+       $lineprefix = "";
+       output_highlight_rst($args{'purpose'});
+       $start = "\n\n**Syntax**\n\n  ``";
+    } else {
+       print ".. c:function:: ";
+    }
+    if ($args{'functiontype'} ne "") {
+       $start .= $args{'functiontype'} . " " . $args{'function'} . " (";
+    } else {
+       $start .= $args{'function'} . " (";
+    }
+    print $start;
+
+    my $count = 0;
+    foreach my $parameter (@{$args{'parameterlist'}}) {
+       if ($count ne 0) {
+           print ", ";
+       }
+       $count++;
+       $type = $args{'parametertypes'}{$parameter};
+
+       if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
+           # pointer-to-function
+           print $1 . $parameter . ") (" . $2;
+       } else {
+           print $type . " " . $parameter;
+       }
+    }
+    if ($args{'typedef'}) {
+       print ");``\n\n";
+    } else {
+       print ")\n\n";
+       print_lineno($declaration_start_line);
+       $lineprefix = "   ";
+       output_highlight_rst($args{'purpose'});
+       print "\n";
+    }
+
+    print "**Parameters**\n\n";
+    $lineprefix = "  ";
+    foreach $parameter (@{$args{'parameterlist'}}) {
+       my $parameter_name = $parameter;
+       $parameter_name =~ s/\[.*//;
+       $type = $args{'parametertypes'}{$parameter};
+
+       if ($type ne "") {
+           print "``$type $parameter``\n";
+       } else {
+           print "``$parameter``\n";
+       }
+
+        print_lineno($parameterdesc_start_lines{$parameter_name});
+
+       if (defined($args{'parameterdescs'}{$parameter_name}) &&
+           $args{'parameterdescs'}{$parameter_name} ne $undescribed) {
+           output_highlight_rst($args{'parameterdescs'}{$parameter_name});
+       } else {
+           print "  *undescribed*\n";
+       }
+       print "\n";
+    }
+
+    $lineprefix = $oldprefix;
+    output_section_rst(@_);
+}
+
+sub output_section_rst(%) {
+    my %args = %{$_[0]};
+    my $section;
+    my $oldprefix = $lineprefix;
+    $lineprefix = "";
+
+    foreach $section (@{$args{'sectionlist'}}) {
+       print "**$section**\n\n";
+        print_lineno($section_start_lines{$section});
+       output_highlight_rst($args{'sections'}{$section});
+       print "\n";
+    }
+    print "\n";
+    $lineprefix = $oldprefix;
+}
+
+sub output_enum_rst(%) {
+    my %args = %{$_[0]};
+    my ($parameter);
+    my $oldprefix = $lineprefix;
+    my $count;
+    my $name = "enum " . $args{'enum'};
+
+    print "\n\n.. c:type:: " . $name . "\n\n";
+    print_lineno($declaration_start_line);
+    $lineprefix = "   ";
+    output_highlight_rst($args{'purpose'});
+    print "\n";
+
+    print "**Constants**\n\n";
+    $lineprefix = "  ";
+    foreach $parameter (@{$args{'parameterlist'}}) {
+       print "``$parameter``\n";
+       if ($args{'parameterdescs'}{$parameter} ne $undescribed) {
+           output_highlight_rst($args{'parameterdescs'}{$parameter});
+       } else {
+           print "  *undescribed*\n";
+       }
+       print "\n";
+    }
+
+    $lineprefix = $oldprefix;
+    output_section_rst(@_);
+}
+
+sub output_typedef_rst(%) {
+    my %args = %{$_[0]};
+    my ($parameter);
+    my $oldprefix = $lineprefix;
+    my $name = "typedef " . $args{'typedef'};
+
+    print "\n\n.. c:type:: " . $name . "\n\n";
+    print_lineno($declaration_start_line);
+    $lineprefix = "   ";
+    output_highlight_rst($args{'purpose'});
+    print "\n";
+
+    $lineprefix = $oldprefix;
+    output_section_rst(@_);
+}
+
+sub output_struct_rst(%) {
+    my %args = %{$_[0]};
+    my ($parameter);
+    my $oldprefix = $lineprefix;
+    my $name = $args{'type'} . " " . $args{'struct'};
+
+    print "\n\n.. c:type:: " . $name . "\n\n";
+    print_lineno($declaration_start_line);
+    $lineprefix = "   ";
+    output_highlight_rst($args{'purpose'});
+    print "\n";
+
+    print "**Definition**\n\n";
+    print "::\n\n";
+    print "  " . $args{'type'} . " " . $args{'struct'} . " {\n";
+    foreach $parameter (@{$args{'parameterlist'}}) {
+       if ($parameter =~ /^#/) {
+           print "  " . "$parameter\n";
+           next;
+       }
+
+       my $parameter_name = $parameter;
+       $parameter_name =~ s/\[.*//;
+
+       ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
+       $type = $args{'parametertypes'}{$parameter};
+       if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
+           # pointer-to-function
+           print "    $1 $parameter) ($2);\n";
+       } elsif ($type =~ m/^(.*?)\s*(:.*)/) {
+           # bitfield
+           print "    $1 $parameter$2;\n";
+       } else {
+           print "    " . $type . " " . $parameter . ";\n";
+       }
+    }
+    print "  };\n\n";
+
+    print "**Members**\n\n";
+    $lineprefix = "  ";
+    foreach $parameter (@{$args{'parameterlist'}}) {
+       ($parameter =~ /^#/) && next;
+
+       my $parameter_name = $parameter;
+       $parameter_name =~ s/\[.*//;
+
+       ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
+       $type = $args{'parametertypes'}{$parameter};
+        print_lineno($parameterdesc_start_lines{$parameter_name});
+       print "``" . $parameter . "``\n";
+       output_highlight_rst($args{'parameterdescs'}{$parameter_name});
+       print "\n";
+    }
+    print "\n";
+
+    $lineprefix = $oldprefix;
+    output_section_rst(@_);
+}
+
+
+## list mode output functions
+
+sub output_function_list(%) {
+    my %args = %{$_[0]};
+
+    print $args{'function'} . "\n";
+}
+
+# output enum in list
+sub output_enum_list(%) {
+    my %args = %{$_[0]};
+    print $args{'enum'} . "\n";
+}
+
+# output typedef in list
+sub output_typedef_list(%) {
+    my %args = %{$_[0]};
+    print $args{'typedef'} . "\n";
+}
+
+# output struct as list
+sub output_struct_list(%) {
+    my %args = %{$_[0]};
+
+    print $args{'struct'} . "\n";
+}
+
+sub output_blockhead_list(%) {
+    my %args = %{$_[0]};
+    my ($parameter, $section);
+
+    foreach $section (@{$args{'sectionlist'}}) {
+       print "DOC: $section\n";
+    }
+}
+
+##
+# generic output function for all types (function, struct/union, typedef, enum);
+# calls the generated, variable output_ function name based on
+# functype and output_mode
+sub output_declaration {
+    no strict 'refs';
+    my $name = shift;
+    my $functype = shift;
+    my $func = "output_${functype}_$output_mode";
+    if (($output_selection == OUTPUT_ALL) ||
+       (($output_selection == OUTPUT_INCLUDE ||
+         $output_selection == OUTPUT_EXPORTED) &&
+        defined($function_table{$name})) ||
+       (($output_selection == OUTPUT_EXCLUDE ||
+         $output_selection == OUTPUT_INTERNAL) &&
+        !($functype eq "function" && defined($function_table{$name}))))
+    {
+       &$func(@_);
+       $section_counter++;
+    }
+}
+
+##
+# generic output function - calls the right one based on current output mode.
+sub output_blockhead {
+    no strict 'refs';
+    my $func = "output_blockhead_" . $output_mode;
+    &$func(@_);
+    $section_counter++;
+}
+
+##
+# takes a declaration (struct, union, enum, typedef) and
+# invokes the right handler. NOT called for functions.
+sub dump_declaration($$) {
+    no strict 'refs';
+    my ($prototype, $file) = @_;
+    my $func = "dump_" . $decl_type;
+    &$func(@_);
+}
+
+sub dump_union($$) {
+    dump_struct(@_);
+}
+
+sub dump_struct($$) {
+    my $x = shift;
+    my $file = shift;
+    my $nested;
+
+    if ($x =~ /(struct|union)\s+(\w+)\s*{(.*)}/) {
+       my $decl_type = $1;
+       $declaration_name = $2;
+       my $members = $3;
+
+       # ignore embedded structs or unions
+       $members =~ s/({.*})//g;
+       $nested = $1;
+
+       # ignore members marked private:
+       $members =~ s/\/\*\s*private:.*?\/\*\s*public:.*?\*\///gosi;
+       $members =~ s/\/\*\s*private:.*//gosi;
+       # strip comments:
+       $members =~ s/\/\*.*?\*\///gos;
+       $nested =~ s/\/\*.*?\*\///gos;
+       # strip attributes
+       $members =~ s/__attribute__\s*\(\([a-z,_\*\s\(\)]*\)\)//i;
+       $members =~ s/__aligned\s*\([^;]*\)//gos;
+       $members =~ s/\s*CRYPTO_MINALIGN_ATTR//gos;
+       # replace DECLARE_BITMAP
+       $members =~ s/DECLARE_BITMAP\s*\(([^,)]+), ([^,)]+)\)/unsigned long $1\[BITS_TO_LONGS($2)\]/gos;
+       # replace DECLARE_HASHTABLE
+       $members =~ s/DECLARE_HASHTABLE\s*\(([^,)]+), ([^,)]+)\)/unsigned long $1\[1 << (($2) - 1)\]/gos;
+
+       create_parameterlist($members, ';', $file);
+       check_sections($file, $declaration_name, $decl_type, $sectcheck, $struct_actual, $nested);
+
+       output_declaration($declaration_name,
+                          'struct',
+                          {'struct' => $declaration_name,
+                           'module' => $modulename,
+                           'parameterlist' => \@parameterlist,
+                           'parameterdescs' => \%parameterdescs,
+                           'parametertypes' => \%parametertypes,
+                           'sectionlist' => \@sectionlist,
+                           'sections' => \%sections,
+                           'purpose' => $declaration_purpose,
+                           'type' => $decl_type
+                          });
+    }
+    else {
+       print STDERR "${file}:$.: error: Cannot parse struct or union!\n";
+       ++$errors;
+    }
+}
+
+sub dump_enum($$) {
+    my $x = shift;
+    my $file = shift;
+
+    $x =~ s@/\*.*?\*/@@gos;    # strip comments.
+    # strip #define macros inside enums
+    $x =~ s@#\s*((define|ifdef)\s+|endif)[^;]*;@@gos;
+
+    if ($x =~ /enum\s+(\w+)\s*{(.*)}/) {
+       $declaration_name = $1;
+       my $members = $2;
+       my %_members;
+
+       $members =~ s/\s+$//;
+
+       foreach my $arg (split ',', $members) {
+           $arg =~ s/^\s*(\w+).*/$1/;
+           push @parameterlist, $arg;
+           if (!$parameterdescs{$arg}) {
+               $parameterdescs{$arg} = $undescribed;
+               print STDERR "${file}:$.: warning: Enum value '$arg' ".
+                   "not described in enum '$declaration_name'\n";
+           }
+           $_members{$arg} = 1;
+       }
+
+       while (my ($k, $v) = each %parameterdescs) {
+           if (!exists($_members{$k})) {
+            print STDERR "${file}:$.: warning: Excess enum value " .
+                         "'$k' description in '$declaration_name'\n";
+           }
+        }
+
+       output_declaration($declaration_name,
+                          'enum',
+                          {'enum' => $declaration_name,
+                           'module' => $modulename,
+                           'parameterlist' => \@parameterlist,
+                           'parameterdescs' => \%parameterdescs,
+                           'sectionlist' => \@sectionlist,
+                           'sections' => \%sections,
+                           'purpose' => $declaration_purpose
+                          });
+    }
+    else {
+       print STDERR "${file}:$.: error: Cannot parse enum!\n";
+       ++$errors;
+    }
+}
+
+sub dump_typedef($$) {
+    my $x = shift;
+    my $file = shift;
+
+    $x =~ s@/\*.*?\*/@@gos;    # strip comments.
+
+    # Parse function prototypes
+    if ($x =~ /typedef\s+(\w+)\s*\(\*\s*(\w\S+)\s*\)\s*\((.*)\);/ ||
+       $x =~ /typedef\s+(\w+)\s*(\w\S+)\s*\s*\((.*)\);/) {
+
+       # Function typedefs
+       $return_type = $1;
+       $declaration_name = $2;
+       my $args = $3;
+
+       create_parameterlist($args, ',', $file);
+
+       output_declaration($declaration_name,
+                          'function',
+                          {'function' => $declaration_name,
+                           'typedef' => 1,
+                           'module' => $modulename,
+                           'functiontype' => $return_type,
+                           'parameterlist' => \@parameterlist,
+                           'parameterdescs' => \%parameterdescs,
+                           'parametertypes' => \%parametertypes,
+                           'sectionlist' => \@sectionlist,
+                           'sections' => \%sections,
+                           'purpose' => $declaration_purpose
+                          });
+       return;
+    }
+
+    while (($x =~ /\(*.\)\s*;$/) || ($x =~ /\[*.\]\s*;$/)) {
+       $x =~ s/\(*.\)\s*;$/;/;
+       $x =~ s/\[*.\]\s*;$/;/;
+    }
+
+    if ($x =~ /typedef.*\s+(\w+)\s*;/) {
+       $declaration_name = $1;
+
+       output_declaration($declaration_name,
+                          'typedef',
+                          {'typedef' => $declaration_name,
+                           'module' => $modulename,
+                           'sectionlist' => \@sectionlist,
+                           'sections' => \%sections,
+                           'purpose' => $declaration_purpose
+                          });
+    }
+    else {
+       print STDERR "${file}:$.: error: Cannot parse typedef!\n";
+       ++$errors;
+    }
+}
+
+sub save_struct_actual($) {
+    my $actual = shift;
+
+    # strip all spaces from the actual param so that it looks like one string item
+    $actual =~ s/\s*//g;
+    $struct_actual = $struct_actual . $actual . " ";
+}
+
+sub create_parameterlist($$$) {
+    my $args = shift;
+    my $splitter = shift;
+    my $file = shift;
+    my $type;
+    my $param;
+
+    # temporarily replace commas inside function pointer definition
+    while ($args =~ /(\([^\),]+),/) {
+       $args =~ s/(\([^\),]+),/$1#/g;
+    }
+
+    foreach my $arg (split($splitter, $args)) {
+       # strip comments
+       $arg =~ s/\/\*.*\*\///;
+       # strip leading/trailing spaces
+       $arg =~ s/^\s*//;
+       $arg =~ s/\s*$//;
+       $arg =~ s/\s+/ /;
+
+       if ($arg =~ /^#/) {
+           # Treat preprocessor directive as a typeless variable just to fill
+           # corresponding data structures "correctly". Catch it later in
+           # output_* subs.
+           push_parameter($arg, "", $file);
+       } elsif ($arg =~ m/\(.+\)\s*\(/) {
+           # pointer-to-function
+           $arg =~ tr/#/,/;
+           $arg =~ m/[^\(]+\(\*?\s*(\w*)\s*\)/;
+           $param = $1;
+           $type = $arg;
+           $type =~ s/([^\(]+\(\*?)\s*$param/$1/;
+           save_struct_actual($param);
+           push_parameter($param, $type, $file);
+       } elsif ($arg) {
+           $arg =~ s/\s*:\s*/:/g;
+           $arg =~ s/\s*\[/\[/g;
+
+           my @args = split('\s*,\s*', $arg);
+           if ($args[0] =~ m/\*/) {
+               $args[0] =~ s/(\*+)\s*/ $1/;
+           }
+
+           my @first_arg;
+           if ($args[0] =~ /^(.*\s+)(.*?\[.*\].*)$/) {
+                   shift @args;
+                   push(@first_arg, split('\s+', $1));
+                   push(@first_arg, $2);
+           } else {
+                   @first_arg = split('\s+', shift @args);
+           }
+
+           unshift(@args, pop @first_arg);
+           $type = join " ", @first_arg;
+
+           foreach $param (@args) {
+               if ($param =~ m/^(\*+)\s*(.*)/) {
+                   save_struct_actual($2);
+                   push_parameter($2, "$type $1", $file);
+               }
+               elsif ($param =~ m/(.*?):(\d+)/) {
+                   if ($type ne "") { # skip unnamed bit-fields
+                       save_struct_actual($1);
+                       push_parameter($1, "$type:$2", $file)
+                   }
+               }
+               else {
+                   save_struct_actual($param);
+                   push_parameter($param, $type, $file);
+               }
+           }
+       }
+    }
+}
+
+sub push_parameter($$$) {
+       my $param = shift;
+       my $type = shift;
+       my $file = shift;
+
+       if (($anon_struct_union == 1) && ($type eq "") &&
+           ($param eq "}")) {
+               return;         # ignore the ending }; from anon. struct/union
+       }
+
+       $anon_struct_union = 0;
+       $param =~ s/[\[\)].*//;
+
+       if ($type eq "" && $param =~ /\.\.\.$/)
+       {
+           if (!$param =~ /\w\.\.\.$/) {
+             # handles unnamed variable parameters
+             $param = "...";
+           }
+           if (!defined $parameterdescs{$param} || $parameterdescs{$param} eq "") {
+               $parameterdescs{$param} = "variable arguments";
+           }
+       }
+       elsif ($type eq "" && ($param eq "" or $param eq "void"))
+       {
+           $param="void";
+           $parameterdescs{void} = "no arguments";
+       }
+       elsif ($type eq "" && ($param eq "struct" or $param eq "union"))
+       # handle unnamed (anonymous) union or struct:
+       {
+               $type = $param;
+               $param = "{unnamed_" . $param . "}";
+               $parameterdescs{$param} = "anonymous\n";
+               $anon_struct_union = 1;
+       }
+
+       # warn if parameter has no description
+       # (but ignore ones starting with # as these are not parameters
+       # but inline preprocessor statements);
+       # also ignore unnamed structs/unions;
+       if (!$anon_struct_union) {
+       if (!defined $parameterdescs{$param} && $param !~ /^#/) {
+
+           $parameterdescs{$param} = $undescribed;
+
+           if (($type eq 'function') || ($type eq 'enum')) {
+               print STDERR "${file}:$.: warning: Function parameter ".
+                   "or member '$param' not " .
+                   "described in '$declaration_name'\n";
+           }
+           print STDERR "${file}:$.: warning:" .
+                        " No description found for parameter '$param'\n";
+           ++$warnings;
+       }
+       }
+
+       $param = xml_escape($param);
+
+       # strip spaces from $param so that it is one continuous string
+       # on @parameterlist;
+       # this fixes a problem where check_sections() cannot find
+       # a parameter like "addr[6 + 2]" because it actually appears
+       # as "addr[6", "+", "2]" on the parameter list;
+       # but it's better to maintain the param string unchanged for output,
+       # so just weaken the string compare in check_sections() to ignore
+       # "[blah" in a parameter string;
+       ###$param =~ s/\s*//g;
+       push @parameterlist, $param;
+       $type =~ s/\s\s+/ /g;
+       $parametertypes{$param} = $type;
+}
+
+sub check_sections($$$$$$) {
+       my ($file, $decl_name, $decl_type, $sectcheck, $prmscheck, $nested) = @_;
+       my @sects = split ' ', $sectcheck;
+       my @prms = split ' ', $prmscheck;
+       my $err;
+       my ($px, $sx);
+       my $prm_clean;          # strip trailing "[array size]" and/or beginning "*"
+
+       foreach $sx (0 .. $#sects) {
+               $err = 1;
+               foreach $px (0 .. $#prms) {
+                       $prm_clean = $prms[$px];
+                       $prm_clean =~ s/\[.*\]//;
+                       $prm_clean =~ s/__attribute__\s*\(\([a-z,_\*\s\(\)]*\)\)//i;
+                       # ignore array size in a parameter string;
+                       # however, the original param string may contain
+                       # spaces, e.g.:  addr[6 + 2]
+                       # and this appears in @prms as "addr[6" since the
+                       # parameter list is split at spaces;
+                       # hence just ignore "[..." for the sections check;
+                       $prm_clean =~ s/\[.*//;
+
+                       ##$prm_clean =~ s/^\**//;
+                       if ($prm_clean eq $sects[$sx]) {
+                               $err = 0;
+                               last;
+                       }
+               }
+               if ($err) {
+                       if ($decl_type eq "function") {
+                               print STDERR "${file}:$.: warning: " .
+                                       "Excess function parameter " .
+                                       "'$sects[$sx]' " .
+                                       "description in '$decl_name'\n";
+                               ++$warnings;
+                       } else {
+                               if ($nested !~ m/\Q$sects[$sx]\E/) {
+                                   print STDERR "${file}:$.: warning: " .
+                                       "Excess $decl_type member " .
+                                       "'$sects[$sx]' " .
+                                       "description in '$decl_name'\n";
+                                   ++$warnings;
+                               }
+                       }
+               }
+       }
+}
+
+##
+# Checks the section describing the return value of a function.
+sub check_return_section {
+        my $file = shift;
+        my $declaration_name = shift;
+        my $return_type = shift;
+
+        # Ignore an empty return type (It's a macro)
+        # Ignore functions with a "void" return type. (But don't ignore "void *")
+        if (($return_type eq "") || ($return_type =~ /void\s*\w*\s*$/)) {
+                return;
+        }
+
+        if (!defined($sections{$section_return}) ||
+            $sections{$section_return} eq "") {
+                print STDERR "${file}:$.: warning: " .
+                        "No description found for return value of " .
+                        "'$declaration_name'\n";
+                ++$warnings;
+        }
+}
+
+##
+# takes a function prototype and the name of the current file being
+# processed and spits out all the details stored in the global
+# arrays/hashes.
+sub dump_function($$) {
+    my $prototype = shift;
+    my $file = shift;
+    my $noret = 0;
+
+    $prototype =~ s/^static +//;
+    $prototype =~ s/^extern +//;
+    $prototype =~ s/^asmlinkage +//;
+    $prototype =~ s/^inline +//;
+    $prototype =~ s/^__inline__ +//;
+    $prototype =~ s/^__inline +//;
+    $prototype =~ s/^__always_inline +//;
+    $prototype =~ s/^noinline +//;
+    $prototype =~ s/__init +//;
+    $prototype =~ s/__init_or_module +//;
+    $prototype =~ s/__meminit +//;
+    $prototype =~ s/__must_check +//;
+    $prototype =~ s/__weak +//;
+    my $define = $prototype =~ s/^#\s*define\s+//; #ak added
+    $prototype =~ s/__attribute__\s*\(\(
+            (?:
+                 [\w\s]++          # attribute name
+                 (?:\([^)]*+\))?   # attribute arguments
+                 \s*+,?            # optional comma at the end
+            )+
+          \)\)\s+//x;
+
+    # Yes, this truly is vile.  We are looking for:
+    # 1. Return type (may be nothing if we're looking at a macro)
+    # 2. Function name
+    # 3. Function parameters.
+    #
+    # All the while we have to watch out for function pointer parameters
+    # (which IIRC is what the two sections are for), C types (these
+    # regexps don't even start to express all the possibilities), and
+    # so on.
+    #
+    # If you mess with these regexps, it's a good idea to check that
+    # the following functions' documentation still comes out right:
+    # - parport_register_device (function pointer parameters)
+    # - atomic_set (macro)
+    # - pci_match_device, __copy_to_user (long return type)
+
+    if ($define && $prototype =~ m/^()([a-zA-Z0-9_~:]+)\s+/) {
+        # This is an object-like macro, it has no return type and no parameter
+        # list.
+        # Function-like macros are not allowed to have spaces between
+        # declaration_name and opening parenthesis (notice the \s+).
+        $return_type = $1;
+        $declaration_name = $2;
+        $noret = 1;
+    } elsif ($prototype =~ m/^()([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ ||
+       $prototype =~ m/^(\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ ||
+       $prototype =~ m/^(\w+\s*\*+)\s*([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ ||
+       $prototype =~ m/^(\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ ||
+       $prototype =~ m/^(\w+\s+\w+\s*\*+)\s*([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ ||
+       $prototype =~ m/^(\w+\s+\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ ||
+       $prototype =~ m/^(\w+\s+\w+\s+\w+\s*\*+)\s*([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ ||
+       $prototype =~ m/^()([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||
+       $prototype =~ m/^(\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||
+       $prototype =~ m/^(\w+\s*\*+)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||
+       $prototype =~ m/^(\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||
+       $prototype =~ m/^(\w+\s+\w+\s*\*+)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||
+       $prototype =~ m/^(\w+\s+\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||
+       $prototype =~ m/^(\w+\s+\w+\s+\w+\s*\*+)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||
+       $prototype =~ m/^(\w+\s+\w+\s+\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||
+       $prototype =~ m/^(\w+\s+\w+\s+\w+\s+\w+\s*\*+)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||
+       $prototype =~ m/^(\w+\s+\w+\s*\*+\s*\w+\s*\*+\s*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/)  {
+       $return_type = $1;
+       $declaration_name = $2;
+       my $args = $3;
+
+       create_parameterlist($args, ',', $file);
+    } else {
+       print STDERR "${file}:$.: warning: cannot understand function prototype: '$prototype'\n";
+       return;
+    }
+
+       my $prms = join " ", @parameterlist;
+       check_sections($file, $declaration_name, "function", $sectcheck, $prms, "");
+
+        # This check emits a lot of warnings at the moment, because many
+        # functions don't have a 'Return' doc section. So until the number
+        # of warnings goes sufficiently down, the check is only performed in
+        # verbose mode.
+        # TODO: always perform the check.
+        if ($verbose && !$noret) {
+                check_return_section($file, $declaration_name, $return_type);
+        }
+
+    output_declaration($declaration_name,
+                      'function',
+                      {'function' => $declaration_name,
+                       'module' => $modulename,
+                       'functiontype' => $return_type,
+                       'parameterlist' => \@parameterlist,
+                       'parameterdescs' => \%parameterdescs,
+                       'parametertypes' => \%parametertypes,
+                       'sectionlist' => \@sectionlist,
+                       'sections' => \%sections,
+                       'purpose' => $declaration_purpose
+                      });
+}
+
+sub reset_state {
+    $function = "";
+    %parameterdescs = ();
+    %parametertypes = ();
+    @parameterlist = ();
+    %sections = ();
+    @sectionlist = ();
+    $sectcheck = "";
+    $struct_actual = "";
+    $prototype = "";
+
+    $state = STATE_NORMAL;
+    $inline_doc_state = STATE_INLINE_NA;
+}
+
+sub tracepoint_munge($) {
+       my $file = shift;
+       my $tracepointname = 0;
+       my $tracepointargs = 0;
+
+       if ($prototype =~ m/TRACE_EVENT\((.*?),/) {
+               $tracepointname = $1;
+       }
+       if ($prototype =~ m/DEFINE_SINGLE_EVENT\((.*?),/) {
+               $tracepointname = $1;
+       }
+       if ($prototype =~ m/DEFINE_EVENT\((.*?),(.*?),/) {
+               $tracepointname = $2;
+       }
+       $tracepointname =~ s/^\s+//; #strip leading whitespace
+       if ($prototype =~ m/TP_PROTO\((.*?)\)/) {
+               $tracepointargs = $1;
+       }
+       if (($tracepointname eq 0) || ($tracepointargs eq 0)) {
+               print STDERR "${file}:$.: warning: Unrecognized tracepoint format: \n".
+                            "$prototype\n";
+       } else {
+               $prototype = "static inline void trace_$tracepointname($tracepointargs)";
+       }
+}
+
+sub syscall_munge() {
+       my $void = 0;
+
+       $prototype =~ s@[\r\n\t]+@ @gos; # strip newlines/CR's/tabs
+##     if ($prototype =~ m/SYSCALL_DEFINE0\s*\(\s*(a-zA-Z0-9_)*\s*\)/) {
+       if ($prototype =~ m/SYSCALL_DEFINE0/) {
+               $void = 1;
+##             $prototype = "long sys_$1(void)";
+       }
+
+       $prototype =~ s/SYSCALL_DEFINE.*\(/long sys_/; # fix return type & func name
+       if ($prototype =~ m/long (sys_.*?),/) {
+               $prototype =~ s/,/\(/;
+       } elsif ($void) {
+               $prototype =~ s/\)/\(void\)/;
+       }
+
+       # now delete all of the odd-number commas in $prototype
+       # so that arg types & arg names don't have a comma between them
+       my $count = 0;
+       my $len = length($prototype);
+       if ($void) {
+               $len = 0;       # skip the for-loop
+       }
+       for (my $ix = 0; $ix < $len; $ix++) {
+               if (substr($prototype, $ix, 1) eq ',') {
+                       $count++;
+                       if ($count % 2 == 1) {
+                               substr($prototype, $ix, 1) = ' ';
+                       }
+               }
+       }
+}
+
+sub process_proto_function($$) {
+    my $x = shift;
+    my $file = shift;
+
+    $x =~ s@\/\/.*$@@gos; # strip C99-style comments to end of line
+
+    if ($x =~ m#\s*/\*\s+MACDOC\s*#io || ($x =~ /^#/ && $x !~ /^#\s*define/)) {
+       # do nothing
+    }
+    elsif ($x =~ /([^\{]*)/) {
+       $prototype .= $1;
+    }
+
+    if (($x =~ /\{/) || ($x =~ /\#\s*define/) || ($x =~ /;/)) {
+       $prototype =~ s@/\*.*?\*/@@gos; # strip comments.
+       $prototype =~ s@[\r\n]+@ @gos; # strip newlines/cr's.
+       $prototype =~ s@^\s+@@gos; # strip leading spaces
+       if ($prototype =~ /SYSCALL_DEFINE/) {
+               syscall_munge();
+       }
+       if ($prototype =~ /TRACE_EVENT/ || $prototype =~ /DEFINE_EVENT/ ||
+           $prototype =~ /DEFINE_SINGLE_EVENT/)
+       {
+               tracepoint_munge($file);
+       }
+       dump_function($prototype, $file);
+       reset_state();
+    }
+}
+
+sub process_proto_type($$) {
+    my $x = shift;
+    my $file = shift;
+
+    $x =~ s@[\r\n]+@ @gos; # strip newlines/cr's.
+    $x =~ s@^\s+@@gos; # strip leading spaces
+    $x =~ s@\s+$@@gos; # strip trailing spaces
+    $x =~ s@\/\/.*$@@gos; # strip C99-style comments to end of line
+
+    if ($x =~ /^#/) {
+       # To distinguish preprocessor directive from regular declaration later.
+       $x .= ";";
+    }
+
+    while (1) {
+       if ( $x =~ /([^{};]*)([{};])(.*)/ ) {
+            if( length $prototype ) {
+                $prototype .= " "
+            }
+           $prototype .= $1 . $2;
+           ($2 eq '{') && $brcount++;
+           ($2 eq '}') && $brcount--;
+           if (($2 eq ';') && ($brcount == 0)) {
+               dump_declaration($prototype, $file);
+               reset_state();
+               last;
+           }
+           $x = $3;
+       } else {
+           $prototype .= $x;
+           last;
+       }
+    }
+}
+
+# xml_escape: replace <, >, and & in the text stream;
+#
+# however, formatting controls that are generated internally/locally in the
+# kernel-doc script are not escaped here; instead, they begin life like
+# $blankline_html (4 of '\' followed by a mnemonic + ':'), then these strings
+# are converted to their mnemonic-expected output, without the 4 * '\' & ':',
+# just before actual output; (this is done by local_unescape())
+sub xml_escape($) {
+       my $text = shift;
+       if (($output_mode eq "text") || ($output_mode eq "man")) {
+               return $text;
+       }
+       $text =~ s/\&/\\\\\\amp;/g;
+       $text =~ s/\</\\\\\\lt;/g;
+       $text =~ s/\>/\\\\\\gt;/g;
+       return $text;
+}
+
+# xml_unescape: reverse the effects of xml_escape
+sub xml_unescape($) {
+       my $text = shift;
+       if (($output_mode eq "text") || ($output_mode eq "man")) {
+               return $text;
+       }
+       $text =~ s/\\\\\\amp;/\&/g;
+       $text =~ s/\\\\\\lt;/</g;
+       $text =~ s/\\\\\\gt;/>/g;
+       return $text;
+}
+
+# convert local escape strings to html
+# local escape strings look like:  '\\\\menmonic:' (that's 4 backslashes)
+sub local_unescape($) {
+       my $text = shift;
+       if (($output_mode eq "text") || ($output_mode eq "man")) {
+               return $text;
+       }
+       $text =~ s/\\\\\\\\lt:/</g;
+       $text =~ s/\\\\\\\\gt:/>/g;
+       return $text;
+}
+
+sub map_filename($) {
+    my $file;
+    my ($orig_file) = @_;
+
+    if (defined($ENV{'SRCTREE'})) {
+       $file = "$ENV{'SRCTREE'}" . "/" . $orig_file;
+    } else {
+       $file = $orig_file;
+    }
+
+    if (defined($source_map{$file})) {
+       $file = $source_map{$file};
+    }
+
+    return $file;
+}
+
+sub process_export_file($) {
+    my ($orig_file) = @_;
+    my $file = map_filename($orig_file);
+
+    if (!open(IN,"<$file")) {
+       print STDERR "Error: Cannot open file $file\n";
+       ++$errors;
+       return;
+    }
+
+    while (<IN>) {
+       if (/$export_symbol/) {
+           $function_table{$2} = 1;
+       }
+    }
+
+    close(IN);
+}
+
+sub process_file($) {
+    my $file;
+    my $identifier;
+    my $func;
+    my $descr;
+    my $in_purpose = 0;
+    my $initial_section_counter = $section_counter;
+    my ($orig_file) = @_;
+    my $leading_space;
+
+    $file = map_filename($orig_file);
+
+    if (!open(IN,"<$file")) {
+       print STDERR "Error: Cannot open file $file\n";
+       ++$errors;
+       return;
+    }
+
+    $. = 1;
+
+    $section_counter = 0;
+    while (<IN>) {
+       while (s/\\\s*$//) {
+           $_ .= <IN>;
+       }
+       if ($state == STATE_NORMAL) {
+           if (/$doc_start/o) {
+               $state = STATE_NAME;    # next line is always the function name
+               $in_doc_sect = 0;
+               $declaration_start_line = $. + 1;
+           }
+       } elsif ($state == STATE_NAME) {# this line is the function name (always)
+           if (/$doc_block/o) {
+               $state = STATE_DOCBLOCK;
+               $contents = "";
+                $new_start_line = $. + 1;
+
+               if ( $1 eq "" ) {
+                       $section = $section_intro;
+               } else {
+                       $section = $1;
+               }
+           }
+           elsif (/$doc_decl/o) {
+               $identifier = $1;
+               if (/\s*([\w\s]+?)\s*-/) {
+                   $identifier = $1;
+               }
+
+               $state = STATE_FIELD;
+               # if there's no @param blocks need to set up default section
+               # here
+               $contents = "";
+               $section = $section_default;
+               $new_start_line = $. + 1;
+               if (/-(.*)/) {
+                   # strip leading/trailing/multiple spaces
+                   $descr= $1;
+                   $descr =~ s/^\s*//;
+                   $descr =~ s/\s*$//;
+                   $descr =~ s/\s+/ /g;
+                   $declaration_purpose = xml_escape($descr);
+                   $in_purpose = 1;
+               } else {
+                   $declaration_purpose = "";
+               }
+
+               if (($declaration_purpose eq "") && $verbose) {
+                       print STDERR "${file}:$.: warning: missing initial short description on line:\n";
+                       print STDERR $_;
+                       ++$warnings;
+               }
+
+               if ($identifier =~ m/^struct/) {
+                   $decl_type = 'struct';
+               } elsif ($identifier =~ m/^union/) {
+                   $decl_type = 'union';
+               } elsif ($identifier =~ m/^enum/) {
+                   $decl_type = 'enum';
+               } elsif ($identifier =~ m/^typedef/) {
+                   $decl_type = 'typedef';
+               } else {
+                   $decl_type = 'function';
+               }
+
+               if ($verbose) {
+                   print STDERR "${file}:$.: info: Scanning doc for $identifier\n";
+               }
+           } else {
+               print STDERR "${file}:$.: warning: Cannot understand $_ on line $.",
+               " - I thought it was a doc line\n";
+               ++$warnings;
+               $state = STATE_NORMAL;
+           }
+       } elsif ($state == STATE_FIELD) {       # look for head: lines, and include content
+           if (/$doc_sect/i) { # case insensitive for supported section names
+               $newsection = $1;
+               $newcontents = $2;
+
+               # map the supported section names to the canonical names
+               if ($newsection =~ m/^description$/i) {
+                   $newsection = $section_default;
+               } elsif ($newsection =~ m/^context$/i) {
+                   $newsection = $section_context;
+               } elsif ($newsection =~ m/^returns?$/i) {
+                   $newsection = $section_return;
+               } elsif ($newsection =~ m/^\@return$/) {
+                   # special: @return is a section, not a param description
+                   $newsection = $section_return;
+               }
+
+               if (($contents ne "") && ($contents ne "\n")) {
+                   if (!$in_doc_sect && $verbose) {
+                       print STDERR "${file}:$.: warning: contents before sections\n";
+                       ++$warnings;
+                   }
+                   dump_section($file, $section, xml_escape($contents));
+                   $section = $section_default;
+               }
+
+               $in_doc_sect = 1;
+               $in_purpose = 0;
+               $contents = $newcontents;
+                $new_start_line = $.;
+               while ((substr($contents, 0, 1) eq " ") ||
+                      substr($contents, 0, 1) eq "\t") {
+                   $contents = substr($contents, 1);
+               }
+               if ($contents ne "") {
+                   $contents .= "\n";
+               }
+               $section = $newsection;
+               $leading_space = undef;
+           } elsif (/$doc_end/) {
+               if (($contents ne "") && ($contents ne "\n")) {
+                   dump_section($file, $section, xml_escape($contents));
+                   $section = $section_default;
+                   $contents = "";
+               }
+               # look for doc_com + <text> + doc_end:
+               if ($_ =~ m'\s*\*\s*[a-zA-Z_0-9:\.]+\*/') {
+                   print STDERR "${file}:$.: warning: suspicious ending line: $_";
+                   ++$warnings;
+               }
+
+               $prototype = "";
+               $state = STATE_PROTO;
+               $brcount = 0;
+#              print STDERR "end of doc comment, looking for prototype\n";
+           } elsif (/$doc_content/) {
+               # miguel-style comment kludge, look for blank lines after
+               # @parameter line to signify start of description
+               if ($1 eq "") {
+                   if ($section =~ m/^@/ || $section eq $section_context) {
+                       dump_section($file, $section, xml_escape($contents));
+                       $section = $section_default;
+                       $contents = "";
+                        $new_start_line = $.;
+                   } else {
+                       $contents .= "\n";
+                   }
+                   $in_purpose = 0;
+               } elsif ($in_purpose == 1) {
+                   # Continued declaration purpose
+                   chomp($declaration_purpose);
+                   $declaration_purpose .= " " . xml_escape($1);
+                   $declaration_purpose =~ s/\s+/ /g;
+               } else {
+                   my $cont = $1;
+                   if ($section =~ m/^@/ || $section eq $section_context) {
+                       if (!defined $leading_space) {
+                           if ($cont =~ m/^(\s+)/) {
+                               $leading_space = $1;
+                           } else {
+                               $leading_space = "";
+                           }
+                       }
+
+                       $cont =~ s/^$leading_space//;
+                   }
+                   $contents .= $cont . "\n";
+               }
+           } else {
+               # i dont know - bad line?  ignore.
+               print STDERR "${file}:$.: warning: bad line: $_";
+               ++$warnings;
+           }
+       } elsif ($state == STATE_INLINE) { # scanning for inline parameters
+           # First line (state 1) needs to be a @parameter
+           if ($inline_doc_state == STATE_INLINE_NAME && /$doc_inline_sect/o) {
+               $section = $1;
+               $contents = $2;
+                $new_start_line = $.;
+               if ($contents ne "") {
+                   while ((substr($contents, 0, 1) eq " ") ||
+                          substr($contents, 0, 1) eq "\t") {
+                       $contents = substr($contents, 1);
+                   }
+                   $contents .= "\n";
+               }
+               $inline_doc_state = STATE_INLINE_TEXT;
+           # Documentation block end */
+           } elsif (/$doc_inline_end/) {
+               if (($contents ne "") && ($contents ne "\n")) {
+                   dump_section($file, $section, xml_escape($contents));
+                   $section = $section_default;
+                   $contents = "";
+               }
+               $state = STATE_PROTO;
+               $inline_doc_state = STATE_INLINE_NA;
+           # Regular text
+           } elsif (/$doc_content/) {
+               if ($inline_doc_state == STATE_INLINE_TEXT) {
+                   $contents .= $1 . "\n";
+                   # nuke leading blank lines
+                   if ($contents =~ /^\s*$/) {
+                       $contents = "";
+                   }
+               } elsif ($inline_doc_state == STATE_INLINE_NAME) {
+                   $inline_doc_state = STATE_INLINE_ERROR;
+                   print STDERR "${file}:$.: warning: ";
+                   print STDERR "Incorrect use of kernel-doc format: $_";
+                   ++$warnings;
+               }
+           }
+       } elsif ($state == STATE_PROTO) {       # scanning for function '{' (end of prototype)
+           if (/$doc_inline_oneline/) {
+               $section = $1;
+               $contents = $2;
+               if ($contents ne "") {
+                   $contents .= "\n";
+                   dump_section($file, $section, xml_escape($contents));
+                   $section = $section_default;
+                   $contents = "";
+               }
+           } elsif (/$doc_inline_start/) {
+               $state = STATE_INLINE;
+               $inline_doc_state = STATE_INLINE_NAME;
+           } elsif ($decl_type eq 'function') {
+               process_proto_function($_, $file);
+           } else {
+               process_proto_type($_, $file);
+           }
+       } elsif ($state == STATE_DOCBLOCK) {
+               if (/$doc_end/)
+               {
+                       dump_doc_section($file, $section, xml_escape($contents));
+                       $section = $section_default;
+                       $contents = "";
+                       $function = "";
+                       %parameterdescs = ();
+                       %parametertypes = ();
+                       @parameterlist = ();
+                       %sections = ();
+                       @sectionlist = ();
+                       $prototype = "";
+                       $state = STATE_NORMAL;
+               }
+               elsif (/$doc_content/)
+               {
+                       if ( $1 eq "" )
+                       {
+                               $contents .= $blankline;
+                       }
+                       else
+                       {
+                               $contents .= $1 . "\n";
+                       }
+               }
+       }
+    }
+    if ($initial_section_counter == $section_counter) {
+       print STDERR "${file}:1: warning: no structured comments found\n";
+       if (($output_selection == OUTPUT_INCLUDE) && ($show_not_found == 1)) {
+           print STDERR "    Was looking for '$_'.\n" for keys %function_table;
+       }
+       if ($output_mode eq "xml") {
+           # The template wants at least one RefEntry here; make one.
+           print "<refentry>\n";
+           print " <refnamediv>\n";
+           print "  <refname>\n";
+           print "   ${orig_file}\n";
+           print "  </refname>\n";
+           print "  <refpurpose>\n";
+           print "   Document generation inconsistency\n";
+           print "  </refpurpose>\n";
+           print " </refnamediv>\n";
+           print " <refsect1>\n";
+           print "  <title>\n";
+           print "   Oops\n";
+           print "  </title>\n";
+           print "  <warning>\n";
+           print "   <para>\n";
+           print "    The template for this document tried to insert\n";
+           print "    the structured comment from the file\n";
+           print "    <filename>${orig_file}</filename> at this point,\n";
+           print "    but none was found.\n";
+           print "    This dummy section is inserted to allow\n";
+           print "    generation to continue.\n";
+           print "   </para>\n";
+           print "  </warning>\n";
+           print " </refsect1>\n";
+           print "</refentry>\n";
+       }
+    }
+}
+
+
+$kernelversion = get_kernel_version();
+
+# generate a sequence of code that will splice in highlighting information
+# using the s// operator.
+for (my $k = 0; $k < @highlights; $k++) {
+    my $pattern = $highlights[$k][0];
+    my $result = $highlights[$k][1];
+#   print STDERR "scanning pattern:$pattern, highlight:($result)\n";
+    $dohighlight .=  "\$contents =~ s:$pattern:$result:gs;\n";
+}
+
+# Read the file that maps relative names to absolute names for
+# separate source and object directories and for shadow trees.
+if (open(SOURCE_MAP, "<.tmp_filelist.txt")) {
+       my ($relname, $absname);
+       while(<SOURCE_MAP>) {
+               chop();
+               ($relname, $absname) = (split())[0..1];
+               $relname =~ s:^/+::;
+               $source_map{$relname} = $absname;
+       }
+       close(SOURCE_MAP);
+}
+
+if ($output_selection == OUTPUT_EXPORTED ||
+    $output_selection == OUTPUT_INTERNAL) {
+
+    push(@export_file_list, @ARGV);
+
+    foreach (@export_file_list) {
+       chomp;
+       process_export_file($_);
+    }
+}
+
+foreach (@ARGV) {
+    chomp;
+    process_file($_);
+}
+if ($verbose && $errors) {
+  print STDERR "$errors errors\n";
+}
+if ($verbose && $warnings) {
+  print STDERR "$warnings warnings\n";
+}
+
+exit($errors);
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/docs/libopeniscsiusr.h.3 b/pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/docs/libopeniscsiusr.h.3
new file mode 100644 (file)
index 0000000..9aecbb6
--- /dev/null
@@ -0,0 +1,89 @@
+.TH "libopeniscsiusr.h" 3 "November 2017" "iSCSI userspace API - libopeniscsiusr Manual"
+
+.SH NAME
+libopeniscsiusr.h \- iSCSI userspace API.
+
+.SH SYNOPSIS
+#include <libopeniscsiusr/libopeniscsiusr.h>
+
+.SH "DESCRIPTION"
+
+All the libopeniscsiusr public functions ship their own man pages.
+You may use 'man -k iscsi' to find out and use 'man 3 <function_name>' to check
+the detail usage.
+
+.SH "USAGE"
+
+To use libopeniscsiusr in your project, we suggest to use the 'pkg-config' way:
+
+ * Add this line into your configure.ac:
+
+    PKG_CHECK_MODULES([LIBISCSIUSR], [libopeniscsiusr])
+
+ * Add these lines into your Makefile.am:
+
+    foo_LDFLAGS += $(LIBISCSIUSR_LIBS)
+    foo_CFLAGS += $(LIBISCSIUSR_CFLAGS)
+
+.SH LOG HANDLING
+
+The log handler function could be set via 'iscsi_context_log_func_set()'.
+The log priority could be set via 'iscsi_context_log_priority_set()'.
+
+By default, the log priorities is 'LIBISCSI_LOG_PRIORITY_WARNING'.
+By default, the log handler is print log to STDERR, and its code is listed
+below in case you want to take it as an example to create your own log handler.
+
+        #define _ISCSI_LOG_STRERR_ALIGN_WIDTH   80
+
+        void _iscsi_log_stderr(struct iscsi_context *ctx, int priority,
+                               const char *file, int line,
+                               const char *func_name,
+                               const char *format, va_list args)
+        {
+                int printed_bytes = 0;
+
+                printed_bytes += fprintf(stderr, "iSCSI %s: ",
+                                         iscsi_log_priority_str(priority));
+                printed_bytes += vfprintf(stderr, format, args);
+
+                if (printed_bytes < _ISCSI_LOG_STRERR_ALIGN_WIDTH) {
+                        fprintf(stderr, "%*s # %s:%s():%d\n",
+                                _ISCSI_LOG_STRERR_ALIGN_WIDTH - printed_bytes,
+                                "", file, func_name, line);
+                } else {
+                        fprintf(stderr, " # %s:%s():%d\n", file, func_name,
+                                line);
+                }
+        }
+
+
+.SH "SAMPLE CODE"
+
+        struct iscsi_context *ctx = NULL;
+        struct iscsi_session **ses = NULL;
+        uint32_t se_count = 0;
+        uint32_t i = 0;
+        int rc = EXIT_SUCCESS;
+
+        ctx = iscsi_context_new();
+        iscsi_context_log_priority_set(ctx, LIBISCSI_LOG_PRIORITY_DEBUG);
+
+        if (iscsi_sessions_get(ctx, &ses, &se_count) != LIBISCSI_OK) {
+                printf("FAILED\n");
+                rc = EXIT_FAILURE;
+        } else {
+                printf("\nGot %" PRIu32 " iSCSI sessions\n", se_count);
+                for (i = 0; i < se_count; ++i)
+                        printf("SID is %" PRIu32 "\n",
+                               iscsi_session_sid_get(ses[i]));
+                iscsi_sessions_free(ses, se_count);
+        }
+        iscsi_context_free(ctx);
+        exit(rc);
+
+.SH "LICENSE"
+GPLv3+
+
+.SH "BUG"
+Please report bug to https://github.com/open-iscsi/open-iscsi/issues
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/docs/list-man-pages.sh b/pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/docs/list-man-pages.sh
new file mode 100755 (executable)
index 0000000..dda8277
--- /dev/null
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# list man pages found given one or more ??? passed in
+#
+# copied from
+#  https://github.com/linux-nvme/libnvme:doc/list-man-pages.sh
+#
+
+for file in $@; do
+    for func in $(sed -n 's/ \* \([a-z_][a-z_0-9]*\)() -.*/\1/p' $file); do
+       echo ${func}
+    done
+
+    for struct in $(sed -n 's/ \* struct \([a-z_]*\) -.*/\1/p' $file); do
+       echo ${struct}
+    done
+
+    for enum in $(sed -n 's/ \* enum \([a-z_]*\) -.*/\1/p' $file); do
+       echo ${enum}
+    done
+done
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/idbm.c b/pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/idbm.c
new file mode 100644 (file)
index 0000000..cb0d5c9
--- /dev/null
@@ -0,0 +1,1198 @@
+/*
+ * Copyright (C) 2017-2018 Red Hat, Inc.
+ *
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Gris Ge <fge@redhat.com>
+ */
+
+/* The code below is modified from usr/idbm.c which licensed like below:
+ *
+ * iSCSI Discovery Database Library
+ *
+ * Copyright (C) 2004 Dmitry Yusupov, Alex Aizman
+ * Copyright (C) 2006 Mike Christie
+ * Copyright (C) 2006 Red Hat, Inc. All rights reserved.
+ * 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 _GNU_SOURCE
+#define _GNU_SOURCE                    /* For strerror_r() */
+#endif
+
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <stdbool.h>
+
+#include "libopeniscsiusr/libopeniscsiusr_common.h"
+
+#include "context.h"
+#include "idbm.h"
+#include "misc.h"
+#include "idbm_fields.h"
+#include "iface.h"
+#include "node.h"
+#include "default.h"
+
+#define TYPE_INT_O     1
+#define TYPE_STR       2
+#define TYPE_UINT8     3
+#define TYPE_UINT16    4
+#define TYPE_UINT32    5
+#define TYPE_INT32     6
+#define TYPE_INT64     7
+#define TYPE_BOOL      8
+#define TYPE_INT_LIST  9
+#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. */
+/* ^ MAX_KEYS, NAME_MAXVAL and VALUE_MAXVAL are copied from usr/idbm.h
+ * The RFC 3720 only said:
+ *     If not otherwise specified, the maximum length of a simple-value (not
+ *     its encoded representation) is 255 bytes, not including the delimiter
+ *     (comma or zero byte).
+ */
+
+#define OPTS_MAXVAL    8
+
+#define IDBM_HIDE      0    /* Hide parameter when print. */
+#define IDBM_SHOW      1    /* Show parameter when print. */
+#define IDBM_MASKED    2    /* Show "stars" instead of real value when print */
+
+#define ISCSI_BEGIN_REC        "# BEGIN RECORD "ISCSI_VERSION_STR
+#define ISCSI_END_REC  "# END RECORD"
+
+#ifndef LOCK_DIR
+#define LOCK_DIR               "/run/lock/iscsi"
+#endif
+#define LOCK_FILE              LOCK_DIR"/lock"
+#define LOCK_WRITE_FILE                LOCK_DIR"/lock.write"
+
+#define _rec_str(_key, _recs, _org, _name, _show, _n, _mod) \
+do { \
+       _recs[_n].type = TYPE_STR; \
+       _strncpy(_recs[_n].name, _key, NAME_MAXVAL); \
+       if (strlen((char*)_org->_name)) \
+               _strncpy((char*)_recs[_n].value, (char*)_org->_name, \
+                        VALUE_MAXVAL); \
+       _recs[_n].data = &_org->_name; \
+       _recs[_n].data_len = sizeof(_org->_name); \
+       _recs[_n].visible = _show; \
+       _recs[_n].can_modify = _mod; \
+       _n++; \
+} while(0)
+
+#define _rec_uint8(_key, _recs, _org, _name, _show, _n, _mod) \
+do { \
+       _recs[_n].type = TYPE_UINT8; \
+       _strncpy(_recs[_n].name, _key, NAME_MAXVAL); \
+       snprintf(_recs[_n].value, VALUE_MAXVAL, "%" PRIu8, _org->_name); \
+       _recs[_n].data = &_org->_name; \
+       _recs[_n].data_len = sizeof(_org->_name); \
+       _recs[_n].visible = _show; \
+       _recs[_n].can_modify = _mod; \
+       _n++; \
+} while (0)
+
+#define _rec_uint16(_key, _recs, _org, _name, _show, _n, _mod) \
+do { \
+       _recs[_n].type = TYPE_UINT16; \
+       _strncpy(_recs[_n].name, _key, NAME_MAXVAL); \
+       snprintf(_recs[_n].value, VALUE_MAXVAL, "%" PRIu16, _org->_name); \
+       _recs[_n].data = &_org->_name; \
+       _recs[_n].data_len = sizeof(_org->_name); \
+       _recs[_n].visible = _show; \
+       _recs[_n].can_modify = _mod; \
+       _n++; \
+} while (0)
+
+#define _rec_uint32(_key, _recs, _org, _name, _show, _n, _mod) \
+do { \
+       _recs[_n].type = TYPE_UINT32; \
+       _strncpy(_recs[_n].name, _key, NAME_MAXVAL); \
+       snprintf(_recs[_n].value, VALUE_MAXVAL, "%" PRIu32, _org->_name); \
+       _recs[_n].data = &_org->_name; \
+       _recs[_n].data_len = sizeof(_org->_name); \
+       _recs[_n].visible = _show; \
+       _recs[_n].can_modify = _mod; \
+       _n++; \
+} while (0)
+
+#define _rec_int32(_key, _recs, _org, _name, _show, _n, _mod) \
+do { \
+       _recs[_n].type = TYPE_INT32; \
+       _strncpy(_recs[_n].name, _key, NAME_MAXVAL); \
+       snprintf(_recs[_n].value, VALUE_MAXVAL, "%" PRIi32, _org->_name); \
+       _recs[_n].data = &_org->_name; \
+       _recs[_n].data_len = sizeof(_org->_name); \
+       _recs[_n].visible = _show; \
+       _recs[_n].can_modify = _mod; \
+       _n++; \
+} while (0)
+
+#define _rec_int64(_key, _recs, _org, _name, _show, _n, _mod) \
+do { \
+       _recs[_n].type = TYPE_INT64; \
+       _strncpy(_recs[_n].name, _key, NAME_MAXVAL); \
+       snprintf(_recs[_n].value, VALUE_MAXVAL, "%" PRIi64, _org->_name); \
+       _recs[_n].data = &_org->_name; \
+       _recs[_n].data_len = sizeof(_org->_name); \
+       _recs[_n].visible = _show; \
+       _recs[_n].can_modify = _mod; \
+       _n++; \
+} while (0)
+
+#define _rec_bool(_key, _recs, _org, _name, _show, _n, _mod) \
+do { \
+       _recs[_n].type = TYPE_BOOL; \
+       _strncpy(_recs[_n].name, _key, NAME_MAXVAL); \
+       snprintf(_recs[_n].value, VALUE_MAXVAL, "%s", \
+                _org->_name ? "Yes" : "No"); \
+       _recs[_n].data = &_org->_name; \
+       _recs[_n].data_len = sizeof(_org->_name); \
+       _recs[_n].visible = _show; \
+       _recs[_n].can_modify = _mod; \
+       _n++; \
+} while(0)
+
+#define _rec_int_o2(_key, _recs, _org, _name, _show, _op0, _op1, _n, _mod) \
+do { \
+       _recs[_n].type = TYPE_INT_O; \
+       _strncpy(_recs[_n].name, _key, NAME_MAXVAL); \
+       if (_org->_name == 0) _strncpy(_recs[_n].value, _op0, VALUE_MAXVAL); \
+       if (_org->_name == 1) _strncpy(_recs[_n].value, _op1, VALUE_MAXVAL); \
+       _recs[_n].data = &_org->_name; \
+       _recs[_n].data_len = sizeof(_org->_name); \
+       _recs[_n].visible = _show; \
+       _recs[_n].opts[0] = _op0; \
+       _recs[_n].opts[1] = _op1; \
+       _recs[_n].numopts = 2; \
+       _recs[_n].can_modify = _mod; \
+       _n++; \
+} while(0)
+
+#define _rec_int_o3(_key, _recs, _org, _name, _show, _op0, _op1, _op2, _n, \
+                   _mod) \
+do { \
+       _rec_int_o2(_key, _recs, _org, _name, _show, _op0, _op1, _n, _mod); \
+       _n--; \
+       if (_org->_name == 2) _strncpy(_recs[_n].value, _op2, VALUE_MAXVAL);\
+       _recs[_n].opts[2] = _op2; \
+       _recs[_n].numopts = 3; \
+       _n++; \
+} while(0)
+
+#define _rec_int_o4(_key, _recs, _org, _name, _show, _op0, _op1, _op2, _op3, \
+                   _n, _mod) \
+do { \
+       _rec_int_o3(_key, _recs, _org, _name, _show, _op0, _op1, _op2, _n, \
+                   _mod); \
+       _n--; \
+       if (_org->_name == 3) _strncpy(_recs[_n].value, _op3, VALUE_MAXVAL);\
+       _recs[_n].opts[3] = _op3; \
+       _recs[_n].numopts = 4; \
+       _n++; \
+} while(0)
+
+#define _rec_int_o5(_key, _recs, _org, _name, _show, _op0, _op1, _op2, _op3, \
+                   _op4, _n, _mod) \
+do { \
+       _rec_int_o4(_key, _recs, _org, _name, _show, _op0, _op1, _op2, _op3, \
+                   _n, _mod); \
+       _n--; \
+       if (_org->_name == 4) _strncpy(_recs[_n].value, _op4, VALUE_MAXVAL);\
+       _recs[_n].opts[4] = _op4; \
+       _recs[_n].numopts = 5; \
+       _n++; \
+} while(0)
+
+#define _rec_int_o6(_key, _recs, _org, _name, _show, _op0, _op1, _op2, _op3, \
+                   _op4, _op5, _n, _mod) \
+do { \
+       _rec_int_o5(_key, _recs, _org, _name, _show, _op0, _op1, _op2, _op3, \
+                   _op4, _n, _mod); \
+       _n--; \
+       if (_org->_name == 5) _strncpy(_recs[_n].value, _op5, VALUE_MAXVAL);\
+       _recs[_n].opts[5] = _op5; \
+       _recs[_n].numopts = 6; \
+       _n++; \
+} while(0)
+
+#define ARRAY_LEN(x) ( sizeof(x) / sizeof((x)[0]) )
+
+/* Options list type, rather than matching a single value this populates an
+ * array with a list of values in user specified order.
+ * Requires a table matching config strings to values.
+ **/
+#define _rec_int_list(_key, _recs, _org, _name, _show, _tbl, _n, _mod) \
+do {\
+       _recs[_n].type = TYPE_INT_LIST; \
+       _strncpy(_recs[_n].name, _key, NAME_MAXVAL); \
+       for (unsigned int _i = 0; _i < ARRAY_LEN(_org->_name); _i++) { \
+               if (_org->_name[_i] != UINT_MAX) { \
+                       for (unsigned int _j = 0; _j < ARRAY_LEN(_tbl); _j++) { \
+                               if (_tbl[_j].value == _org->_name[_i]) { \
+                                       strcat(_recs[_n].value, _tbl[_j].name); \
+                                       strcat(_recs[_n].value, ","); \
+                                       break; \
+                               } \
+                       } \
+               } \
+       } \
+       /* delete traling ',' */ \
+       if (strrchr(_recs[_n].value, ',')) \
+               *strrchr(_recs[_n].value, ',') = '\0'; \
+       _recs[_n].data = &_org->_name; \
+       _recs[_n].data_len = sizeof(_org->_name); \
+       _recs[_n].visible = _show; \
+       _recs[_n].opts[0] = (void *)&_tbl; \
+       _recs[_n].numopts = ARRAY_LEN(_tbl); \
+       _recs[_n].can_modify = _mod; \
+       _n++; \
+} while(0)
+
+enum modify_mode {
+       _CANNOT_MODIFY,
+       _CAN_MODIFY,
+};
+
+struct idbm_rec {
+       int                     type;
+       char                    name[NAME_MAXVAL];
+       char                    value[VALUE_MAXVAL];
+       void                    *data;
+       int                     data_len;
+       int                     visible;
+       char*                   opts[OPTS_MAXVAL];
+       int                     numopts;
+       /*
+        * TODO: make it a enum that can indicate whether it also requires
+        * a relogin to pick up if a session is running.
+        */
+       enum modify_mode        can_modify;
+};
+
+static void _idbm_node_rec_link(struct iscsi_node *node, struct idbm_rec *recs, const char *iface_name);
+
+int _idbm_lock(struct iscsi_context *ctx)
+{
+       int fd, i, ret;
+       struct idbm *db = NULL;
+       char strerr_buff[_STRERR_BUFF_LEN];
+       int errno_save = 0;
+
+       assert(ctx != NULL);
+
+       db = ctx->db;
+
+       if (db->refs > 0) {
+               db->refs++;
+               return 0;
+       }
+
+       if (access(LOCK_DIR, F_OK) != 0) {
+               if (mkdir(LOCK_DIR, 0770) != 0) {
+                       _error(ctx, "Could not open %s: %d %s", LOCK_DIR, errno,
+                               _strerror(errno, strerr_buff));
+                       return LIBISCSI_ERR_IDBM;
+               }
+       }
+
+       fd = open(LOCK_FILE, O_RDWR | O_CREAT, 0666);
+       if (fd >= 0)
+               close(fd);
+
+       for (i = 0; i < 3000; i++) {
+               ret = link(LOCK_FILE, LOCK_WRITE_FILE);
+               if (ret == 0)
+                       break;
+               errno_save = errno;
+
+               if (errno != EEXIST) {
+                       _error(ctx, "Maybe you are not root? "
+                              "Could not lock discovery DB: %s: %d %s",
+                              LOCK_WRITE_FILE, errno_save,
+                              _strerror(errno_save, strerr_buff));
+                       return LIBISCSI_ERR_IDBM;
+               } else if (i == 0)
+                       _debug(ctx, "Waiting for discovery DB lock on %s",
+                              LOCK_WRITE_FILE);
+
+               usleep(10000);
+       }
+
+       if (ret != 0) {
+               _error(ctx, "Timeout on acquiring lock on DB: %s, errno: %d %s",
+                      LOCK_WRITE_FILE, errno_save,
+                      _strerror(errno_save, strerr_buff));
+               return LIBISCSI_ERR_IDBM;
+       }
+
+       db->refs = 1;
+       return 0;
+}
+
+void _idbm_unlock(struct iscsi_context *ctx)
+{
+       struct idbm *db = NULL;
+
+       assert(ctx != NULL);
+
+       db = ctx->db;
+
+       if (db->refs > 1) {
+               db->refs--;
+               return;
+       }
+
+       db->refs = 0;
+       unlink(LOCK_WRITE_FILE);
+}
+
+static struct idbm_rec* _idbm_recs_alloc(void)
+{
+       return calloc(MAX_KEYS, sizeof(struct idbm_rec));
+}
+
+static void _idbm_recs_free(struct idbm_rec* recs)
+{
+       free(recs);
+}
+
+static int _idbm_iface_rec_link(struct iscsi_iface *iface,
+                                struct idbm_rec *recs, int num)
+{
+       int init_num = num;
+
+       if (strstr(iface->name, "ipv6"))
+               iface->is_ipv6 = true;
+
+       if (init_num == 0)
+               _rec_str(IFACE_ISCSINAME, recs, iface, name, IDBM_SHOW, num,
+                        _CANNOT_MODIFY);
+       else
+               _rec_str(IFACE_ISCSINAME, recs, iface, name, IDBM_SHOW, num,
+                        _CAN_MODIFY);
+       _rec_str(IFACE_NETNAME, recs, iface, netdev, IDBM_SHOW, num,
+                _CAN_MODIFY);
+       _rec_str(IFACE_IPADDR, recs, iface, ipaddress, IDBM_SHOW, num,
+                _CAN_MODIFY);
+       _rec_uint8(IFACE_PREFIX_LEN, recs, iface, prefix_len, IDBM_SHOW, num,
+               _CAN_MODIFY);
+       _rec_str(IFACE_HWADDR, recs, iface, hwaddress, IDBM_SHOW, num,
+                _CAN_MODIFY);
+       _rec_str(IFACE_TRANSPORTNAME, recs, iface, transport_name, IDBM_SHOW,
+                num, _CAN_MODIFY);
+       _rec_str(IFACE_INAME, recs, iface, iname, IDBM_SHOW, num, _CAN_MODIFY);
+       _rec_str(IFACE_STATE, recs, iface, state, IDBM_SHOW, num, _CAN_MODIFY);
+       _rec_uint16(IFACE_VLAN_ID, recs, iface, vlan_id, IDBM_SHOW, num,
+                   _CAN_MODIFY);
+       _rec_uint8(IFACE_VLAN_PRIORITY, recs, iface, vlan_priority, IDBM_SHOW,
+                  num, _CAN_MODIFY);
+       _rec_str(IFACE_VLAN_STATE, recs, iface, vlan_state, IDBM_SHOW, num,
+                _CAN_MODIFY);
+       _rec_uint32(IFACE_NUM, recs, iface, iface_num, IDBM_SHOW, num,
+                   _CAN_MODIFY);
+       _rec_uint16(IFACE_MTU, recs, iface, mtu, IDBM_SHOW, num, _CAN_MODIFY);
+       _rec_uint16(IFACE_PORT, recs, iface, port, IDBM_SHOW, num, _CAN_MODIFY);
+
+       if (! iface->is_ipv6) {
+               _rec_str(IFACE_BOOT_PROTO, recs, iface, bootproto, IDBM_SHOW,
+                        num, _CAN_MODIFY);
+               _rec_str(IFACE_SUBNET_MASK, recs, iface, subnet_mask, IDBM_SHOW,
+                        num, _CAN_MODIFY);
+               _rec_str(IFACE_GATEWAY, recs, iface, gateway, IDBM_SHOW, num,
+                        _CAN_MODIFY);
+               _rec_str(IFACE_DHCP_ALT_CID, recs, iface,
+                        dhcp_alt_client_id_state, IDBM_SHOW, num, _CAN_MODIFY);
+               _rec_str(IFACE_DHCP_ALT_CID_STR, recs, iface,
+                        dhcp_alt_client_id, IDBM_SHOW, num, _CAN_MODIFY);
+               _rec_str(IFACE_DHCP_DNS, recs, iface, dhcp_dns, IDBM_SHOW, num,
+                        _CAN_MODIFY);
+               _rec_str(IFACE_DHCP_LEARN_IQN, recs, iface, dhcp_learn_iqn,
+                        IDBM_SHOW, num, _CAN_MODIFY);
+               _rec_str(IFACE_DHCP_REQ_VID, recs, iface,
+                        dhcp_req_vendor_id_state, IDBM_SHOW, num, _CAN_MODIFY);
+               _rec_str(IFACE_DHCP_VID, recs, iface, dhcp_vendor_id_state,
+                        IDBM_SHOW, num, _CAN_MODIFY);
+               _rec_str(IFACE_DHCP_VID_STR, recs, iface, dhcp_vendor_id,
+                        IDBM_SHOW, num, _CAN_MODIFY);
+               _rec_str(IFACE_DHCP_SLP_DA, recs, iface, dhcp_slp_da, IDBM_SHOW,
+                        num, _CAN_MODIFY);
+               _rec_str(IFACE_FRAGMENTATION, recs, iface, fragmentation,
+                        IDBM_SHOW, num, _CAN_MODIFY);
+               _rec_str(IFACE_GRAT_ARP, recs, iface, gratuitous_arp, IDBM_SHOW,
+                        num, _CAN_MODIFY);
+               _rec_str(IFACE_IN_FORWARD, recs, iface, incoming_forwarding,
+                        IDBM_SHOW, num, _CAN_MODIFY);
+               _rec_str(IFACE_TOS_STATE, recs, iface, tos_state, IDBM_SHOW,
+                        num, _CAN_MODIFY);
+               _rec_uint8(IFACE_TOS, recs, iface, tos, IDBM_SHOW, num,
+                          _CAN_MODIFY);
+               _rec_uint8(IFACE_TTL, recs, iface, ttl, IDBM_SHOW, num,
+                          _CAN_MODIFY);
+       } else {
+               _rec_str(IFACE_IPV6_AUTOCFG, recs, iface, ipv6_autocfg,
+                        IDBM_SHOW, num, _CAN_MODIFY);
+               _rec_str(IFACE_LINKLOCAL_AUTOCFG, recs, iface,
+                        linklocal_autocfg, IDBM_SHOW, num, _CAN_MODIFY);
+               _rec_str(IFACE_ROUTER_AUTOCFG, recs, iface, router_autocfg,
+                        IDBM_SHOW, num, _CAN_MODIFY);
+               _rec_str(IFACE_LINKLOCAL, recs, iface, ipv6_linklocal,
+                        IDBM_SHOW, num, _CAN_MODIFY);
+               _rec_str(IFACE_ROUTER, recs, iface, ipv6_router, IDBM_SHOW, num,
+                        _CAN_MODIFY);
+               _rec_uint8(IFACE_DUP_ADDR_DETECT_CNT, recs, iface,
+                          dup_addr_detect_cnt, IDBM_SHOW, num, _CAN_MODIFY);
+               _rec_uint32(IFACE_FLOW_LABEL, recs, iface, flow_label,
+                           IDBM_SHOW, num, _CAN_MODIFY);
+               _rec_str(IFACE_GRAT_NEIGHBOR_ADV, recs, iface,
+                        gratuitous_neighbor_adv, IDBM_SHOW, num, _CAN_MODIFY);
+               _rec_uint8(IFACE_HOP_LIMIT, recs, iface, hop_limit, IDBM_SHOW,
+                          num, _CAN_MODIFY);
+               _rec_str(IFACE_MLD, recs, iface, mld, IDBM_SHOW, num,
+                        _CAN_MODIFY);
+               _rec_uint32(IFACE_ND_REACHABLE_TMO, recs, iface,
+                           nd_reachable_tmo, IDBM_SHOW, num, _CAN_MODIFY);
+               _rec_uint32(IFACE_ND_REXMIT_TIME, recs, iface, nd_rexmit_time,
+                           IDBM_SHOW, num, _CAN_MODIFY);
+               _rec_uint32(IFACE_ND_STALE_TMO, recs, iface, nd_stale_tmo,
+                           IDBM_SHOW, num, _CAN_MODIFY);
+               _rec_uint32(IFACE_RTR_ADV_LINK_MTU, recs, iface,
+                           router_adv_link_mtu, IDBM_SHOW, num, _CAN_MODIFY);
+               _rec_uint8(IFACE_TRAFFIC_CLASS, recs, iface, traffic_class,
+                          IDBM_SHOW, num, _CAN_MODIFY);
+       }
+
+       _rec_str(IFACE_DELAYED_ACK, recs, iface, delayed_ack, IDBM_SHOW, num,
+                _CAN_MODIFY);
+       _rec_str(IFACE_TCP_NAGLE, recs, iface, nagle, IDBM_SHOW, num,
+                _CAN_MODIFY);
+       _rec_str(IFACE_TCP_WSF_STATE, recs, iface, tcp_wsf_state, IDBM_SHOW,
+                num, _CAN_MODIFY);
+       _rec_uint8(IFACE_TCP_WSF, recs, iface, tcp_wsf, IDBM_SHOW, num,
+                  _CAN_MODIFY);
+       _rec_uint8(IFACE_TCP_TIMER_SCALE, recs, iface, tcp_timer_scale,
+                  IDBM_SHOW, num, _CAN_MODIFY);
+       _rec_str(IFACE_TCP_TIMESTAMP, recs, iface, tcp_timestamp, IDBM_SHOW,
+                num, _CAN_MODIFY);
+       _rec_str(IFACE_REDIRECT, recs, iface, redirect, IDBM_SHOW, num,
+                _CAN_MODIFY);
+       _rec_uint16(IFACE_DEF_TMF_TMO, recs, iface, def_task_mgmt_tmo,
+                   IDBM_SHOW, num, _CAN_MODIFY);
+       _rec_str(IFACE_HDRDGST, recs, iface, header_digest, IDBM_SHOW, num,
+                _CAN_MODIFY);
+       _rec_str(IFACE_DATADGST, recs, iface, data_digest, IDBM_SHOW, num,
+                _CAN_MODIFY);
+       _rec_str(IFACE_IMM_DATA, recs, iface, immediate_data, IDBM_SHOW, num,
+                _CAN_MODIFY);
+       _rec_str(IFACE_INITIAL_R2T, recs, iface, initial_r2t, IDBM_SHOW, num,
+                _CAN_MODIFY);
+       _rec_str(IFACE_DSEQ_INORDER, recs, iface, data_seq_inorder, IDBM_SHOW,
+                num, _CAN_MODIFY);
+       _rec_str(IFACE_DPDU_INORDER, recs, iface, data_pdu_inorder, IDBM_SHOW,
+                num, _CAN_MODIFY);
+       _rec_uint8(IFACE_ERL, recs, iface, erl, IDBM_SHOW, num, _CAN_MODIFY);
+       _rec_uint32(IFACE_MAX_RECV_DLEN, recs, iface, max_recv_dlength,
+                   IDBM_SHOW, num, _CAN_MODIFY);
+       _rec_uint32(IFACE_FIRST_BURST, recs, iface, first_burst_len, IDBM_SHOW,
+                   num, _CAN_MODIFY);
+       _rec_uint16(IFACE_MAX_R2T, recs, iface, max_out_r2t, IDBM_SHOW, num,
+                   _CAN_MODIFY);
+       _rec_uint32(IFACE_MAX_BURST, recs, iface, max_burst_len, IDBM_SHOW, num,
+                   _CAN_MODIFY);
+       _rec_str(IFACE_CHAP_AUTH, recs, iface, chap_auth, IDBM_SHOW, num,
+                _CAN_MODIFY);
+       _rec_str(IFACE_BIDI_CHAP, recs, iface, bidi_chap, IDBM_SHOW, num,
+                _CAN_MODIFY);
+       _rec_str(IFACE_STRICT_LOGIN_COMP, recs, iface, strict_login_comp,
+                IDBM_SHOW, num, _CAN_MODIFY);
+       _rec_str(IFACE_DISCOVERY_AUTH, recs, iface, discovery_auth, IDBM_SHOW,
+                num, _CAN_MODIFY);
+       _rec_str(IFACE_DISCOVERY_LOGOUT, recs, iface, discovery_logout,
+                IDBM_SHOW, num, _CAN_MODIFY);
+       return num;
+}
+
+static void _idbm_recs_print(struct idbm_rec *recs, FILE *f, int show)
+{
+       int i;
+       fprintf(f, "%s\n", ISCSI_BEGIN_REC);
+       for (i = 0; i < MAX_KEYS; i++) {
+               if (recs[i].visible == IDBM_HIDE)
+                       continue;
+               if (show == IDBM_MASKED && recs[i].visible == IDBM_MASKED) {
+                       if (*(char*)recs[i].data) {
+                               fprintf(f, "%s = ********\n", recs[i].name);
+                               continue;
+                       }
+                       /* fall through */
+               }
+
+               if (strlen(recs[i].value))
+                       fprintf(f, "%s = %s\n", recs[i].name, recs[i].value);
+               else if (f == stdout)
+                       fprintf(f, "%s = <empty>\n", recs[i].name);
+       }
+       fprintf(f, "%s\n", ISCSI_END_REC);
+}
+
+void _idbm_iface_print(struct iscsi_iface *iface, FILE *f)
+{
+       struct idbm_rec *recs = NULL;
+
+       recs = _idbm_recs_alloc();
+       if (recs == NULL)
+               return;
+
+       _idbm_iface_rec_link(iface, recs, 0);
+
+       _idbm_recs_print(recs, f, IDBM_SHOW);
+
+       _idbm_recs_free(recs);
+}
+
+void _idbm_node_print(struct iscsi_node *node, FILE *f, bool show_secret)
+{
+       struct idbm_rec *recs = NULL;
+
+       recs = _idbm_recs_alloc();
+       if (recs == NULL)
+               return;
+
+       _idbm_node_rec_link(node, recs, NULL);
+       _idbm_recs_print(recs, f, show_secret ? IDBM_SHOW : IDBM_MASKED);
+       _idbm_recs_free(recs);
+}
+
+struct int_list_tbl {
+       const char *name;
+       unsigned int value;
+};
+
+static int _idbm_rec_update_param(struct iscsi_context *ctx,
+                                 struct idbm_rec *recs, char *name,
+                                 char *value, int line_number)
+{
+       int rc = LIBISCSI_OK;
+       int i = 0;
+       int j = 0;
+       int k = 0;
+       int passwd_done = 0;
+       char passwd_len[8];
+       struct int_list_tbl *tbl = NULL;
+       char *tmp_value, *orig_tmp_value;
+       int *tmp_data;
+       bool *found;
+       char *token;
+
+       assert(ctx != NULL);
+       assert(recs != NULL);
+       assert(name != NULL);
+       assert(value != NULL);
+
+setup_passwd_len:
+       for (i = 0; i < MAX_KEYS; ++i) {
+               if (!strcmp(name, recs[i].name)) {
+                       _debug(ctx, "updated '%s', '%s' => '%s'", name,
+                              recs[i].value, value);
+                       /* parse recinfo by type */
+                       switch (recs[i].type) {
+                       case TYPE_UINT8:
+                               if (!recs[i].data)
+                                       continue;
+
+                               *(uint8_t *)recs[i].data =
+                                       strtoul(value, NULL, 10);
+                               goto updated;
+                       case TYPE_UINT16:
+                               if (!recs[i].data)
+                                       continue;
+
+                               *(uint16_t *)recs[i].data =
+                                       strtoul(value, NULL, 10);
+                               goto updated;
+                       case TYPE_UINT32:
+                               if (!recs[i].data)
+                                       continue;
+
+                               *(uint32_t *)recs[i].data =
+                                       strtoul(value, NULL, 10);
+                               goto updated;
+                       case TYPE_STR:
+                               if (!recs[i].data)
+                                       continue;
+
+                               _strncpy((char*)recs[i].data,
+                                        value, recs[i].data_len);
+                               goto updated;
+                       case TYPE_INT32:
+                               if (!recs[i].data)
+                                       continue;
+
+                               *(int32_t *)recs[i].data =
+                                       strtoul(value, NULL, 10);
+                               goto updated;
+                       case TYPE_INT64:
+                               if (!recs[i].data)
+                                       continue;
+
+                               *(int64_t *)recs[i].data =
+                                       strtoull(value, NULL, 10);
+                               goto updated;
+                       case TYPE_INT_O:
+                               for (j = 0; j < recs[i].numopts; ++j) {
+                                       if (!strcmp(value, recs[i].opts[j])) {
+                                               if (!recs[i].data)
+                                                       continue;
+
+                                               *(int*)recs[i].data = j;
+                                               goto updated;
+                                       }
+                               }
+                               goto unknown_value;
+                       case TYPE_BOOL:
+                               if (!recs[i].data)
+                                       continue;
+                               if (strcmp(value, "Yes") == 0)
+                                       *(bool *)recs[i].data = true;
+                               else if (strcmp(value, "No") == 0)
+                                       *(bool *)recs[i].data = false;
+                               else
+                                       goto unknown_value;
+                               goto updated;
+                       case TYPE_INT_LIST:
+                               if (!recs[i].data)
+                                       continue;
+                               tbl = (void *)recs[i].opts[0];
+                               /* strsep is destructive, make a copy to work with */
+                               orig_tmp_value = tmp_value = strdup(value);
+                               k = 0;
+                               tmp_data = malloc(recs[i].data_len);
+                               memset(tmp_data, ~0, recs[i].data_len);
+                               found = calloc(recs[i].numopts, sizeof(bool));
+next_token:                    while ((token = strsep(&tmp_value, ", \n"))) {
+                                       if (!strlen(token))
+                                               continue;
+                                       if ((k * (int)sizeof(int)) >= (recs[i].data_len)) {
+                                               _warn(ctx, "Too many values set for '%s'"
+                                                     ", continuing without processing them all",
+                                                     recs[i].name);
+                                               break;
+                                       }
+                                       for (j = 0; j < recs[i].numopts; j++) {
+                                               if (!strcmp(token, tbl[j].name)) {
+                                                       if ((found[j])) {
+                                                               _warn(ctx, "Ignoring repeated value '%s'"
+                                                                     " for '%s'", token, recs[i].name);
+                                                               goto next_token;
+                                                       }
+                                                       ((unsigned *)tmp_data)[k++] = tbl[j].value;
+                                                       found[j] = true;
+                                                       goto next_token;
+                                               }
+                                       }
+                                       _warn(ctx, "Ignoring unknown value '%s'"
+                                             " for '%s'", token, recs[i].name);
+                               }
+                               free(found);
+                               found = NULL;
+                               free(orig_tmp_value);
+                               orig_tmp_value = NULL;
+                               memcpy(recs[i].data, tmp_data, recs[i].data_len);
+                               free(tmp_data);
+                               tmp_data = NULL;
+                               token = NULL;
+                               goto updated;
+                       default:
+unknown_value:
+                               _error(ctx, "Got unknown data type %d "
+                                      "for name '%s', value '%s'",
+                                      recs[i].data, recs[i].name,
+                                      recs[i].value);
+                               rc = LIBISCSI_ERR_BUG;
+                               goto out;
+                       }
+                       if (line_number) {
+                               _warn(ctx, "config file line %d contains "
+                                          "unknown value format '%s' for "
+                                          "parameter name '%s'",
+                                          line_number, value, name);
+                       } else {
+                               _error(ctx, "unknown value format '%s' for "
+                                      "parameter name '%s'", value, name);
+                               rc = LIBISCSI_ERR_INVAL;
+                       }
+                       goto out;
+               }
+       }
+       _error(ctx, "Unknown parameter name %s", name);
+       rc = LIBISCSI_ERR_INVAL;
+       goto out;
+
+updated:
+       _strncpy((char*)recs[i].value, value, VALUE_MAXVAL);
+
+#define check_password_param(_param) \
+       if (!passwd_done && !strcmp(#_param, name)) { \
+               passwd_done = 1; \
+               name = #_param "_length"; \
+               snprintf(passwd_len, 8, "%.7d", (int)strlen(value) & 0xffff); \
+               value = passwd_len; \
+               goto setup_passwd_len; \
+       }
+
+       check_password_param(node.session.auth.password);
+       check_password_param(node.session.auth.password_in);
+       check_password_param(discovery.sendtargets.auth.password);
+       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);
+
+out:
+       return rc;
+}
+
+/*
+ * from linux kernel
+ */
+static char *strstrip(char *s)
+{
+       size_t size;
+       char *end;
+
+       size = strlen(s);
+       if (!size)
+               return s;
+
+       end = s + size - 1;
+       while (end >= s && isspace(*end))
+               end--;
+       *(end + 1) = '\0';
+
+       while (*s && isspace(*s))
+               s++;
+
+       return s;
+}
+
+static int _idbm_recs_read(struct iscsi_context *ctx, struct idbm_rec *recs,
+                          const char *conf_path)
+{
+       int rc = LIBISCSI_OK;
+       char name[NAME_MAXVAL];
+       char value[VALUE_MAXVAL];
+       char *line = NULL;
+       char *nl = NULL;
+       char buffer[2048];
+       int line_number = 0;
+       int c = 0;
+       int i = 0;
+       FILE *f = NULL;
+       int errno_save = 0;
+       char strerr_buff[_STRERR_BUFF_LEN];
+
+       assert(ctx != NULL);
+       assert(recs != NULL);
+       assert(conf_path != NULL);
+
+       f = fopen(conf_path, "r");
+       errno_save = errno;
+       if (!f) {
+               _error(ctx, "Failed to open %s using read mode: %d %s",
+                      conf_path, errno_save,
+                      _strerror(errno_save, strerr_buff));
+               rc = LIBISCSI_ERR_IDBM;
+               goto out;
+       }
+
+       _info(ctx, "Parsing iSCSI interface configuration %s", conf_path);
+       /* process the config file */
+       do {
+               line = fgets(buffer, sizeof (buffer), f);
+               line_number++;
+               if (!line)
+                       continue;
+               if (strlen(line) == 0)
+                       continue;
+
+               nl = line + strlen(line) - 1;
+               if (*nl != '\n') {
+                       _warn(ctx, "Config file %s line %d too long.",
+                             conf_path, line_number);
+                       continue;
+               }
+
+               line = strstrip(line);
+               /* process any non-empty, non-comment lines */
+               if (!*line || *line == '\0' || *line ==  '\n' || *line == '#')
+                       continue;
+
+               /* parse name */
+               i=0; nl = line; *name = 0;
+               while (*nl && !isspace(c = *nl) && *nl != '=') {
+                       *(name+i) = *nl; i++; nl++;
+               }
+               if (!*nl) {
+                       _warn(ctx, "config file %s line %d do not has value",
+                             conf_path, line_number);
+                       continue;
+               }
+               *(name+i)=0; nl++;
+               /* skip after-name traling spaces */
+               while (*nl && isspace(c = *nl)) nl++;
+               if (*nl && *nl != '=') {
+                       _warn(ctx, "config file %s line %d has not '=' "
+                             "separator", conf_path, line_number);
+                       continue;
+               }
+               /* skip '=' sepa */
+               nl++;
+               /* skip after-sepa traling spaces */
+               while (*nl && isspace(c = *nl)) nl++;
+               if (!*nl) {
+                       _warn(ctx, "config file %s line %d do not has value",
+                             conf_path, line_number);
+                       continue;
+               }
+               /* parse value */
+               i=0; *value = 0;
+               while (*nl) {
+                       *(value+i) = *nl; i++; nl++;
+               }
+               *(value+i) = 0;
+
+               rc = _idbm_rec_update_param(ctx, recs, name, value,
+                                           line_number);
+               if (rc == LIBISCSI_ERR_INVAL) {
+                       _error(ctx, "config file %s invalid.", conf_path);
+                       goto out;
+               } else if (rc != LIBISCSI_OK)
+                     goto out;
+       } while (line);
+
+out:
+       if (f != NULL)
+               fclose(f);
+       return rc;
+}
+
+int _idbm_iface_get(struct iscsi_context *ctx, const char *iface_name, struct
+                   iscsi_iface **iface)
+{
+       int rc = LIBISCSI_OK;
+       char *conf_path = NULL;
+       struct idbm_rec *recs = NULL;
+
+       assert(iface != NULL);
+       assert(ctx != NULL);
+
+       *iface = NULL;
+
+       if (iface_name == NULL)
+               goto out;
+
+       if (strcmp(iface_name, "iface.example") == 0)
+               goto out;
+
+       _good(_asprintf(&conf_path, "%s/%s", IFACE_CONFIG_DIR, iface_name),
+             rc, out);
+
+       *iface = calloc(1, sizeof(struct iscsi_iface));
+       _alloc_null_check(ctx, *iface, rc, out);
+
+       snprintf((*iface)->name, sizeof((*iface)->name)/sizeof(char),
+                "%s", iface_name);
+
+       if (strstr(iface_name, "ipv6"))
+               (*iface)->is_ipv6 = true;
+
+       recs = _idbm_recs_alloc();
+       _alloc_null_check(ctx, recs, rc, out);
+
+       _idbm_iface_rec_link(*iface, recs, 0);
+
+       _good(_idbm_recs_read(ctx, recs, conf_path), rc, out);
+
+       if (! _iface_is_valid(*iface)) {
+               _warn(ctx, "'%s' is not a valid iSCSI interface configuration "
+                     "file", conf_path);
+               iscsi_iface_free(*iface);
+               *iface = NULL;
+               /* We still treat this as pass(no error) */
+       }
+
+out:
+       if (rc != LIBISCSI_OK) {
+               iscsi_iface_free(*iface);
+               *iface = NULL;
+       }
+       free(conf_path);
+       _idbm_recs_free(recs);
+       return rc;
+}
+struct idbm *_idbm_new(void)
+{
+       return calloc(1, sizeof(struct idbm));
+}
+
+void _idbm_free(struct idbm *db)
+{
+       free(db);
+}
+
+static struct int_list_tbl chap_algs[] = {
+       { "MD5", ISCSI_AUTH_CHAP_ALG_MD5 },
+       { "SHA1", ISCSI_AUTH_CHAP_ALG_SHA1 },
+       { "SHA256", ISCSI_AUTH_CHAP_ALG_SHA256 },
+       { "SHA3-256", ISCSI_AUTH_CHAP_ALG_SHA3_256 },
+};
+
+static void _idbm_node_rec_link(struct iscsi_node *node, struct idbm_rec *recs, const char *iface_name)
+{
+       int num = 0;
+
+       _rec_str(NODE_NAME, recs, node, target_name, IDBM_SHOW, num,
+                _CANNOT_MODIFY);
+       _rec_int32(NODE_TPGT, recs, node, tpgt, IDBM_SHOW, num,
+                  _CANNOT_MODIFY);
+       _rec_int_o3(NODE_STARTUP, recs, node, startup, IDBM_SHOW, "manual",
+                   "automatic", "onboot", num, _CAN_MODIFY);
+       _rec_bool(NODE_LEADING_LOGIN, recs, node, leading_login, IDBM_SHOW,
+                 num, _CAN_MODIFY);
+
+       /* use the interface name passed in, if any */
+       if (iface_name)
+               strncpy((*node).iface.name, iface_name, ISCSI_MAX_IFACE_LEN-1);
+
+       /*
+        * Note: because we do not add the iface.iscsi_ifacename to
+        * sysfs iscsiadm does some weird matching. We can change the iface
+        * values if a session is not running, but node record ifaces values
+        * have to be changed and so do the iface record ones.
+        *
+        * Users should normally not want to change the iface ones
+        * in the node record directly and instead do it through
+        * the iface mode which will do the right thing (although that
+        * needs some locking).
+        */
+       num = _idbm_iface_rec_link(&((*node).iface), recs, num);
+
+       _rec_str(NODE_DISC_ADDR, recs, node, disc_address, IDBM_SHOW, num,
+                _CANNOT_MODIFY);
+       _rec_int32(NODE_DISC_PORT, recs, node, disc_port, IDBM_SHOW, num,
+                  _CANNOT_MODIFY);
+       _rec_int_o6(NODE_DISC_TYPE, recs, node, disc_type, IDBM_SHOW,
+                   "send_targets", "isns", "offload_send_targets", "slp",
+                   "static", "fw", num, _CANNOT_MODIFY);
+
+       _rec_uint32(SESSION_INIT_CMDSN, recs, node, session.initial_cmdsn,
+                   IDBM_SHOW, num,_CAN_MODIFY);
+       _rec_int64(SESSION_INIT_LOGIN_RETRY, recs, node,
+                  session.initial_login_retry_max, IDBM_SHOW, num,
+                  _CAN_MODIFY);
+       _rec_int64(SESSION_XMIT_THREAD_PRIORITY, recs, node,
+                  session.xmit_thread_priority, IDBM_SHOW, num, _CAN_MODIFY);
+       _rec_uint16(SESSION_CMDS_MAX, recs, node, session.cmds_max, IDBM_SHOW,
+                   num, _CAN_MODIFY);
+       _rec_uint16(SESSION_QDEPTH, recs, node, session.queue_depth, IDBM_SHOW,
+                   num, _CAN_MODIFY);
+       _rec_int64(SESSION_NR_SESSIONS, recs, node, session.nr_sessions,
+                  IDBM_SHOW, num, _CAN_MODIFY);
+       _rec_int_o2(SESSION_AUTH_METHOD, recs, node, session.auth.authmethod,
+                   IDBM_SHOW, "None", "CHAP", num, _CAN_MODIFY);
+       _rec_str(SESSION_USERNAME, recs, node, session.auth.username, IDBM_SHOW,
+                num, _CAN_MODIFY);
+       _rec_str(SESSION_PASSWORD, recs, node, session.auth.password,
+                IDBM_MASKED, num, _CAN_MODIFY);
+       _rec_uint32(SESSION_PASSWORD_LEN, recs, node,
+                   session.auth.password_length, IDBM_HIDE, num, _CAN_MODIFY);
+       _rec_str(SESSION_USERNAME_IN, recs, node, session.auth.username_in,
+                IDBM_SHOW, num, _CAN_MODIFY);
+       _rec_str(SESSION_PASSWORD_IN, recs, node, session.auth.password_in,
+                IDBM_MASKED, num, _CAN_MODIFY);
+       _rec_uint32(SESSION_PASSWORD_IN_LEN, recs, node,
+                   session.auth.password_in_length, IDBM_HIDE, num,
+                   _CAN_MODIFY);
+       _rec_int_list(SESSION_CHAP_ALGS, recs, node, session.auth.chap_algs,
+               IDBM_SHOW, chap_algs, num, _CAN_MODIFY);
+       _rec_int64(SESSION_REPLACEMENT_TMO, recs, node,
+                  session.tmo.replacement_timeout, IDBM_SHOW, num,
+                  _CAN_MODIFY);
+       _rec_int64(SESSION_ABORT_TMO, recs, node, session.err_tmo.abort_timeout,
+                  IDBM_SHOW, num, _CAN_MODIFY);
+       _rec_int64(SESSION_LU_RESET_TMO, recs, node,
+                  session.err_tmo.lu_reset_timeout, IDBM_SHOW, num,
+                  _CAN_MODIFY);
+       _rec_int64(SESSION_TGT_RESET_TMO, recs, node,
+                  session.err_tmo.tgt_reset_timeout, IDBM_SHOW, num,
+                  _CAN_MODIFY);
+       _rec_int64(SESSION_HOST_RESET_TMO, recs, node,
+                  session.err_tmo.host_reset_timeout, IDBM_SHOW, num,
+                  _CAN_MODIFY);
+       _rec_bool(SESSION_FAST_ABORT, recs, node, session.op_cfg.FastAbort,
+                 IDBM_SHOW, num, _CAN_MODIFY);
+       _rec_bool(SESSION_INITIAL_R2T, recs, node, session.op_cfg.InitialR2T,
+                 IDBM_SHOW, num, _CAN_MODIFY);
+       _rec_bool(SESSION_IMM_DATA, recs, node, session.op_cfg.ImmediateData,
+                 IDBM_SHOW, num, _CAN_MODIFY);
+       _rec_int64(SESSION_FIRST_BURST, recs, node,
+                  session.op_cfg.FirstBurstLength, IDBM_SHOW, num,
+                  _CAN_MODIFY);
+       _rec_int64(SESSION_MAX_BURST, recs, node, session.op_cfg.MaxBurstLength,
+                  IDBM_SHOW, num, _CAN_MODIFY);
+       _rec_int64(SESSION_DEF_TIME2RETAIN, recs, node,
+                  session.op_cfg.DefaultTime2Retain, IDBM_SHOW, num,
+                  _CAN_MODIFY);
+       _rec_int64(SESSION_DEF_TIME2WAIT, recs, node,
+                  session.op_cfg.DefaultTime2Wait, IDBM_SHOW, num,
+                  _CAN_MODIFY);
+       _rec_int64(SESSION_MAX_CONNS, recs, node, session.op_cfg.MaxConnections,
+                  IDBM_SHOW, num, _CAN_MODIFY);
+       _rec_int64(SESSION_MAX_R2T, recs, node,
+                  session.op_cfg.MaxOutstandingR2T, IDBM_SHOW, num,
+                  _CAN_MODIFY);
+       _rec_int64(SESSION_ERL, recs, node, session.op_cfg.ERL, IDBM_SHOW, num,
+                  _CAN_MODIFY);
+       _rec_int_o2(SESSION_SCAN, recs, node, session.scan, IDBM_SHOW, "manual",
+                   "auto", num, _CAN_MODIFY);
+       _rec_int64(SESSION_REOPEN_MAX, recs, node, session.reopen_max, IDBM_SHOW, num,
+                  _CAN_MODIFY);
+
+       _rec_str(CONN_ADDR, recs, node, conn.address, IDBM_SHOW, num,
+                _CANNOT_MODIFY);
+       _rec_int32(CONN_PORT, recs, node, conn.port, IDBM_SHOW, num,
+                  _CANNOT_MODIFY);
+       _rec_int_o3(CONN_STARTUP, recs, node, conn.startup, IDBM_SHOW,
+                   "manual", "automatic", "onboot", num, _CAN_MODIFY);
+       _rec_int64(CONN_WINDOW_SIZE, recs, node, conn.tcp.window_size,
+                  IDBM_SHOW, num, _CAN_MODIFY);
+       _rec_int64(CONN_SERVICE_TYPE, recs, node, conn.tcp.type_of_service,
+                  IDBM_SHOW, num, _CAN_MODIFY);
+       _rec_int64(CONN_LOGOUT_TMO, recs, node, conn.tmo.logout_timeout,
+                  IDBM_SHOW, num, _CAN_MODIFY);
+       _rec_int64(CONN_LOGIN_TMO, recs, node, conn.tmo.login_timeout,
+                  IDBM_SHOW, num, _CAN_MODIFY);
+       _rec_int64(CONN_AUTH_TMO, recs, node, conn.tmo.auth_timeout,
+                  IDBM_SHOW, num, _CAN_MODIFY);
+       _rec_int64(CONN_NOP_INT, recs, node, conn.tmo.noop_out_interval,
+                  IDBM_SHOW, num, _CAN_MODIFY);
+       _rec_int64(CONN_NOP_TMO, recs, node, conn.tmo.noop_out_timeout,
+                  IDBM_SHOW, num, _CAN_MODIFY);
+       _rec_int64(CONN_MAX_XMIT_DLEN, recs, node,
+                  conn.op_cfg.MaxXmitDataSegmentLength, IDBM_SHOW,
+                  num, _CAN_MODIFY);
+       _rec_int64(CONN_MAX_RECV_DLEN, recs, node,
+                  conn.op_cfg.MaxRecvDataSegmentLength, IDBM_SHOW,
+                  num, _CAN_MODIFY);
+       _rec_int_o4(CONN_HDR_DIGEST, recs, node, conn.op_cfg.HeaderDigest,
+                   IDBM_SHOW, "None", "CRC32C", "CRC32C,None",
+                   "None,CRC32C", num, _CAN_MODIFY);
+       _rec_int_o4(CONN_DATA_DIGEST, recs, node, conn.op_cfg.DataDigest,
+                   IDBM_SHOW, "None", "CRC32C", "CRC32C,None",
+                   "None,CRC32C", num, _CAN_MODIFY);
+       _rec_bool(CONN_IFMARKER, recs, node, conn.op_cfg.IFMarker, IDBM_SHOW,
+                 num, _CAN_MODIFY);
+       _rec_bool(CONN_OFMARKER, recs, node, conn.op_cfg.OFMarker, IDBM_SHOW,
+                 num, _CAN_MODIFY);
+}
+
+int _idbm_node_get(struct iscsi_context *ctx, const char *target_name,
+                  const char *portal, const char *iface_name,
+                  struct iscsi_node **node)
+{
+       int rc = LIBISCSI_OK;
+       char *conf_path = NULL;
+       struct idbm_rec *recs = NULL;
+
+       assert(node != NULL);
+       assert(ctx != NULL);
+
+       *node = NULL;
+
+       if ((target_name == NULL) || (portal == NULL))
+               goto out;
+
+       if (iface_name == NULL)                 // old style of config
+               _good(_asprintf(&conf_path, "%s/%s/%s", NODE_CONFIG_DIR,
+                        target_name, portal), rc, out);
+       else
+               _good(_asprintf(&conf_path, "%s/%s/%s/%s", NODE_CONFIG_DIR,
+                        target_name, portal, iface_name), rc, out);
+
+       *node = calloc(1, sizeof(struct iscsi_node));
+       _alloc_null_check(ctx, *node, rc, out);
+
+       _default_node(*node);
+
+       recs = _idbm_recs_alloc();
+       _alloc_null_check(ctx, recs, rc, out);
+
+       _idbm_node_rec_link(*node, recs, iface_name);
+
+       _good(_idbm_recs_read(ctx, recs, conf_path), rc, out);
+
+       if (! _iface_is_valid(&((*node)->iface))) {
+               _warn(ctx, "'%s' has invalid iSCSI interface configuration",
+                     conf_path);
+               iscsi_node_free(*node);
+               *node = NULL;
+               /* We still treat this as pass(no error) */
+               goto out;
+       }
+
+       // Add extra properties
+       if (strchr((*node)->conn.address, '.')) {
+               (*node)->conn.is_ipv6 = false;
+               snprintf((*node)->portal, sizeof((*node)->portal)/sizeof(char),
+                        "%s:%" PRIi32, (*node)->conn.address,
+                        (*node)->conn.port);
+
+       } else {
+               (*node)->conn.is_ipv6 = true;
+               snprintf((*node)->portal, sizeof((*node)->portal)/sizeof(char),
+                        "[%s]:%" PRIi32, (*node)->conn.address,
+                        (*node)->conn.port);
+       }
+
+out:
+       if (rc != LIBISCSI_OK) {
+               iscsi_node_free(*node);
+               *node = NULL;
+       }
+       free(conf_path);
+       _idbm_recs_free(recs);
+       return rc;
+}
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/idbm.h b/pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/idbm.h
new file mode 100644 (file)
index 0000000..be5986f
--- /dev/null
@@ -0,0 +1,233 @@
+/*
+ * Copyright (C) 2017-2018 Red Hat, Inc.
+ *
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Gris Ge <fge@redhat.com>
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE                    /* For NI_MAXHOST */
+#endif
+
+#ifndef __ISCSI_OPEN_USR_IDBM_H__
+#define __ISCSI_OPEN_USR_IDBM_H__
+
+#include <stdio.h>
+#include <stdbool.h>
+#include <netdb.h>
+
+#include "libopeniscsiusr/libopeniscsiusr_common.h"
+
+#ifndef ISCSI_DB_ROOT
+#define ISCSI_DB_ROOT "/etc/iscsi"
+#endif
+
+#define        IFACE_CONFIG_DIR        ISCSI_DB_ROOT"/ifaces"
+
+#define AUTH_STR_MAX_LEN       256
+#define BOOT_NAME_MAXLEN       256
+#define IDBM_DUMP_SIZE         8192
+
+
+struct __DLL_LOCAL idbm;
+
+struct idbm {
+       int             refs;
+};
+
+enum iscsi_auth_method {
+       ISCSI_AUTH_METHOD_NONE,
+       ISCSI_AUTH_METHOD_CHAP,
+};
+
+enum iscsi_chap_algs {
+       ISCSI_AUTH_CHAP_ALG_MD5 = 5,
+       ISCSI_AUTH_CHAP_ALG_SHA1 = 6,
+       ISCSI_AUTH_CHAP_ALG_SHA256 = 7,
+       ISCSI_AUTH_CHAP_ALG_SHA3_256 = 8,
+       AUTH_CHAP_ALG_MAX_COUNT = 5,
+};
+
+enum iscsi_startup_type {
+       ISCSI_STARTUP_MANUAL,
+       ISCSI_STARTUP_AUTOMATIC,
+       ISCSI_STARTUP_ONBOOT,
+};
+
+enum discovery_type {
+       DISCOVERY_TYPE_SENDTARGETS,
+       DISCOVERY_TYPE_ISNS,
+       DISCOVERY_TYPE_OFFLOAD_SENDTARGETS,
+       DISCOVERY_TYPE_SLP,
+       DISCOVERY_TYPE_STATIC,
+       DISCOVERY_TYPE_FW,
+};
+
+enum leading_login_type {
+       LEADING_LOGIN_NO,
+       LEADING_LOGIN_YES,
+};
+
+enum init_scan_type {
+       INIT_SCAN_MANUAL,
+       INIT_SCAN_AUTO,
+};
+
+enum digest_type {
+       DIGEST_NEVER,
+       DIGEST_ALWAYS,
+       DIGEST_PREFER_ON,
+       DIGEST_PREFER_OFF,
+};
+
+/* all authentication-related options should be added to this structure.
+ * this structure is per-session, and can be configured
+ * by TargetName but not Subnet.
+ */
+struct iscsi_auth_config {
+       enum iscsi_auth_method                  authmethod;
+       char                                    username[AUTH_STR_MAX_LEN];
+       unsigned char                           password[AUTH_STR_MAX_LEN];
+       uint32_t                                password_length;
+       char                                    username_in[AUTH_STR_MAX_LEN];
+       unsigned char                           password_in[AUTH_STR_MAX_LEN];
+       uint32_t                                password_in_length;
+       unsigned int                            chap_algs[AUTH_CHAP_ALG_MAX_COUNT];
+};
+
+/* all TCP options go in this structure.
+ * this structure is per-portal, and can be configured
+ * both by TargetName and Subnet.
+ */
+struct iscsi_tcp_config {
+       int64_t                                 window_size;
+       int64_t                                 type_of_service;
+       /* ^ try to set IP TOS bits */
+};
+
+/* all per-session timeouts go in this structure.
+ * this structure is per-session, and can be configured
+ * by TargetName but not by Subnet.
+ */
+struct iscsi_session_tmo_cfg {
+       int64_t                                 replacement_timeout;
+};
+
+/* all error handling timeouts go in this structure.
+ * this structure is per-portal, and can be configured
+ * both by TargetName and Subnet.
+ */
+struct iscsi_error_tmo_cfg {
+       int64_t                                 abort_timeout;
+       int64_t                                 host_reset_timeout;
+       int64_t                                 lu_reset_timeout;
+       int64_t                                 tgt_reset_timeout;
+};
+
+/* all per-connection timeouts go in this structure.
+ * this structure is per-portal, and can be configured
+ * both by TargetName and Subnet.
+ */
+struct iscsi_conn_tmo_cfg {
+       int64_t                                 login_timeout;
+       int64_t                                 logout_timeout;
+       int64_t                                 auth_timeout;
+       int64_t                                 active_timeout;
+       int64_t                                 noop_out_interval;
+       int64_t                                 noop_out_timeout;
+};
+
+struct iscsi_conn_op_cfg {
+       int64_t                                 MaxRecvDataSegmentLength;
+       int64_t                                 MaxXmitDataSegmentLength;
+       enum digest_type                        HeaderDigest;
+       enum digest_type                        DataDigest;
+       bool                                    IFMarker;
+       bool                                    OFMarker;
+};
+
+struct iscsi_conn {
+       enum iscsi_startup_type                 startup;
+       char                                    address[NI_MAXHOST];
+       int32_t                                 port;
+       struct iscsi_tcp_config                 tcp;
+       struct iscsi_conn_tmo_cfg               tmo;
+       struct iscsi_conn_op_cfg                op_cfg;
+       bool                                    is_ipv6;
+};
+
+/* all iSCSI operational params go in this structure.
+ * this structure is per-portal, and can be configured
+ * both by TargetName and Subnet.
+ */
+struct iscsi_session_op_cfg {
+       int64_t                                 DataPDUInOrder;
+       int64_t                                 DataSequenceInOrder;
+       int64_t                                 protocol;
+       bool                                    InitialR2T;
+       bool                                    ImmediateData;
+       int64_t                                 FirstBurstLength;
+       int64_t                                 MaxBurstLength;
+       int64_t                                 DefaultTime2Wait;
+       int64_t                                 DefaultTime2Retain;
+       int64_t                                 MaxConnections;
+       int64_t                                 MaxOutstandingR2T;
+       int64_t                                 ERL;
+       bool                                    FastAbort;
+};
+
+struct iscsi_session_idbm {
+       uint32_t                                initial_cmdsn;
+       int64_t                                 reopen_max;
+       int64_t                                 initial_login_retry_max;
+       int64_t                                 xmit_thread_priority;
+       uint16_t                                cmds_max;
+       uint16_t                                queue_depth;
+       int64_t                                 nr_sessions;
+       enum init_scan_type                     scan;
+       struct iscsi_auth_config                auth;
+       struct iscsi_session_tmo_cfg            tmo;
+       struct iscsi_error_tmo_cfg              err_tmo;
+       struct iscsi_session_op_cfg             op_cfg;
+       struct iscsi_session                    *se;
+       uint32_t                                sid;
+       /*
+        * This is a flag passed to iscsid.  If set, multiple sessions are
+        * 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];
+
+};
+
+__DLL_LOCAL struct idbm *_idbm_new(void);
+__DLL_LOCAL void _idbm_free(struct idbm *db);
+__DLL_LOCAL int _idbm_lock(struct iscsi_context *ctx);
+__DLL_LOCAL void _idbm_unlock(struct iscsi_context *ctx);
+__DLL_LOCAL void _idbm_iface_print(struct iscsi_iface *iface, FILE *f);
+__DLL_LOCAL int _idbm_iface_get(struct iscsi_context *ctx,
+                               const char *iface_name,
+                               struct iscsi_iface **iface);
+__DLL_LOCAL int _idbm_node_get(struct iscsi_context *ctx,
+                               const char *target_name,
+                               const char *portal,
+                               const char *iface_name,
+                               struct iscsi_node **node);
+__DLL_LOCAL void _idbm_node_print(struct iscsi_node *node, FILE *f,
+                                 bool show_secret);
+
+#endif /* End of __ISCSI_OPEN_USR_IDBM_H__ */
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/idbm_fields.h b/pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/idbm_fields.h
new file mode 100644 (file)
index 0000000..8bf17b0
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Gris Ge <fge@redhat.com>
+ */
+
+#ifndef __ISCSI_OPEN_USER_IDBM_FIELDS_H
+#define __ISCSI_OPEN_USER_IDBM_FIELDS_H
+
+/* iface fields */
+#define IFACE_HWADDR           "iface.hwaddress"
+#define IFACE_ISCSINAME                "iface.iscsi_ifacename"
+#define IFACE_NETNAME          "iface.net_ifacename"
+#define IFACE_TRANSPORTNAME    "iface.transport_name"
+#define IFACE_INAME            "iface.initiatorname"
+#define IFACE_ISID             "iface.isid"
+#define IFACE_BOOT_PROTO       "iface.bootproto"
+#define IFACE_IPADDR           "iface.ipaddress"
+#define IFACE_PREFIX_LEN       "iface.prefix_len"
+#define IFACE_SUBNET_MASK      "iface.subnet_mask"
+#define IFACE_GATEWAY          "iface.gateway"
+#define IFACE_PRIMARY_DNS      "iface.primary_dns"
+#define IFACE_SEC_DNS          "iface.secondary_dns"
+#define IFACE_VLAN_ID          "iface.vlan_id"
+#define IFACE_VLAN_PRIORITY    "iface.vlan_priority"
+#define IFACE_VLAN_STATE       "iface.vlan_state"
+#define IFACE_LINKLOCAL        "iface.ipv6_linklocal"
+#define IFACE_ROUTER           "iface.ipv6_router"
+#define IFACE_IPV6_AUTOCFG     "iface.ipv6_autocfg"
+#define IFACE_LINKLOCAL_AUTOCFG        "iface.linklocal_autocfg"
+#define IFACE_ROUTER_AUTOCFG   "iface.router_autocfg"
+#define IFACE_STATE            "iface.state"
+#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"
+
+/* node fields */
+#define NODE_NAME              "node.name"
+#define NODE_TPGT              "node.tpgt"
+#define NODE_STARTUP           "node.startup"
+#define NODE_LEADING_LOGIN     "node.leading_login"
+#define NODE_DISC_ADDR         "node.discovery_address"
+#define NODE_DISC_PORT         "node.discovery_port"
+#define NODE_DISC_TYPE         "node.discovery_type"
+#define NODE_BOOT_LUN          "node.boot_lun"
+
+/* session fields */
+#define SESSION_INIT_CMDSN     "node.session.initial_cmdsn"
+#define SESSION_INIT_LOGIN_RETRY "node.session.initial_login_retry_max"
+#define SESSION_CMDS_MAX       "node.session.cmds_max"
+#define SESSION_XMIT_THREAD_PRIORITY "node.session.xmit_thread_priority"
+#define SESSION_QDEPTH         "node.session.queue_depth"
+#define SESSION_NR_SESSIONS    "node.session.nr_sessions"
+#define SESSION_AUTH_METHOD    "node.session.auth.authmethod"
+#define SESSION_USERNAME       "node.session.auth.username"
+#define SESSION_PASSWORD       "node.session.auth.password"
+#define SESSION_PASSWORD_LEN   "node.session.auth.password_length"
+#define SESSION_USERNAME_IN    "node.session.auth.username_in"
+#define SESSION_PASSWORD_IN    "node.session.auth.password_in"
+#define SESSION_PASSWORD_IN_LEN        "node.session.auth.password_in_length"
+#define SESSION_CHAP_ALGS      "node.session.auth.chap_algs"
+#define SESSION_REPLACEMENT_TMO        "node.session.timeo.replacement_timeout"
+#define SESSION_ABORT_TMO      "node.session.err_timeo.abort_timeout"
+#define SESSION_LU_RESET_TMO   "node.session.err_timeo.lu_reset_timeout"
+#define SESSION_TGT_RESET_TMO  "node.session.err_timeo.tgt_reset_timeout"
+#define SESSION_HOST_RESET_TMO "node.session.err_timeo.host_reset_timeout"
+#define SESSION_FAST_ABORT     "node.session.iscsi.FastAbort"
+#define SESSION_INITIAL_R2T    "node.session.iscsi.InitialR2T"
+#define SESSION_IMM_DATA       "node.session.iscsi.ImmediateData"
+#define SESSION_FIRST_BURST    "node.session.iscsi.FirstBurstLength"
+#define SESSION_MAX_BURST      "node.session.iscsi.MaxBurstLength"
+#define SESSION_DEF_TIME2RETAIN        "node.session.iscsi.DefaultTime2Retain"
+#define SESSION_DEF_TIME2WAIT  "node.session.iscsi.DefaultTime2Wait"
+#define SESSION_MAX_CONNS      "node.session.iscsi.MaxConnections"
+#define SESSION_MAX_R2T                "node.session.iscsi.MaxOutstandingR2T"
+#define SESSION_ERL            "node.session.iscsi.ERL"
+#define SESSION_SCAN           "node.session.scan"
+#define SESSION_REOPEN_MAX     "node.session.reopen_max"
+
+/* connections fields */
+#define CONN_ADDR              "node.conn[0].address"
+#define CONN_PORT              "node.conn[0].port"
+#define CONN_STARTUP           "node.conn[0].startup"
+#define CONN_WINDOW_SIZE       "node.conn[0].tcp.window_size"
+#define CONN_SERVICE_TYPE      "node.conn[0].tcp.type_of_service"
+#define CONN_LOGOUT_TMO                "node.conn[0].timeo.logout_timeout"
+#define CONN_LOGIN_TMO         "node.conn[0].timeo.login_timeout"
+#define CONN_AUTH_TMO          "node.conn[0].timeo.auth_timeout"
+#define CONN_NOP_INT           "node.conn[0].timeo.noop_out_interval"
+#define CONN_NOP_TMO           "node.conn[0].timeo.noop_out_timeout"
+#define CONN_MAX_XMIT_DLEN     "node.conn[0].iscsi.MaxXmitDataSegmentLength"
+#define CONN_MAX_RECV_DLEN     "node.conn[0].iscsi.MaxRecvDataSegmentLength"
+#define CONN_HDR_DIGEST                "node.conn[0].iscsi.HeaderDigest"
+#define CONN_DATA_DIGEST       "node.conn[0].iscsi.DataDigest"
+#define CONN_IFMARKER          "node.conn[0].iscsi.IFMarker"
+#define CONN_OFMARKER          "node.conn[0].iscsi.OFMarker"
+
+#endif /* End of __ISCSI_OPEN_USER_IDBM_FIELDS_H */
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/iface.c b/pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/iface.c
new file mode 100644 (file)
index 0000000..006b188
--- /dev/null
@@ -0,0 +1,948 @@
+/*
+ * Copyright (C) 2017-2018 Red Hat, Inc.
+ *
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Gris Ge <fge@redhat.com>
+ */
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE                    /* For NI_MAXHOST */
+#endif
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <dirent.h>
+#include <string.h>
+#include <net/if.h>
+#include <assert.h>
+#include <inttypes.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <stdbool.h>
+#include <libkmod.h>
+#include <limits.h>
+
+#include "libopeniscsiusr/libopeniscsiusr.h"
+#include "misc.h"
+#include "sysfs.h"
+#include "iface.h"
+#include "context.h"
+#include "idbm.h"
+#include "default.h"
+
+#ifndef SBINDIR
+#define SBINDIR "/sbin"
+#endif
+#define ISCSIUIO_PATH SBINDIR "/iscsiuio"
+
+struct _iscsi_net_drv {
+       const char *net_driver_name;            // Ethernet driver.
+       const char *iscsi_driver_name;          // iSCSI offload driver.
+       const char *transport_name;             // iSCSI transport name.
+};
+
+static struct _iscsi_net_drv _ISCSI_NET_DRVS[] = {
+       {"cxgb3", "cxgb3i", "cxgb3i"},
+       {"cxgb4", "cxgb4i", "cxgb4i"},
+       {"bnx2", "bnx2i" , "bnx2i"},
+       {"bnx2x", "bnx2i", "bnx2i"},
+};
+
+const struct iscsi_iface _DEFAULT_IFACES[] = {
+       {
+               .name = "default",
+               .transport_name = "tcp",
+       },
+       {
+               .name           = "iser",
+               .transport_name = "iser",
+       },
+};
+
+static int _load_kernel_module(struct iscsi_context *ctx, const char *drv_name);
+static int _iface_conf_write(struct iscsi_context *ctx,
+                            struct iscsi_iface *iface);
+static int _fill_hw_iface_from_sys(struct iscsi_context *ctx,
+                                  struct iscsi_iface *iface,
+                                  const char *iface_kern_id);
+
+_iscsi_getter_func_gen(iscsi_iface, hwaddress, const char *);
+_iscsi_getter_func_gen(iscsi_iface, transport_name, const char *);
+_iscsi_getter_func_gen(iscsi_iface, ipaddress, const char *);
+_iscsi_getter_func_gen(iscsi_iface, netdev, const char *);
+_iscsi_getter_func_gen(iscsi_iface, iname, const char *);
+_iscsi_getter_func_gen(iscsi_iface, port_state, const char *);
+_iscsi_getter_func_gen(iscsi_iface, port_speed, const char *);
+_iscsi_getter_func_gen(iscsi_iface, name, const char *);
+
+/*
+ * ipv6 address strings will have at least two colons
+ *
+ * NOTE: does NOT validate the IP address
+ */
+static bool lib_ipaddr_is_ipv6(struct iscsi_context *ctx, char *ipaddr)
+{
+       char *first_colon, *second_colon;
+       bool res = false;
+
+       if (ipaddr) {
+               first_colon = strchr(ipaddr, ':');
+               if (first_colon) {
+                       second_colon = strchr(first_colon+1, ':');
+                       if (second_colon &&
+                           (second_colon != first_colon))
+                               res = true;
+               }
+       }
+       _debug(ctx, "ipaddr=\"%s\" -> %u", ipaddr, res);
+       return res;
+}
+
+int _iscsi_iface_get_from_sysfs(struct iscsi_context *ctx, uint32_t host_id,
+                               uint32_t sid, char *iface_kern_id,
+                               struct iscsi_iface **iface)
+{
+       int rc = LIBISCSI_OK;
+       char *sysfs_se_dir_path = NULL;
+       char *sysfs_sh_dir_path = NULL;
+       char *sysfs_scsi_host_dir_path = NULL;
+       char proc_name[ISCSI_TRANSPORT_NAME_MAXLEN];
+       struct iscsi_iface **ifaces = NULL;
+       uint32_t iface_count = 0;
+       uint32_t i = 0;
+       struct iscsi_iface *tmp_iface = NULL;
+       bool bound_by_hwaddr = false;
+       bool bound_by_netdev = false;
+       bool matched = false;
+
+       assert(ctx != NULL);
+       assert(iface != NULL);
+
+       *iface = NULL;
+
+       if (sid != 0) {
+               _good(_asprintf(&sysfs_se_dir_path, "%s/session%" PRIu32,
+                               _ISCSI_SYS_SESSION_DIR, sid), rc, out);
+       }
+
+       _good(_asprintf(&sysfs_sh_dir_path, "%s/host%" PRIu32,
+                       _ISCSI_SYS_HOST_DIR, host_id),rc, out);
+
+       _good(_asprintf(&sysfs_scsi_host_dir_path, "%s/host%" PRIu32,
+                _SCSI_SYS_HOST_DIR, host_id), rc, out);
+
+       *iface = (struct iscsi_iface *) calloc(1, sizeof(struct iscsi_iface));
+       _alloc_null_check(ctx, *iface, rc, out);
+
+       _good(_sysfs_prop_get_str(ctx, sysfs_scsi_host_dir_path, "proc_name",
+                                 proc_name, sizeof(proc_name) / sizeof(char),
+                                 NULL /* raise error if failed */),
+             rc, out);
+
+       if (strncmp(proc_name, "iscsi_", strlen("iscsi_")) == 0)
+               _strncpy((*iface)->transport_name, proc_name + strlen("iscsi_"),
+                        sizeof((*iface)->transport_name) / sizeof(char));
+       else
+               _strncpy((*iface)->transport_name, proc_name,
+                       sizeof((*iface)->transport_name) / sizeof(char));
+
+       _good(_sysfs_prop_get_str(ctx, sysfs_sh_dir_path, "hwaddress",
+                                 (*iface)->hwaddress,
+                                 sizeof((*iface)->hwaddress) / sizeof(char),
+                                 DEFAULT_HWADDRESS),
+             rc, out);
+       if (strcmp((*iface)->hwaddress, DEFAULT_HWADDRESS) != 0)
+               bound_by_hwaddr = true;
+
+       _good(_sysfs_prop_get_str(ctx, sysfs_sh_dir_path, "netdev",
+                                 (*iface)->netdev,
+                                 sizeof((*iface)->netdev) / sizeof(char),
+                                 DEFAULT_NETDEV),
+             rc, out);
+       if (strcmp((*iface)->netdev, DEFAULT_NETDEV) != 0)
+               bound_by_netdev = true;
+
+       if (sysfs_se_dir_path)
+               _sysfs_prop_get_str(ctx, sysfs_se_dir_path, "initiatorname",
+                                   (*iface)->iname,
+                                   sizeof((*iface)->iname) / sizeof(char), "");
+       if (strcmp((*iface)->iname, "") == 0)
+               _good(_sysfs_prop_get_str(ctx, sysfs_sh_dir_path,
+                                         "initiatorname", (*iface)->iname,
+                                         sizeof((*iface)->iname) /
+                                         sizeof(char), ""),
+                     rc, out);
+
+       _good(_sysfs_prop_get_str(ctx, sysfs_sh_dir_path, "port_state",
+                                 (*iface)->port_state,
+                                 sizeof((*iface)->port_state) / sizeof(char),
+                                 "unknown"),
+             rc, out);
+
+       if (strcmp((*iface)->port_state, "Unknown!") == 0)
+               _strncpy((*iface)->port_state, "unknown",
+                        sizeof((*iface)->port_state) / sizeof(char));
+
+       _good(_sysfs_prop_get_str(ctx, sysfs_sh_dir_path, "port_speed",
+                                 (*iface)->port_speed,
+                                 sizeof((*iface)->port_speed) / sizeof(char),
+                                 "unknown"),
+             rc, out);
+
+       if (strncmp((*iface)->port_speed, "Unknown", strlen("Unknown")) == 0)
+               _strncpy((*iface)->port_speed, "unknown",
+                        sizeof((*iface)->port_speed) / sizeof(char));
+
+       if (sysfs_se_dir_path != NULL)
+           _sysfs_prop_get_str(ctx, sysfs_se_dir_path, "ifacename",
+                               (*iface)->name,
+                               sizeof((*iface)->name)/sizeof(char), "");
+
+       if (iface_kern_id != NULL) {
+               _good(_fill_hw_iface_from_sys(ctx, *iface, iface_kern_id),
+                     rc, out);
+       } else {
+               _good(_sysfs_prop_get_str(ctx, sysfs_sh_dir_path, "ipaddress",
+                                       (*iface)->ipaddress,
+                                       sizeof((*iface)->ipaddress) /
+                                       sizeof(char), DEFAULT_IPADDRESS),
+                     rc, out);
+               /* bnx2i does not create
+                * /sys/class/iscsi_iface/<iface_kernl_id>
+                * We need to use transport_name.hwaddress as iface name.
+                */
+               _debug(ctx, "HAHA: hwaddress %s", (*iface)->hwaddress);
+               if (bound_by_hwaddr)
+                       snprintf((*iface)->name,
+                                sizeof((*iface)->name)/sizeof(char),
+                                "%s.%s.%s.%u", (*iface)->transport_name,
+                                (*iface)->hwaddress,
+                                lib_ipaddr_is_ipv6(ctx, (*iface)->ipaddress) ? "ipv6" : "ipv4",
+                                (*iface)->iface_num);
+       }
+
+       if (strcmp((*iface)->name, "") == 0) {
+               /*
+                * Before 2.0.870, we only could bind by netdeivce or hwaddress,
+                * so we did a simple reverse lookup to go from sysfs info to
+                * the iface name. After 2.0.870 we added a lot of options to
+                * the iface binding so we added the ifacename to the kernel.
+                *
+                * Below codes are for older kernels that do not export the
+                * ifacename.  If the user was doing iscsi_tcp session binding
+                * we will find the iface by matching net info.
+                */
+
+               _good(iscsi_ifaces_get(ctx, &ifaces, &iface_count), rc, out);
+
+               for (i = 0; i < iface_count; ++i) {
+                       tmp_iface = ifaces[i];
+                       if ((bound_by_hwaddr == true) &&
+                           (strcmp(tmp_iface->hwaddress, (*iface)->hwaddress)
+                            == 0)) {
+                               _strncpy((*iface)->name, tmp_iface->name,
+                                        sizeof((*iface)->name)/sizeof(char));
+                               matched = true;
+                               break;
+                       }
+                       if ((bound_by_netdev == true) &&
+                           (strcmp(tmp_iface->netdev, (*iface)->netdev)
+                            == 0)) {
+                               _strncpy((*iface)->name, tmp_iface->name,
+                                        sizeof((*iface)->name)/sizeof(char));
+                               matched = true;
+                               break;
+                       }
+               }
+               if (!matched)
+                       _strncpy((*iface)->name, DEFAULT_IFACENAME,
+                                sizeof((*iface)->name) / sizeof(char));
+       }
+
+out:
+       if (rc != LIBISCSI_OK) {
+               iscsi_iface_free(*iface);
+               *iface = NULL;
+       }
+       free(sysfs_se_dir_path);
+       free(sysfs_sh_dir_path);
+       free(sysfs_scsi_host_dir_path);
+       iscsi_ifaces_free(ifaces, iface_count);
+       return rc;
+}
+
+/* create all ifaces for a host from sysfs */
+int _iscsi_ifaces_get_from_sysfs(struct iscsi_context *ctx, uint32_t host_id,
+                                struct iscsi_iface ***ifaces, uint32_t *iface_count)
+{
+       int rc = LIBISCSI_OK;
+       char **iface_kern_ids = NULL;
+       uint32_t i = 0;
+
+       assert(ctx != NULL);
+       assert(ifaces != NULL);
+
+       *ifaces = NULL;
+       *iface_count = 0;
+
+       _good(_iscsi_iface_kern_ids_of_host_id(ctx, host_id, &iface_kern_ids, iface_count),
+             rc, out);
+       if (*iface_count > 0) {
+               *ifaces = (struct iscsi_iface **) calloc(*iface_count,
+                                                        sizeof(struct iscsi_iface *));
+               _alloc_null_check(ctx, *ifaces, rc, out);
+               for (i = 0; i < *iface_count; i++) {
+                       _good(_iscsi_iface_get_from_sysfs(ctx, host_id, 0,
+                                       iface_kern_ids[i], &(*ifaces)[i]), rc, out);
+               }
+       } else {
+               /* if there's no iface exported in sysfs,
+                * we should still be able to create one record per host */
+               *ifaces = (struct iscsi_iface **) calloc(1, sizeof(struct iscsi_iface *));
+               _alloc_null_check(ctx, *ifaces, rc, out);
+               *iface_count = 1;
+               _good(_iscsi_iface_get_from_sysfs(ctx, host_id, 0, NULL, &(*ifaces)[0]), rc, out);
+       }
+out:
+       if (iface_kern_ids != NULL) {
+               for (i = 0; i < *iface_count; i++) {
+                       free(iface_kern_ids[i]);
+               }
+               free(iface_kern_ids);
+       }
+       if (rc != LIBISCSI_OK) {
+               iscsi_ifaces_free(*ifaces, *iface_count);
+               *ifaces = NULL;
+               *iface_count = 0;
+       }
+       return rc;
+}
+
+int iscsi_default_iface_setup(struct iscsi_context *ctx)
+{
+       int rc = LIBISCSI_OK;
+       char strerr_buff[_STRERR_BUFF_LEN];
+       int errno_save = 0;
+       struct _eth_if **eifs = NULL;
+       uint32_t eif_count = 0;
+       uint32_t i = 0;
+       uint32_t n = 0;
+       size_t j = 0;
+       struct _iscsi_net_drv *ind = NULL;
+       uint32_t *hids = NULL;
+       uint32_t hid_count = 0;
+       struct iscsi_iface **ifaces = NULL;
+       uint32_t iface_count = 0;
+       char *path = NULL;
+
+       assert(ctx != NULL);
+
+       _good(_idbm_lock(ctx), rc, out);
+
+       if ((access(IFACE_CONFIG_DIR, F_OK) != 0) &&
+           (mkdir(IFACE_CONFIG_DIR, 0770) != 0)) {
+               errno_save = errno;
+               _idbm_unlock(ctx);
+               _error(ctx, "Could not make %s folder(%d %s). "
+                      "HW/OFFLOAD iscsi may not be supported.",
+                      IFACE_CONFIG_DIR, errno_save,
+                      _strerror(errno_save, strerr_buff));
+               if (errno_save == EACCES)
+                       return LIBISCSI_ERR_ACCESS;
+               return LIBISCSI_ERR_BUG;
+       }
+       _idbm_unlock(ctx);
+
+       /* Load kernel driver for iSCSI offload cards, like cxgb3i */
+       _good(_eth_ifs_get(ctx, &eifs, &eif_count), rc, out);
+
+       for (i = 0; i < eif_count; ++i) {
+               for (j = 0;
+                    j < sizeof(_ISCSI_NET_DRVS)/sizeof(struct _iscsi_net_drv);
+                    ++j) {
+                       ind = &(_ISCSI_NET_DRVS[j]);
+                       if ((ind->net_driver_name == NULL) ||
+                           (strcmp(eifs[i]->driver_name,
+                                  ind->net_driver_name) != 0))
+                               continue;
+                       /*
+                       * iSCSI hardware offload for bnx2{,x} is only supported
+                       * if the iscsiuio executable is available.
+                       */
+                       if ((strcmp(eifs[i]->driver_name, "bnx2x") == 0) ||
+                           (strcmp(eifs[i]->driver_name, "bnx2") == 0)) {
+                               if (access(ISCSIUIO_PATH, F_OK) != 0) {
+                                       _debug(ctx, "iSCSI offload on %s(%s) "
+                                              "via %s is not supported due to "
+                                              "missing %s", eifs[i]->if_name,
+                                              eifs[i]->driver_name,
+                                              ind->iscsi_driver_name,
+                                              ISCSIUIO_PATH);
+                                       continue;
+                               }
+                       }
+
+                       if (_iscsi_transport_is_loaded(ind->transport_name))
+                               continue;
+
+                       _debug(ctx, "Loading kernel module %s for iSCSI "
+                              "offload on %s(%s)", ind->iscsi_driver_name,
+                              eifs[i]->if_name, eifs[i]->driver_name);
+                       _good(_load_kernel_module(ctx, ind->iscsi_driver_name),
+                             rc, out);
+               }
+       }
+
+       _good(_iscsi_hids_get(ctx, &hids, &hid_count), rc, out);
+       for (i = 0; i < hid_count; ++i) {
+               /* Create /etc/iscsi/ifaces/<iface_name> file if not found
+                */
+               _good(_iscsi_ifaces_get_from_sysfs(ctx, hids[i], &ifaces, &iface_count),
+                       rc, out);
+               for (n = 0; n < iface_count; n++) {
+                       if ( ! iscsi_is_default_iface(ifaces[n])) {
+                               _good(_asprintf(&path, "%s/%s", IFACE_CONFIG_DIR,
+                                               ifaces[n]->name), rc, out);
+                               if (access(path, F_OK) != 0)
+                                       rc = _iface_conf_write(ctx, ifaces[n]);
+                               free(path);
+                               path = NULL;
+                       }
+                       iscsi_iface_free(ifaces[n]);
+                       ifaces[n] = NULL;
+                       if (rc != LIBISCSI_OK)
+                               goto out;
+               }
+               free(ifaces);
+               ifaces = NULL;
+       }
+
+out:
+       if (ifaces != NULL) {
+               for (i = 0; i < iface_count; i++)
+                       free(ifaces[i]);
+               free(ifaces);
+       }
+       _eth_ifs_free(eifs, eif_count);
+       free(path);
+       free(hids);
+       return rc;
+}
+
+static int _load_kernel_module(struct iscsi_context *ctx, const char *drv_name)
+{
+       struct kmod_ctx *kctx = NULL;
+       struct kmod_module *mod = NULL;
+       int rc = LIBISCSI_OK;
+
+       kctx = kmod_new(NULL, NULL);
+       _alloc_null_check(ctx, kctx, rc, out);
+
+       kmod_load_resources(kctx);
+
+       if (kmod_module_new_from_name(kctx, drv_name, &mod)) {
+               _error(ctx, "Failed to load module %s.", drv_name);
+               rc = LIBISCSI_ERR_TRANS_NOT_FOUND;
+               goto out;
+       }
+
+       if (kmod_module_probe_insert_module(mod, KMOD_PROBE_APPLY_BLACKLIST,
+                                           NULL, NULL, NULL, NULL)) {
+               _error(ctx, "Could not insert module %s. Kmod error %d",
+                      drv_name, rc);
+               rc = LIBISCSI_ERR_TRANS_NOT_FOUND;
+       }
+       kmod_module_unref(mod);
+
+out:
+       if (kctx != NULL)
+               kmod_unref(kctx);
+       return rc;
+}
+
+static int _iface_conf_write(struct iscsi_context *ctx,
+                            struct iscsi_iface *iface)
+{
+       char *conf_path = NULL;
+       char strerr_buff[_STRERR_BUFF_LEN];
+       int errno_save = 0;
+       FILE *f = NULL;
+       int rc = 0;
+
+       if (iscsi_is_default_iface(iface)) {
+               _error(ctx, "iface %s is not a special interface and "
+                      "is not stored in %s", iface->name, IFACE_CONFIG_DIR);
+               return LIBISCSI_ERR_INVAL;
+       }
+
+       _good(_idbm_lock(ctx), rc, out);
+
+       _good(_asprintf(&conf_path, "%s/%s", IFACE_CONFIG_DIR,
+                       iface->name), rc, out);
+       _debug(ctx, "Creating iSCSI interface configuration file '%s' "
+              "using kernel information", conf_path);
+       f = fopen(conf_path, "w");
+       errno_save = errno;
+       if (!f) {
+               _error(ctx, "Failed to open %s using write mode: %d %s",
+                      conf_path, errno_save,
+                      _strerror(errno_save, strerr_buff));
+               rc = LIBISCSI_ERR_IDBM;
+               goto out;
+       }
+
+       _idbm_iface_print(iface, f);
+
+       _idbm_unlock(ctx);
+
+out:
+       free(conf_path);
+       if (f != NULL)
+               fclose(f);
+       return rc;
+}
+
+// mimic of iscsi_sysfs_read_iface() in iscsi_sysfs.c.
+static int _fill_hw_iface_from_sys(struct iscsi_context *ctx,
+                                  struct iscsi_iface *iface,
+                                  const char *iface_kern_id)
+{
+       int rc = LIBISCSI_OK;
+       char *sysfs_iface_dir_path = NULL;
+       uint32_t tmp_host_no = 0;
+       uint32_t iface_num = 0;
+       int iface_type = 0;
+
+       assert(ctx != NULL);
+       assert(iface != NULL);
+       assert(iface_kern_id != NULL);
+
+       _good(_asprintf(&sysfs_iface_dir_path, "%s/%s", _ISCSI_SYS_IFACE_DIR,
+                       iface_kern_id), rc, out);
+
+       _good(_sysfs_prop_get_str(ctx, sysfs_iface_dir_path,
+                                 "ipaddress",
+                                 iface->ipaddress,
+                                 sizeof(iface->ipaddress) /
+                                 sizeof(char), DEFAULT_IPADDRESS),
+                     rc, out);
+
+       if (strncmp(iface_kern_id, "ipv4", strlen("ipv4")) == 0) {
+               iface->is_ipv6 = false;
+               _sysfs_prop_get_str(ctx, sysfs_iface_dir_path,
+                                   "bootproto", iface->bootproto,
+                                   sizeof(iface->bootproto) / sizeof(char),
+                                   "");
+               _sysfs_prop_get_str(ctx, sysfs_iface_dir_path, "gateway",
+                                   iface->gateway,
+                                   sizeof(iface->gateway) / sizeof(char),
+                                   "");
+               _sysfs_prop_get_str(ctx, sysfs_iface_dir_path, "subnet",
+                                   iface->subnet_mask,
+                                   sizeof(iface->subnet_mask) / sizeof(char),
+                                   "");
+               _sysfs_prop_get_str(ctx, sysfs_iface_dir_path,
+                                   "dhcp_alt_client_id_en",
+                                   iface->dhcp_alt_client_id,
+                                   sizeof(iface->dhcp_alt_client_id) /
+                                   sizeof(char),
+                                   "");
+               _sysfs_prop_get_str(ctx, sysfs_iface_dir_path,
+                                   "dhcp_alt_client_id",
+                                   iface->dhcp_alt_client_id,
+                                   sizeof(iface->dhcp_alt_client_id) /
+                                   sizeof(char),
+                                   "");
+               _sysfs_prop_get_str(ctx, sysfs_iface_dir_path,
+                                   "dhcp_dns_address_en", iface->dhcp_dns,
+                                   sizeof(iface->dhcp_dns) / sizeof(char), "");
+               _sysfs_prop_get_str(ctx, sysfs_iface_dir_path,
+                                   "dhcp_learn_iqn_en", iface->dhcp_learn_iqn,
+                                   sizeof(iface->dhcp_learn_iqn) /
+                                   sizeof(char), "");
+               _sysfs_prop_get_str(ctx, sysfs_iface_dir_path,
+                                   "dhcp_req_vendor_id_en",
+                                   iface->dhcp_req_vendor_id_state,
+                                   sizeof(iface->dhcp_req_vendor_id_state) /
+                                   sizeof(char), "");
+               _sysfs_prop_get_str(ctx, sysfs_iface_dir_path,
+                                   "dhcp_use_vendor_id_en",
+                                   iface->dhcp_vendor_id_state,
+                                   sizeof(iface->dhcp_vendor_id_state) /
+                                   sizeof(char), "");
+               _sysfs_prop_get_str(ctx, sysfs_iface_dir_path,
+                                   "dhcp_vendor_id", iface->dhcp_vendor_id,
+                                   sizeof(iface->dhcp_vendor_id) /
+                                   sizeof(char), "");
+               _sysfs_prop_get_str(ctx, sysfs_iface_dir_path,
+                                   "dhcp_slp_da_info_en", iface->dhcp_slp_da,
+                                   sizeof(iface->dhcp_slp_da) / sizeof(char),
+                                   "");
+               _sysfs_prop_get_str(ctx, sysfs_iface_dir_path,
+                                   "fragment_disable", iface->fragmentation,
+                                   sizeof(iface->fragmentation) / sizeof(char),
+                                   "");
+               _sysfs_prop_get_str(ctx, sysfs_iface_dir_path,
+                                   "grat_arp_en", iface->gratuitous_arp,
+                                   sizeof(iface->gratuitous_arp) /
+                                   sizeof(char), "");
+               _sysfs_prop_get_str(ctx, sysfs_iface_dir_path,
+                                   "incoming_forwarding_en",
+                                   iface->incoming_forwarding,
+                                   sizeof(iface->incoming_forwarding) /
+                                   sizeof(char), "");
+               _sysfs_prop_get_str(ctx, sysfs_iface_dir_path, "tos_en",
+                                   iface->tos_state, sizeof(iface->tos_state) /
+                                   sizeof(char), "");
+               _sysfs_prop_get_u8(ctx, sysfs_iface_dir_path, "tos",
+                                  &iface->tos, 0, true);
+               _sysfs_prop_get_u8(ctx, sysfs_iface_dir_path, "ttl",
+                                  &iface->ttl, 0, true);
+       } else {
+               iface->is_ipv6 = true;
+               _sysfs_prop_get_str(ctx, sysfs_iface_dir_path, "ipaddr_autocfg",
+                                   iface->ipv6_autocfg,
+                                   sizeof(iface->ipv6_autocfg) / sizeof(char),
+                                   "");
+               _sysfs_prop_get_str(ctx, sysfs_iface_dir_path,
+                                   "link_local_addr", iface->ipv6_linklocal,
+                                   sizeof(iface->ipv6_linklocal) /
+                                   sizeof(char), "");
+               _sysfs_prop_get_str(ctx, sysfs_iface_dir_path,
+                                   "link_local_autocfg",
+                                   iface->linklocal_autocfg,
+                                   sizeof(iface->linklocal_autocfg) /
+                                   sizeof(char), "");
+               _sysfs_prop_get_str(ctx, sysfs_iface_dir_path,
+                                   "router_addr", iface->ipv6_router,
+                                   sizeof(iface->ipv6_router) / sizeof(char),
+                                   "");
+               _sysfs_prop_get_str(ctx, sysfs_iface_dir_path,
+                                   "router_state", iface->router_autocfg,
+                                   sizeof(iface->router_autocfg) /
+                                   sizeof(char), "");
+               _sysfs_prop_get_str(ctx, sysfs_iface_dir_path,
+                                   "grat_neighbor_adv_en",
+                                   iface->gratuitous_neighbor_adv,
+                                   sizeof(iface->gratuitous_neighbor_adv) /
+                                   sizeof(char), "");
+               _sysfs_prop_get_str(ctx, sysfs_iface_dir_path, "mld_en",
+                                   iface->mld, sizeof(iface->mld) /
+                                   sizeof(char), "");
+               _sysfs_prop_get_u8(ctx, sysfs_iface_dir_path,
+                                  "dup_addr_detect_cnt",
+                                  &iface->dup_addr_detect_cnt, 0, true);
+               _sysfs_prop_get_u8(ctx, sysfs_iface_dir_path, "hop_limit",
+                                  &iface->hop_limit, 0, true);
+               _sysfs_prop_get_u32(ctx, sysfs_iface_dir_path,
+                                   "flow_label", &iface->flow_label, 0, true);
+               _sysfs_prop_get_u32(ctx, sysfs_iface_dir_path,
+                                   "nd_reachable_tmo",
+                                   &iface->nd_reachable_tmo, 0, true);
+               _sysfs_prop_get_u32(ctx, sysfs_iface_dir_path, "nd_rexmit_time",
+                                   &iface->nd_rexmit_time, 0, true);
+               _sysfs_prop_get_u32(ctx, sysfs_iface_dir_path, "nd_stale_tmo",
+                                   &iface->nd_stale_tmo, 0, true);
+               _sysfs_prop_get_u32(ctx, sysfs_iface_dir_path,
+                                   "router_adv_link_mtu",
+                                   &iface->router_adv_link_mtu, 0, true);
+               _sysfs_prop_get_u32(ctx, sysfs_iface_dir_path, "traffic_class",
+                                   &iface->traffic_class, 0, true);
+       }
+
+       _sysfs_prop_get_u16(ctx, sysfs_iface_dir_path, "port", &iface->port, 0,
+                           true);
+       _sysfs_prop_get_u16(ctx, sysfs_iface_dir_path, "mtu", &iface->mtu, 0,
+                           true);
+       _sysfs_prop_get_u16(ctx, sysfs_iface_dir_path, "vlan_id",
+                           &iface->vlan_id, UINT16_MAX, true);
+       _sysfs_prop_get_u8(ctx, sysfs_iface_dir_path, "vlan_priority",
+                           &iface->vlan_priority, UINT8_MAX, true);
+       _sysfs_prop_get_str(ctx, sysfs_iface_dir_path, "vlan_enabled",
+                           iface->vlan_state, sizeof(iface->vlan_state) /
+                           sizeof(char), "");
+       _sysfs_prop_get_str(ctx, sysfs_iface_dir_path, "enabled", iface->state,
+                           sizeof(iface->state) / sizeof(char), "");
+       _sysfs_prop_get_str(ctx, sysfs_iface_dir_path, "delayed_ack_en",
+                           iface->delayed_ack,
+                           sizeof(iface->delayed_ack) / sizeof(char), "");
+       _sysfs_prop_get_str(ctx, sysfs_iface_dir_path, "tcp_nagle_disable",
+                           iface->nagle, sizeof(iface->nagle) / sizeof(char),
+                           "");
+       _sysfs_prop_get_str(ctx, sysfs_iface_dir_path, "tcp_wsf_disable",
+                           iface->tcp_wsf_state,
+                           sizeof(iface->tcp_wsf_state) / sizeof(char), "");
+       _sysfs_prop_get_u8(ctx, sysfs_iface_dir_path, "tcp_wsf",
+                          &iface->tcp_wsf, 0, true);
+       _sysfs_prop_get_u8(ctx, sysfs_iface_dir_path, "tcp_timer_scale",
+                          &iface->tcp_timer_scale, 0, true);
+       _sysfs_prop_get_str(ctx, sysfs_iface_dir_path, "tcp_timestamp_en",
+                           iface->tcp_timestamp,
+                           sizeof(iface->tcp_timestamp) / sizeof(char), "");
+       _sysfs_prop_get_str(ctx, sysfs_iface_dir_path, "redirect_en",
+                           iface->redirect,
+                           sizeof(iface->redirect) / sizeof(char), "");
+       _sysfs_prop_get_u16(ctx, sysfs_iface_dir_path, "def_taskmgmt_tmo",
+                           &iface->def_task_mgmt_tmo, 0, true);
+       _sysfs_prop_get_str(ctx, sysfs_iface_dir_path, "header_digest",
+                           iface->header_digest,
+                           sizeof(iface->header_digest) / sizeof(char), "");
+       _sysfs_prop_get_str(ctx, sysfs_iface_dir_path, "data_digest",
+                           iface->data_digest,
+                           sizeof(iface->data_digest) / sizeof(char), "");
+       _sysfs_prop_get_str(ctx, sysfs_iface_dir_path, "immediate_data",
+                           iface->immediate_data,
+                           sizeof(iface->immediate_data) / sizeof(char), "");
+       _sysfs_prop_get_str(ctx, sysfs_iface_dir_path, "initial_r2t",
+                           iface->initial_r2t,
+                           sizeof(iface->initial_r2t) / sizeof(char), "");
+       _sysfs_prop_get_str(ctx, sysfs_iface_dir_path, "data_seq_in_order",
+                           iface->data_seq_inorder,
+                           sizeof(iface->data_seq_inorder) / sizeof(char),
+                           "");
+       _sysfs_prop_get_str(ctx, sysfs_iface_dir_path, "data_pdu_in_order",
+                           iface->data_pdu_inorder,
+                           sizeof(iface->data_pdu_inorder) / sizeof(char), "");
+       _sysfs_prop_get_u8(ctx, sysfs_iface_dir_path, "erl", &iface->erl, 0,
+                           true);
+       _sysfs_prop_get_u32(ctx, sysfs_iface_dir_path, "max_recv_dlength",
+                           &iface->max_recv_dlength, 0, true);
+       _sysfs_prop_get_u32(ctx, sysfs_iface_dir_path, "first_burst_len",
+                           &iface->first_burst_len, 0, true);
+       _sysfs_prop_get_u16(ctx, sysfs_iface_dir_path, "max_outstanding_r2t",
+                           &iface->max_out_r2t, 0, true);
+       _sysfs_prop_get_u32(ctx, sysfs_iface_dir_path, "max_burst_len",
+                           &iface->max_burst_len, 0, true);
+       _sysfs_prop_get_str(ctx, sysfs_iface_dir_path, "chap_auth",
+                           iface->chap_auth,
+                           sizeof(iface->chap_auth) / sizeof(char), "");
+       _sysfs_prop_get_str(ctx, sysfs_iface_dir_path, "bidi_chap",
+                           iface->bidi_chap,
+                           sizeof(iface->bidi_chap) / sizeof(char), "");
+       _sysfs_prop_get_str(ctx, sysfs_iface_dir_path, "strict_login_comp_en",
+                           iface->strict_login_comp,
+                           sizeof(iface->strict_login_comp) / sizeof(char),
+                           "");
+       _sysfs_prop_get_str(ctx, sysfs_iface_dir_path,
+                           "discovery_auth_optional",
+                           iface->discovery_auth,
+                           sizeof(iface->discovery_auth) / sizeof(char), "");
+       _sysfs_prop_get_str(ctx, sysfs_iface_dir_path,
+                           "discovery_logout",
+                           iface->discovery_logout,
+                           sizeof(iface->discovery_logout) / sizeof(char), "");
+
+       if (sscanf(iface_kern_id, "ipv%d-iface-%" SCNu32 "-%" SCNu32,
+                  &iface_type, &tmp_host_no, &iface_num) == 3)
+               iface->iface_num = iface_num;
+
+       snprintf(iface->name, sizeof(iface->name)/sizeof(char),
+                "%s.%s.%s.%u", iface->transport_name,
+                iface->hwaddress, iface->is_ipv6 ?  "ipv6" : "ipv4",
+                iface->iface_num);
+
+out:
+       free(sysfs_iface_dir_path);
+       return rc;
+}
+
+int iscsi_ifaces_get(struct iscsi_context *ctx, struct iscsi_iface ***ifaces,
+                    uint32_t *iface_count)
+{
+       int rc = LIBISCSI_OK;
+       struct dirent **namelist = NULL;
+       int n = 0;
+       size_t i = 0;
+       struct iscsi_iface *iface = NULL;
+       int j = 0;
+       uint32_t real_iface_count = 0;
+
+       assert(ctx != NULL);
+       assert(ifaces != NULL);
+       assert(iface_count != NULL);
+
+       *ifaces = NULL;
+       *iface_count = 0;
+
+       _good(_idbm_lock(ctx), rc, out);
+
+       _good(_scandir(ctx, IFACE_CONFIG_DIR, &namelist, &n), rc, out);
+       _debug(ctx, "Got %d iface from %s folder", n, IFACE_CONFIG_DIR);
+       *iface_count = (n + sizeof(_DEFAULT_IFACES)/sizeof(struct iscsi_iface))
+               & UINT32_MAX;
+       *ifaces = (struct iscsi_iface **) calloc(*iface_count,
+                                               sizeof(struct iscsi_iface *));
+       _alloc_null_check(ctx, *ifaces, rc, out);
+
+       for (j = 0; j < n; ++j) {
+               _good(_idbm_iface_get(ctx, namelist[j]->d_name, &iface),
+                     rc, out);
+               if (iface != NULL) {
+                       (*ifaces)[real_iface_count++] = iface;
+               }
+       }
+
+       for (i = 0; i < sizeof(_DEFAULT_IFACES)/sizeof(struct iscsi_iface);
+            ++i) {
+               iface = calloc(1, sizeof(struct iscsi_iface));
+               _alloc_null_check(ctx, iface, rc, out);
+               (*ifaces)[real_iface_count++] = iface;
+               memcpy(iface, &_DEFAULT_IFACES[i], sizeof(struct iscsi_iface));
+       }
+
+       *iface_count = real_iface_count;
+
+out:
+       _scandir_free(namelist, n);
+       _idbm_unlock(ctx);
+       if (rc != LIBISCSI_OK) {
+               iscsi_ifaces_free(*ifaces, *iface_count);
+               *ifaces = NULL;
+               *iface_count = 0;
+       }
+       return rc;
+}
+
+void iscsi_ifaces_free(struct iscsi_iface **ifaces, uint32_t iface_count)
+{
+       uint32_t i = 0;
+
+       if ((ifaces == NULL) || (iface_count == 0))
+               return;
+
+       for (i = 0; i < iface_count; ++i)
+               iscsi_iface_free(ifaces[i]);
+       free (ifaces);
+}
+
+static bool _iface_is_bound_by_hwaddr(struct iscsi_iface *iface)
+{
+       if (iface && strlen(iface->hwaddress) &&
+           strcmp(iface->hwaddress, DEFAULT_HWADDRESS))
+               return true;
+       return false;
+}
+
+static bool _iface_is_bound_by_netdev(struct iscsi_iface *iface)
+{
+       if (iface && strlen(iface->netdev) &&
+          strcmp(iface->netdev, DEFAULT_NETDEV))
+               return true;
+       return false;
+}
+
+bool _iface_is_valid(struct iscsi_iface *iface)
+{
+       if (!iface)
+               return false;
+
+       if (strlen(iface->name) == 0)
+               return false;
+
+       if (strlen(iface->transport_name) == 0)
+               return false;
+
+       if (_iface_is_bound_by_hwaddr(iface))
+               return true;
+
+       if (_iface_is_bound_by_netdev(iface))
+               return true;
+
+       /* bound by transport name */
+       return true;
+}
+
+bool iscsi_is_default_iface(struct iscsi_iface *iface)
+{
+       size_t i = 0;
+       for (; i < sizeof(_DEFAULT_IFACES)/sizeof(struct iscsi_iface); ++i) {
+               if (strcmp(iface->name, _DEFAULT_IFACES[i].name) == 0)
+                       return true;
+       }
+       return false;
+}
+
+const char *iscsi_iface_dump_config(struct iscsi_iface *iface)
+{
+       FILE *f = NULL;
+       char *buff = NULL;
+
+       assert(iface != NULL);
+
+       buff = calloc(1, IDBM_DUMP_SIZE);
+       if (buff == NULL)
+               return NULL;
+
+       f = fmemopen(buff, IDBM_DUMP_SIZE - 1, "w");
+       if (f == NULL) {
+               free(buff);
+               return NULL;
+       }
+
+       _idbm_iface_print(iface, f);
+
+       fclose(f);
+
+       return buff;
+}
+
+void iscsi_iface_print_config(struct iscsi_iface *iface)
+{
+       assert(iface != NULL);
+       _idbm_iface_print(iface, stdout);
+}
+
+int iscsi_iface_get(struct iscsi_context *ctx, const char *iface_name,
+                   struct iscsi_iface **iface)
+{
+       int rc = LIBISCSI_OK;
+       assert(ctx != NULL);
+       assert(iface_name != NULL);
+       assert(strlen(iface_name) != 0);
+       assert(iface != NULL);
+
+       *iface = NULL;
+
+       size_t i = 0;
+       for (; i < sizeof(_DEFAULT_IFACES)/sizeof(struct iscsi_iface); ++i) {
+               if (strcmp(iface_name, _DEFAULT_IFACES[i].name) == 0) {
+                       *iface = calloc(1, sizeof(struct iscsi_iface));
+                       _alloc_null_check(ctx, *iface, rc, out);
+                       memcpy(*iface, &_DEFAULT_IFACES[i],
+                              sizeof(struct iscsi_iface));
+                       goto out;
+               }
+       }
+
+       rc = _idbm_lock(ctx);
+       if (rc != LIBISCSI_OK)
+               return rc;
+
+       rc = _idbm_iface_get(ctx, iface_name, iface);
+       if (*iface == NULL)
+               rc = LIBISCSI_ERR_IDBM;
+
+       _idbm_unlock(ctx);
+
+out:
+       return rc;
+}
+
+void iscsi_iface_free(struct iscsi_iface *iface)
+{
+       free(iface);
+}
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/iface.h b/pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/iface.h
new file mode 100644 (file)
index 0000000..f20ea13
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2017-2018 Red Hat, Inc.
+ *
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Gris Ge <fge@redhat.com>
+ */
+
+#ifndef __ISCSI_USR_IFACE_H__
+#define __ISCSI_USR_IFACE_H__
+
+#include "libopeniscsiusr/libopeniscsiusr_common.h"
+#include <stdint.h>
+#include <netdb.h>
+#include <net/if.h>
+
+#define VALUE_MAXVAL   256   /* the maximum length of 223 bytes in the RFC. */
+/* ^ VALUE_MAXVAL is copied from usr/idbm.h
+ * The RFC 3720 only said:
+ *     If not otherwise specified, the maximum length of a simple-value (not
+ *     its encoded representation) is 255 bytes, not including the delimiter
+ *     (comma or zero byte).
+ */
+
+#define ISCSI_MAX_IFACE_LEN                    65
+#define ISCSI_TRANSPORT_NAME_MAXLEN            16
+#define ISCSI_MAX_STR_LEN                      80
+#define ISCSI_HWADDRESS_BUF_SIZE               18
+#define TARGET_NAME_MAXLEN                     VALUE_MAXVAL
+/* ^ TODO(Gris Ge): Above 5 constants are copy from usr/config.h, need to
+ *                 verify them in linux kernel code
+ */
+
+struct iscsi_iface {
+       /* iscsi iface record name */
+       char                    name[ISCSI_MAX_IFACE_LEN];
+       uint32_t                iface_num;
+       /* network layer iface name (eth0) */
+       char                    netdev[IFNAMSIZ];
+       char                    ipaddress[NI_MAXHOST];
+       char                    subnet_mask[NI_MAXHOST];
+       char                    gateway[NI_MAXHOST];
+       char                    bootproto[ISCSI_MAX_STR_LEN];
+       char                    ipv6_linklocal[NI_MAXHOST];
+       char                    ipv6_router[NI_MAXHOST];
+       char                    ipv6_autocfg[NI_MAXHOST];
+       char                    linklocal_autocfg[NI_MAXHOST];
+       char                    router_autocfg[NI_MAXHOST];
+       uint8_t                 prefix_len;
+       /* ^ prefix_len is removed, as linux kernel has no such sysfs property
+        * and there is no actual code in usr/ folder set this property
+        *
+        * Added back, we need to be backward compatible with iface records
+        * created by older tools. Look at fixing code to ignore in record
+        * files instead? - cleech
+        */
+       uint16_t                vlan_id;
+       uint8_t                 vlan_priority;
+       char                    vlan_state[ISCSI_MAX_STR_LEN];
+       char                    state[ISCSI_MAX_STR_LEN]; /* 0 = disable,
+                                                          * 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 infiniband
+        */
+       char                    hwaddress[ISCSI_HWADDRESS_BUF_SIZE];
+       char                    transport_name[ISCSI_TRANSPORT_NAME_MAXLEN];
+       /*
+        * This is only used for boot now, but the iser guys
+        * can use this for their virtualization idea.
+        */
+       char                    alias[TARGET_NAME_MAXLEN + 1];
+       char                    iname[TARGET_NAME_MAXLEN + 1];
+       bool                    is_ipv6;
+};
+
+__DLL_LOCAL int _iscsi_iface_get_from_sysfs(struct iscsi_context *ctx,
+                                           uint32_t host_id, uint32_t sid,
+                                           char *iface_kern_id,
+                                           struct iscsi_iface **iface);
+
+__DLL_LOCAL bool _iface_is_valid(struct iscsi_iface *iface);
+
+#endif /* End of __ISCSI_USR_IFACE_H__ */
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/libopeniscsiusr.pc.in b/pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/libopeniscsiusr.pc.in
new file mode 100644 (file)
index 0000000..6bbee47
--- /dev/null
@@ -0,0 +1,9 @@
+includedir=__INCLUDE_DIR__
+libdir=__LIB_DIR__
+
+Name: libopeniscsiusr
+Version: __VERSION__
+Description: iSCSI userspace library
+Requires:
+Libs: -L${libdir} -lopeniscsiusr
+Cflags: -I${includedir}
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/libopeniscsiusr/libopeniscsiusr.h b/pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/libopeniscsiusr/libopeniscsiusr.h
new file mode 100644 (file)
index 0000000..a29d5b1
--- /dev/null
@@ -0,0 +1,549 @@
+/*
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Gris Ge <fge@redhat.com>
+ */
+#ifndef _LIB_OPEN_ISCSI_USR_H_
+#define _LIB_OPEN_ISCSI_USR_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <stdarg.h>
+#include <stdbool.h>
+
+#include "libopeniscsiusr_common.h"
+#include "libopeniscsiusr_session.h"
+#include "libopeniscsiusr_iface.h"
+#include "libopeniscsiusr_node.h"
+
+/**
+ * iscsi_log_priority_str() - Convert log priority to string.
+ *
+ * Convert log priority to string (const char *).
+ *
+ * @priority:
+ *     int. Log priority.
+ *
+ * Return:
+ *     const char *. Please don't free returned pointer. Valid string are:
+ *
+ *     * "ERROR" for LIBISCSI_LOG_PRIORITY_ERROR
+ *
+ *     * "WARN"  for LIBISCSI_LOG_PRIORITY_WARNING
+ *
+ *     * "INFO"  for LIBISCSI_LOG_PRIORITY_INFO
+ *
+ *     * "DEBUG" for LIBISCSI_LOG_PRIORITY_DEBUG
+ *
+ *     * "Invalid argument" for invalid log priority.
+ */
+__DLL_EXPORT const char *iscsi_log_priority_str(int priority);
+
+/**
+ * iscsi_strerror() - Convert error code to string.
+ *
+ * Convert error code (int) to string (const char *):
+ *
+ *     * LIBISCSI_OK -- "OK"
+ *
+ *     * LIBISCSI_ERR_BUG -- "BUG of libopeniscsiusr library"
+ *
+ *     * LIBISCSI_ERR_SESS_NOT_FOUND - "Specified iSCSI session not found"
+ *
+ *     * LIBISCSI_ERR_ACCESS - "Permission deny"
+ *
+ *     * LIBISCSI_ERR_NOMEM - "Out of memory"
+ *
+ *     * LIBISCSI_ERR_SYSFS_LOOKUP - "Could not lookup object in sysfs"
+ *
+ *     * Other invalid error number -- "Invalid argument"
+ *
+ * @rc:
+ *     int. Return code by libiscsiur functions. When provided error code is
+ *     not a valid error code, return "Invalid argument".
+ *
+ * Return:
+ *     const char *. The meaning of provided error code. Don't free returned
+ *     pointer.
+ */
+__DLL_EXPORT const char *iscsi_strerror(int rc);
+
+/**
+ * iscsi_context_new() - Create struct iscsi_context.
+ *
+ * The default logging level (LIBISCSI_LOG_PRIORITY_DEFAULT) is
+ * LIBISCSI_LOG_PRIORITY_WARNING which means only warning and error message will
+ * be forward to log handler function.  The default log handler function will
+ * print log message to STDERR, to change so, please use
+ * iscsi_context_log_func_set() to set your own log handler, check manpage
+ * libopeniscsiusr.h(3) for detail.
+ *
+ * Return:
+ *     Pointer of 'struct iscsi_context'. Should be freed by
+ *     iscsi_context_free().
+ */
+__DLL_EXPORT struct iscsi_context *iscsi_context_new(void);
+
+/**
+ * iscsi_context_free() - Release the memory of struct iscsi_context.
+ *
+ * Release the memory of struct iscsi_context, but the userdata memory defined
+ * via iscsi_context_userdata_set() will not be touched.
+ *
+ * @ctx:
+ *     Pointer of 'struct iscsi_context'.
+ * Return:
+ *     void
+ */
+__DLL_EXPORT void iscsi_context_free(struct iscsi_context *ctx);
+
+/**
+ * iscsi_context_log_priority_set() - Set log priority.
+ *
+ *
+ * When library generates log message, only equal or more important(less value)
+ * message will be forwarded to log handler function. Valid log priority values
+ * are:
+ *
+ *     * LIBISCSI_LOG_PRIORITY_ERROR -- 3
+ *
+ *     * LIBISCSI_LOG_PRIORITY_WARNING -- 4
+ *
+ *     * LIBISCSI_LOG_PRIORITY_INFO -- 6
+ *
+ *     * LIBISCSI_LOG_PRIORITY_DEBUG -- 7
+ *
+ * @ctx:
+ *     Pointer of 'struct iscsi_context'.
+ *     If this pointer is NULL, your program will be terminated by assert.
+ *
+ * @priority:
+ *     int, log priority.
+ *
+ * Return:
+ *     void
+ */
+__DLL_EXPORT void iscsi_context_log_priority_set(struct iscsi_context *ctx,
+                                                int priority);
+
+/**
+ * iscsi_context_log_priority_get() - Get log priority.
+ *
+ * Retrieve current log priority. Valid log priority values are:
+ *
+ *     * LIBISCSI_LOG_PRIORITY_ERROR -- 3
+ *
+ *     * LIBISCSI_LOG_PRIORITY_WARNING -- 4
+ *
+ *     * LIBISCSI_LOG_PRIORITY_INFO -- 5
+ *
+ *     * LIBISCSI_LOG_PRIORITY_DEBUG -- 7
+ *
+ * @ctx:
+ *     Pointer of 'struct iscsi_context'.
+ *     If this pointer is NULL, your program will be terminated by assert.
+ *
+ * Return:
+ *     int, log priority.
+ */
+__DLL_EXPORT int iscsi_context_log_priority_get(struct iscsi_context *ctx);
+
+/**
+ * iscsi_context_log_func_set() - Set log handler function.
+ *
+ * Set custom log handler. The log handler will be invoked when log message
+ * is equal or more important(less value) than log priority setting.
+ * Please check manpage libopeniscsiusr.h(3) for detail usage.
+ *
+ * @ctx:
+ *     Pointer of 'struct iscsi_context'.
+ *     If this pointer is NULL, your program will be terminated by assert.
+ * @log_func:
+ *     Pointer of log handler function.
+ *
+ * Return:
+ *     void
+ */
+__DLL_EXPORT void iscsi_context_log_func_set
+       (struct iscsi_context *ctx,
+        void (*log_func) (struct iscsi_context *ctx, int priority,
+                          const char *file, int line, const char *func_name,
+                          const char *format, va_list args));
+
+/**
+ * iscsi_context_userdata_set() - Set user data pointer.
+ *
+ * Store user data pointer into 'struct iscsi_context'.
+ *
+ * @ctx:
+ *     Pointer of 'struct iscsi_context'.
+ *     If this pointer is NULL, your program will be terminated by assert.
+ * @userdata:
+ *     Pointer of user defined data.
+ *
+ * Return:
+ *     void
+ */
+__DLL_EXPORT void iscsi_context_userdata_set(struct iscsi_context *ctx,
+                                            void *userdata);
+
+/**
+ * iscsi_context_userdata_get() - Get user data pointer.
+ *
+ * Retrieve user data pointer from 'struct iscsi_context'.
+ *
+ * @ctx:
+ *     Pointer of 'struct iscsi_context'.
+ *     If this pointer is NULL, your program will be terminated by assert.
+ *
+ * Return:
+ *     void *. Pointer of user defined data.
+ */
+__DLL_EXPORT void *iscsi_context_userdata_get(struct iscsi_context *ctx);
+
+/**
+ * iscsi_sessions_get() - Retrieve all iSCSI sessions.
+ *
+ * Retrieves all iSCSI sessions. For the properties of 'struct iscsi_session',
+ * please refer to the functions defined in 'libopeniscsiusr_session.h' file.
+ *
+ * @ctx:
+ *     Pointer of 'struct iscsi_context'.
+ *     If this pointer is NULL, your program will be terminated by assert.
+ * @ses:
+ *     Output pointer of 'struct iscsi_session' pointer array. Its memory
+ *     should be freed by iscsi_sessions_free().
+ *     If this pointer is NULL, your program will be terminated by assert.
+ * @se_count:
+ *     Output pointer of uint32_t. Will store the size of
+ *     'struct iscsi_session' pointer array.
+ *
+ * Return:
+ *     int. Valid error codes are:
+ *
+ *     * LIBISCSI_OK
+ *
+ *     * LIBISCSI_ERR_BUG
+ *
+ *     * LIBISCSI_ERR_NOMEM
+ *
+ *     * LIBISCSI_ERR_ACCESS
+ *
+ *     * LIBISCSI_ERR_SYSFS_LOOKUP
+ *
+ *     Error number could be converted to string by iscsi_strerror().
+ */
+__DLL_EXPORT int iscsi_sessions_get(struct iscsi_context *ctx,
+                                   struct iscsi_session ***ses,
+                                   uint32_t *se_count);
+
+/**
+ * iscsi_sessions_free() - Free the memory of 'struct iscsi_session' pointer
+ * array
+ *
+ * Free the memory of 'iscsi_session' pointer array generated by
+ * 'iscsi_sessions_get()'.
+ * If provided 'ses' pointer is NULL or 'session_count' is 0, do nothing.
+ *
+ * @ses:
+ *     Pointer of 'struct iscsi_session' pointer array.
+ * @session_count:
+ *     uint32_t, the size of 'struct iscsi_session' pointer array.
+ *
+ * Return:
+ *     void
+ */
+__DLL_EXPORT void iscsi_sessions_free(struct iscsi_session **ses,
+                                     uint32_t session_count);
+
+/**
+ * iscsi_session_get() - Retrieve specified iSCSI sessions.
+ *
+ * Retrieves specified iSCSI sessions. For the properties of
+ * 'struct iscsi_session', please refer to the functions defined in
+ * 'libopeniscsiusr_session.h' file.
+ *
+ * @ctx:
+ *     Pointer of 'struct iscsi_context'.
+ *     If this pointer is NULL, your program will be terminated by assert.
+ * @sid:
+ *     uint32_t, iSCSI session ID.
+ * @se:
+ *     Output pointer of 'struct iscsi_session' pointer. Its memory
+ *     should be freed by iscsi_session_free().
+ *     If this pointer is NULL, your program will be terminated by assert.
+ *     If specified iSCSI session does not exist, this pointer will be set to
+ *     NULL with LIBISCSI_OK returned.
+ *
+ * Return:
+ *     int. Valid error codes are:
+ *
+ *     * LIBISCSI_OK
+ *
+ *     * LIBISCSI_ERR_BUG
+ *
+ *     * LIBISCSI_ERR_NOMEM
+ *
+ *     * LIBISCSI_ERR_ACCESS
+ *
+ *     * LIBISCSI_ERR_SYSFS_LOOKUP
+ *
+ *     * LIBISCSI_ERR_SESS_NOT_FOUND
+ *
+ *     Error number could be converted to string by iscsi_strerror().
+ */
+__DLL_EXPORT int iscsi_session_get(struct iscsi_context *ctx, uint32_t sid,
+                                  struct iscsi_session **se);
+
+/**
+ * iscsi_session_free() - Free the memory of 'struct iscsi_session'.
+ *
+ * Free the memory of 'iscsi_session' pointer generated by
+ * 'iscsi_sessions_get()'.
+ * If provided 'se' pointer is NULL, do nothing.
+ *
+ * @se:
+ *     Pointer of 'struct iscsi_session' pointer.
+ *
+ * Return:
+ *     void
+ */
+__DLL_EXPORT void iscsi_session_free(struct iscsi_session *se);
+
+/**
+ * iscsi_default_iface_setup() - Setup default iSCSI interfaces.
+ *
+ * Setup default iSCSI interfaces for iSCSI TCP, iSER and iSCSI hardware offload
+ * cards. It is required after new iSCSI hardware offload card installed.
+ *
+ * Below kernel modules will be loaded when required by this function:
+ *
+ *     * cxgb3i
+ *     * cxgb4i
+ *     * bnx2i
+ *
+ * It will also create configuration files for iSCSI hardware offload cards in
+ * /etc/iscsi/ifaces/<iface_name>.
+ *
+ * @ctx:
+ *     Pointer of 'struct iscsi_context'.
+ *
+ * Return:
+ *     int. Valid error codes are:
+ *
+ *     * LIBISCSI_OK
+ *
+ *     * LIBISCSI_ERR_BUG
+ *
+ *     * LIBISCSI_ERR_NOMEM
+ *
+ *     * LIBISCSI_ERR_ACCESS
+ *
+ *     * LIBISCSI_ERR_SYSFS_LOOKUP
+ *
+ *     * LIBISCSI_ERR_IDBM
+ *
+ *     Error number could be converted to string by iscsi_strerror().
+ */
+__DLL_EXPORT int iscsi_default_iface_setup(struct iscsi_context *ctx);
+
+/**
+ * iscsi_ifaces_get() - Retrieve all iSCSI interfaces.
+ *
+ * Retrieves all iSCSI interfaces. For the properties of 'struct iscsi_iface',
+ * please refer to the functions defined in 'libopeniscsiusr_iface.h' file.
+ * The returned results contains default iSCSI interfaces(iser and iscsi_tcp)
+ * and iSCSI interfaces configured in "/etc/iscsi/ifaces/".
+ * Illegal configuration file will be skipped and warned.
+ * To generate iSCSI interface configuration when new card installed, please
+ * use iscsi_default_iface_setup().
+ *
+ * @ctx:
+ *     Pointer of 'struct iscsi_context'.
+ *     If this pointer is NULL, your program will be terminated by assert.
+ * @ifaces:
+ *     Output pointer of 'struct iscsi_iface' pointer array. Its memory
+ *     should be freed by iscsi_ifaces_free().
+ *     If this pointer is NULL, your program will be terminated by assert.
+ * @iface_count:
+ *     Output pointer of uint32_t. Will store the size of
+ *     'struct iscsi_iface' pointer array.
+ *
+ * Return:
+ *     int. Valid error codes are:
+ *
+ *     * LIBISCSI_OK
+ *
+ *     * LIBISCSI_ERR_BUG
+ *
+ *     * LIBISCSI_ERR_NOMEM
+ *
+ *     * LIBISCSI_ERR_ACCESS
+ *
+ *     * LIBISCSI_ERR_SYSFS_LOOKUP
+ *
+ *     Error number could be converted to string by iscsi_strerror().
+ */
+__DLL_EXPORT int iscsi_ifaces_get(struct iscsi_context *ctx,
+                                 struct iscsi_iface ***ifaces,
+                                 uint32_t *iface_count);
+
+/**
+ * iscsi_ifaces_free() - Free the memory of 'struct iscsi_iface' pointer
+ * array
+ *
+ * Free the memory of 'iscsi_iface' pointer array generated by
+ * 'iscsi_ifaces_get()'.
+ * If provided 'ifaces' pointer is NULL or 'iface_count' is 0, do nothing.
+ *
+ * @ifaces:
+ *     Pointer of 'struct iscsi_iface' pointer array.
+ * @iface_count:
+ *     uint32_t, the size of 'struct iscsi_iface' pointer array.
+ *
+ * Return:
+ *     void
+ */
+__DLL_EXPORT void iscsi_ifaces_free(struct iscsi_iface **ifaces,
+                                   uint32_t iface_count);
+
+/**
+ * iscsi_iface_get() - Retrieve specified iSCSI interface.
+ *
+ * Retrieves specified iSCSI interfaces by reading configuration from
+ * "/etc/iscsi/iface/<iface_name>".
+ * To generate iSCSI interface configuration when new card installed, please
+ * use iscsi_default_iface_setup().
+ * Illegal configuration file will be treated as error LIBISCSI_ERR_IDBM.
+ * Configuration file not found will be treated as error LIBISCSI_ERR_INVAL.
+ *
+ * @ctx:
+ *     Pointer of 'struct iscsi_context'.
+ *     If this pointer is NULL, your program will be terminated by assert.
+ * @iface_name:
+ *     String. Name of iSCSI interface. Also the file name of configuration
+ *     file "/etc/iscsi/iface/<iface_name>".
+ *     If this pointer is NULL or empty string, your program will be terminated
+ *     by assert.
+ * @iface:
+ *     Output pointer of 'struct iscsi_iface'. Its memory should be freed by
+ *     iscsi_iface_free().
+ *     If this pointer is NULL, your program will be terminated by assert.
+ *
+ * Return:
+ *     int. Valid error codes are:
+ *
+ *     * LIBISCSI_OK
+ *
+ *     * LIBISCSI_ERR_BUG
+ *
+ *     * LIBISCSI_ERR_NOMEM
+ *
+ *     * LIBISCSI_ERR_ACCESS
+ *
+ *     * LIBISCSI_ERR_SYSFS_LOOKUP
+ *
+ *     * LIBISCSI_ERR_IDBM
+ *
+ *     Error number could be converted to string by iscsi_strerror().
+ */
+__DLL_EXPORT int iscsi_iface_get(struct iscsi_context *ctx,
+                                const char *iface_name,
+                                struct iscsi_iface **iface);
+
+/**
+ * iscsi_iface_free() - Free the memory of 'struct iscsi_iface' pointer.
+ *
+ * Free the memory of 'iscsi_iface' pointer generated by 'iscsi_iface_get()'.
+ * If provided 'iface' pointer is NULL, do nothing.
+ *
+ * @iface:
+ *     Pointer of 'struct iscsi_iface' pointer.
+ *
+ * Return:
+ *     void
+ */
+__DLL_EXPORT void iscsi_iface_free(struct iscsi_iface *iface);
+
+/**
+ * iscsi_nodes_get() - Retrieve all iSCSI nodes.
+ *
+ * Retrieves all iSCSI nodes. For the properties of 'struct iscsi_node',
+ * please refer to the functions defined in 'libopeniscsiusr_node.h' file.
+ * The returned results contains iSCSI nodes configured in "/etc/iscsi/nodes/".
+ * Illegal configuration file will be skipped and warned.
+ * The returned 'struct iscsi_node' pointer array is sorted by target name,
+ * connection address, connection port and interface.
+ *
+ * @ctx:
+ *     Pointer of 'struct iscsi_context'.
+ *     If this pointer is NULL, your program will be terminated by assert.
+ * @nodes:
+ *     Output pointer of 'struct iscsi_node' pointer array. Its memory
+ *     should be freed by iscsi_nodes_free().
+ *     If this pointer is NULL, your program will be terminated by assert.
+ * @node_count:
+ *     Output pointer of uint32_t. Will store the size of
+ *     'struct iscsi_node' pointer array.
+ *
+ * Return:
+ *     int. Valid error codes are:
+ *
+ *     * LIBISCSI_OK
+ *
+ *     * LIBISCSI_ERR_BUG
+ *
+ *     * LIBISCSI_ERR_NOMEM
+ *
+ *     * LIBISCSI_ERR_ACCESS
+ *
+ *     * LIBISCSI_ERR_SYSFS_LOOKUP
+ *
+ *     * LIBISCSI_ERR_IDBM
+ *
+ *     Error number could be converted to string by iscsi_strerror().
+ */
+__DLL_EXPORT int iscsi_nodes_get(struct iscsi_context *ctx,
+                                struct iscsi_node ***nodes,
+                                uint32_t *node_count);
+
+/**
+ * iscsi_nodes_free() - Free the memory of 'struct iscsi_node' pointer
+ * array
+ *
+ * Free the memory of 'iscsi_node' pointer array generated by
+ * 'iscsi_nodes_get()'.
+ * If provided 'nodes' pointer is NULL or 'node_count' is 0, do nothing.
+ *
+ * @nodes:
+ *     Pointer of 'struct iscsi_node' pointer array.
+ * @node_count:
+ *     uint32_t, the size of 'struct iscsi_node' pointer array.
+ *
+ * Return:
+ *     void
+ */
+__DLL_EXPORT void iscsi_nodes_free(struct iscsi_node **nodes,
+                                  uint32_t node_count);
+
+#ifdef __cplusplus
+} /* End of extern "C" */
+#endif
+
+#endif /* End of _LIB_OPEN_ISCSI_USR_H_ */
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/libopeniscsiusr/libopeniscsiusr_common.h b/pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/libopeniscsiusr/libopeniscsiusr_common.h
new file mode 100644 (file)
index 0000000..7ae2906
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Gris Ge <fge@redhat.com>
+ */
+
+
+#ifndef _LIB_OPEN_ISCSI_USR_COMMON_H_
+#define _LIB_OPEN_ISCSI_USR_COMMON_H_
+
+#include <errno.h>
+
+/* Below error numbers should align with 'open-iscsi/include/iscsi_err.h' */
+#define LIBISCSI_OK                    0
+/* ^ No error */
+
+#define LIBISCSI_ERR_BUG               1
+/* ^ Bug of library */
+
+#define LIBISCSI_ERR_SESS_NOT_FOUND    2
+/* ^ session could not be found */
+
+#define LIBISCSI_ERR_NOMEM             3
+/* ^ Could not allocate resource for operation */
+
+#define LIBISCSI_ERR_IDBM              6
+/* ^ Error accessing/managing iSCSI DB */
+
+#define LIBISCSI_ERR_INVAL             7
+/* ^ Invalid argument */
+
+#define LIBISCSI_ERR_TRANS_NOT_FOUND   12
+/* ^ iSCSI transport module not loaded in kernel or iscsid */
+
+#define LIBISCSI_ERR_ACCESS            13
+/* ^ Permission denied */
+
+#define LIBISCSI_ERR_SYSFS_LOOKUP      22
+/* ^ Could not lookup object in sysfs */
+
+/*
+ * Use the syslog severity level as log priority
+ */
+#define LIBISCSI_LOG_PRIORITY_ERROR    3
+#define LIBISCSI_LOG_PRIORITY_WARNING  4
+#define LIBISCSI_LOG_PRIORITY_INFO     6
+#define LIBISCSI_LOG_PRIORITY_DEBUG    7
+
+#define LIBISCSI_LOG_PRIORITY_DEFAULT  LIBISCSI_LOG_PRIORITY_WARNING
+
+#define __DLL_EXPORT   __attribute__ ((visibility ("default")))
+/* ^ Mark function or struct as external use.
+ *   Check https://gcc.gnu.org/wiki/Visibility for detail
+ */
+#define __DLL_LOCAL    __attribute__ ((visibility ("hidden")))
+/* ^ Mark function or struct as internal use only.
+ *   Check https://gcc.gnu.org/wiki/Visibility for detail
+ */
+
+struct __DLL_EXPORT iscsi_context;
+
+struct __DLL_EXPORT iscsi_session;
+
+struct __DLL_EXPORT iscsi_iface;
+
+struct __DLL_EXPORT iscsi_node;
+
+#endif /* End of _LIB_OPEN_ISCSI_USR_COMMON_H_ */
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/libopeniscsiusr/libopeniscsiusr_iface.h b/pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/libopeniscsiusr/libopeniscsiusr_iface.h
new file mode 100644 (file)
index 0000000..9ac1aa5
--- /dev/null
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Gris Ge <fge@redhat.com>
+ */
+
+#ifndef _LIB_OPEN_ISCSI_USR_IFACE_H_
+#define _LIB_OPEN_ISCSI_USR_IFACE_H_
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include "libopeniscsiusr_common.h"
+
+/**
+ * iscsi_iface_ipaddress_get() - Retrieve IP address of specified
+ * iSCSI interface
+ *
+ * Retrieve the IP address of specified iSCSI interface.
+ *
+ * @iface:
+ *     Pointer of 'struct iscsi_iface'.
+ *     If this pointer is NULL, your program will be terminated by assert.
+ *
+ * Return:
+ *     const char *.
+ *     No need to free this memory, the resources will get freed by
+ *     iscsi_session_free() or iscsi_sessions_free().
+ */
+__DLL_EXPORT const char *iscsi_iface_ipaddress_get(struct iscsi_iface *iface);
+
+/**
+ * iscsi_iface_hwaddress_get() - Retrieve hardware address of specified
+ * iSCSI interface
+ *
+ * Retrieve the hardware address of specified iSCSI interface.
+ *
+ * @iface:
+ *     Pointer of 'struct iscsi_iface'.
+ *     If this pointer is NULL, your program will be terminated by assert.
+ *
+ * Return:
+ *     const char *.
+ *     No need to free this memory, the resources will get freed by
+ *     iscsi_session_free() or iscsi_sessions_free().
+ */
+__DLL_EXPORT const char *iscsi_iface_hwaddress_get(struct iscsi_iface *iface);
+
+/**
+ * iscsi_iface_netdev_get() - Retrieve network device name of specified
+ * iSCSI interface
+ *
+ * Retrieve the network device name of specified iSCSI interface.
+ *
+ * @iface:
+ *     Pointer of 'struct iscsi_iface'.
+ *     If this pointer is NULL, your program will be terminated by assert.
+ *
+ * Return:
+ *     const char *.
+ *     No need to free this memory, the resources will get freed by
+ *     iscsi_session_free() or iscsi_sessions_free().
+ */
+__DLL_EXPORT const char *iscsi_iface_netdev_get(struct iscsi_iface *iface);
+
+/**
+ * iscsi_iface_transport_name_get() - Retrieve transport name of specified
+ * iSCSI interface
+ *
+ * Retrieve the transport name of specified iSCSI interface.
+ * Examples:
+ *
+ *     * "tcp" (Software iSCSI over TCP/IP)
+ *     * "iser" (Software iSCSI over infinniband
+ *     * "qla4xxx" (Qlogic QLA4XXX HBAs)
+ *     * "bnx2i" (Broadcom bnx iSCSI HBAs);
+ *     * "cxgb3i" (Chelsio cxgb S3 iSCSI HBAs);
+ *
+ * @iface:
+ *     Pointer of 'struct iscsi_iface'.
+ *     If this pointer is NULL, your program will be terminated by assert.
+ *
+ * Return:
+ *     const char *.
+ *     No need to free this memory, the resources will get freed by
+ *     iscsi_session_free() or iscsi_sessions_free().
+ */
+__DLL_EXPORT const char *iscsi_iface_transport_name_get
+       (struct iscsi_iface *iface);
+
+/**
+ * iscsi_iface_iname_get() - Retrieve initiator name of specified
+ * iSCSI interface
+ *
+ * Retrieve the initiator name of specified iSCSI interface.
+ *
+ * @iface:
+ *     Pointer of 'struct iscsi_iface'.
+ *     If this pointer is NULL, your program will be terminated by assert.
+ *
+ * Return:
+ *     const char *.
+ *     No need to free this memory, the resources will get freed by
+ *     iscsi_session_free() or iscsi_sessions_free().
+ */
+__DLL_EXPORT const char *iscsi_iface_iname_get(struct iscsi_iface *iface);
+
+/**
+ * iscsi_iface_port_state_get() - Retrieve network port state of specified
+ * iSCSI interface
+ *
+ * Retrieve the network port state of specified iSCSI interface.
+ *
+ * @iface:
+ *     Pointer of 'struct iscsi_iface'.
+ *     If this pointer is NULL, your program will be terminated by assert.
+ *
+ * Return:
+ *     const char *. Possible values are :
+ *
+ *     * "LINK_UP"
+ *
+ *     * "LINK_DOWN"
+ *
+ *     * "unknown"
+ *
+ *     No need to free this memory, the resources will get freed by
+ *     iscsi_session_free() or iscsi_sessions_free().
+ */
+__DLL_EXPORT const char *iscsi_iface_port_state_get(struct iscsi_iface *iface);
+
+/**
+ * iscsi_iface_port_speed_get() - Retrieve network port speed of specified
+ * iSCSI interface
+ *
+ * Retrieve the network port speed of specified iSCSI interface.
+ * Returned string format is '[0-9]+ [MGT]bps', example: '10 Mbps' or '10 Gbps'.
+ *
+ * @iface:
+ *     Pointer of 'struct iscsi_iface'.
+ *     If this pointer is NULL, your program will be terminated by assert.
+ *
+ * Return:
+ *     const char *. Set to "unknown" if unknown.
+ *     No need to free this memory, the resources will get freed by
+ *     iscsi_session_free() or iscsi_sessions_free().
+ */
+__DLL_EXPORT const char *iscsi_iface_port_speed_get(struct iscsi_iface *iface);
+
+/**
+ * iscsi_iface_name_get() - Retrieve name of specified iSCSI interface
+ *
+ * Retrieve the name of specified iSCSI interface.
+ *
+ * @iface:
+ *     Pointer of 'struct iscsi_iface'.
+ *     If this pointer is NULL, your program will be terminated by assert.
+ *
+ * Return:
+ *     const char *.
+ *     No need to free this memory, the resources will get freed by
+ *     iscsi_session_free() or iscsi_sessions_free().
+ */
+__DLL_EXPORT const char *iscsi_iface_name_get(struct iscsi_iface *iface);
+
+/**
+ * iscsi_iface_dump_config() - Dump all configurations of specified iSCSI
+ * interface.
+ *
+ * Dump all configurations of specified iSCSI interface. Will skip empty
+ * configuration so that output string could be saved directly to
+ * /etc/iscsi/ifaces/<iface_name> file.
+ *
+ * @iface:
+ *     Pointer of 'struct iscsi_iface'.
+ *     If this pointer is NULL, your program will be terminated by assert.
+ *
+ * Return:
+ *     const char *.
+ *     Need to free this memory by free().
+ */
+__DLL_EXPORT const char *iscsi_iface_dump_config(struct iscsi_iface *iface);
+
+/**
+ * iscsi_iface_print_config() - Print all configurations of specified iSCSI
+ * interface to STDOUT.
+ *
+ * Print all configurations of specified iSCSI interface.
+ * For empty configuration, it will be shown as "name = <empty>".
+ *
+ * @iface:
+ *     Pointer of 'struct iscsi_iface'.
+ *     If this pointer is NULL, your program will be terminated by assert.
+ *
+ * Return:
+ *     void
+ */
+__DLL_EXPORT void iscsi_iface_print_config(struct iscsi_iface *iface);
+
+/**
+ * iscsi_is_default_iface() - Whether specified iSCSI interface is default
+ * interface.
+ *
+ * Check whether specified iSCSI interface is one of the default interfaces.
+ * Currently, default interfaces are :
+ *
+ *   * Interface 'default' using 'iscsi_tcp' kernel module.
+ *
+ *   * Interface 'iser' is using 'ib_iser' kernel module.
+ *
+ * @iface:
+ *     Pointer of 'struct iscsi_iface'.
+ *
+ * Return:
+ *     bool.
+ */
+__DLL_EXPORT bool iscsi_is_default_iface(struct iscsi_iface *iface);
+
+#endif /* End of _LIB_OPEN_ISCSI_USR_IFACE_H_ */
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/libopeniscsiusr/libopeniscsiusr_node.h b/pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/libopeniscsiusr/libopeniscsiusr_node.h
new file mode 100644 (file)
index 0000000..4a31aa9
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Gris Ge <fge@redhat.com>
+ */
+
+#ifndef _LIB_OPEN_ISCSI_USR_NODE_H_
+#define _LIB_OPEN_ISCSI_USR_NODE_H_
+
+#include "libopeniscsiusr_common.h"
+
+/**
+ * iscsi_node_dump_config() - Dump all configurations of specified iSCSI
+ * node.
+ *
+ * Dump all configurations of specified iSCSI node. Will skip empty
+ * configuration.
+ *
+ * @node:
+ *     Pointer of 'struct iscsi_node'.
+ *     If this pointer is NULL, your program will be terminated by assert.
+ * @show_secret:
+ *     Whether show CHAP secret. If set as false, will show password as
+ *     "********"
+ *
+ * Return:
+ *     const char *.
+ *     Need to free this memory by free().
+ */
+__DLL_EXPORT const char *iscsi_node_dump_config(struct iscsi_node *node,
+                                               bool show_secret);
+
+/**
+ * iscsi_node_print_config() - Print all configurations of specified iSCSI
+ * node to STDOUT.
+ *
+ * Print all configurations of specified iSCSI node.
+ * For empty configuration, it will be shown as "name = <empty>".
+ *
+ * @node:
+ *     Pointer of 'struct iscsi_node'.
+ *     If this pointer is NULL, your program will be terminated by assert.
+ * @show_secret:
+ *     Whether show CHAP secret. If set as false, will show password as
+ *     "********"
+ *
+ * Return:
+ *     void
+ */
+__DLL_EXPORT void iscsi_node_print_config(struct iscsi_node *node,
+                                         bool show_secret);
+
+/**
+ * iscsi_node_target_name_get() - Retrieve target name of specified iSCSI node.
+ *
+ * Retrieve the target name of specified iSCSI node.
+ * Examples: "iqn.2003-01.org.linux-iscsi.org:iscsi-targetcli"
+ *
+ * @node:
+ *     Pointer of 'struct iscsi_node'.
+ *     If this pointer is NULL, your program will be terminated by assert.
+ *
+ * Return:
+ *     const char *.
+ *     No need to free this memory, the resources will get freed by
+ *     iscsi_node_free() or iscsi_nodes_free().
+ */
+__DLL_EXPORT const char *iscsi_node_target_name_get
+       (struct iscsi_node *node);
+
+/**
+ * iscsi_node_conn_is_ipv6() - Check whether specified node is using ipv6
+ * connection.
+ *
+ * Check whether specified node is using ipv6 connection.
+ *
+ * @node:
+ *     Pointer of 'struct iscsi_node'.
+ *     If this pointer is NULL, your program will be terminated by assert.
+ *
+ * Return:
+ *     bool
+ */
+__DLL_EXPORT bool iscsi_node_conn_is_ipv6(struct iscsi_node *node);
+
+/**
+ * iscsi_node_conn_address_get() - Retrieve connection address of specified
+ * iSCSI node.
+ *
+ * Retrieve the iscsi connection target address of specified iSCSI node.
+ * Examples: "192.168.1.1"
+ *
+ * @node:
+ *     Pointer of 'struct iscsi_node'.
+ *     If this pointer is NULL, your program will be terminated by assert.
+ *
+ * Return:
+ *     const char *.
+ *     No need to free this memory, the resources will get freed by
+ *     iscsi_node_free() or iscsi_nodes_free().
+ */
+__DLL_EXPORT const char *iscsi_node_conn_address_get(struct iscsi_node *node);
+
+/**
+ * iscsi_node_conn_port_get() - Retrieve connection port of specified iSCSI
+ * node.
+ *
+ * Retrieve the iscsi connection target port of specified iSCSI node.
+ * Examples: "3260"
+ *
+ * @node:
+ *     Pointer of 'struct iscsi_node'.
+ *     If this pointer is NULL, your program will be terminated by assert.
+ *
+ * Return:
+ *     uint32_t
+ */
+__DLL_EXPORT uint32_t iscsi_node_conn_port_get(struct iscsi_node *node);
+
+/**
+ * iscsi_node_portal_get() - Retrieve connection portal of specified
+ * iSCSI node.
+ *
+ * Retrieve the iscsi connection target portal of specified iSCSI node.
+ * Just a combination of iscsi_node_conn_address_get() and
+ * iscsi_node_conn_port_get().
+ * Examples: "192.168.1.1:3260" and "[::1]:3260"
+ *
+ * @node:
+ *     Pointer of 'struct iscsi_node'.
+ *     If this pointer is NULL, your program will be terminated by assert.
+ *
+ * Return:
+ *     const char *.
+ *     No need to free this memory, the resources will get freed by
+ *     iscsi_node_free() or iscsi_nodes_free().
+ */
+__DLL_EXPORT const char *iscsi_node_portal_get(struct iscsi_node *node);
+
+/**
+ * iscsi_node_tpgt_get() - Retrieve target portal group tag of specified
+ * iSCSI node.
+ *
+ * Retrieve the target portal group tag of specified iSCSI node.
+ *
+ * @node:
+ *     Pointer of 'struct iscsi_node'.
+ *     If this pointer is NULL, your program will be terminated by assert.
+ *
+ * Return:
+ *     int32_t. -1 for unknown.
+ */
+__DLL_EXPORT int32_t iscsi_node_tpgt_get(struct iscsi_node *node);
+
+/**
+ * iscsi_node_iface_name_get() - Retrieve interface name of specified iSCSI
+ * node.
+ *
+ * Retrieve the interface name of specified iSCSI node.
+ * Examples: "default" for iscsi tcp interface.
+ *
+ * @node:
+ *     Pointer of 'struct iscsi_node'.
+ *     If this pointer is NULL, your program will be terminated by assert.
+ *
+ * Return:
+ *     const char *.
+ *     No need to free this memory, the resources will get freed by
+ *     iscsi_node_free() or iscsi_nodes_free().
+ */
+__DLL_EXPORT const char *iscsi_node_iface_name_get(struct iscsi_node *node);
+
+#endif /* End of _LIB_OPEN_ISCSI_USR_NODE_H_ */
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/libopeniscsiusr/libopeniscsiusr_session.h b/pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/libopeniscsiusr/libopeniscsiusr_session.h
new file mode 100644 (file)
index 0000000..5a0c667
--- /dev/null
@@ -0,0 +1,351 @@
+/*
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Gris Ge <fge@redhat.com>
+ */
+
+#ifndef _LIB_OPEN_ISCSI_USR_SESSION_H_
+#define _LIB_OPEN_ISCSI_USR_SESSION_H_
+
+#include "libopeniscsiusr_common.h"
+
+#include <stdint.h>
+
+/**
+ * iscsi_session_sid_get() - Retrieve iSCSI session ID of specified session.
+ *
+ * Retrieve iSCSI session ID. The session ID here is the integer used
+ * in '/sys/class/iscsi_session/session<session_id>/'
+ *
+ * @se:
+ *     Pointer of 'struct iscsi_session'.
+ *     If this pointer is NULL, your program will be terminated by assert.
+ *
+ * Return:
+ *     uint32_t.
+ */
+__DLL_EXPORT uint32_t iscsi_session_sid_get(struct iscsi_session *se);
+
+/**
+ * iscsi_session_persistent_address_get() - Retrieve iSCSI target persistent
+ * address of specified session
+ *
+ * Retrieve the iSCSI target persistent address of specified iSCSI session.
+ * The 'persistent address' is the network address where iSCSI initiator send
+ * initial request. When iSCSI redirection in use, this address might not be
+ * the network address used for actual iSCSI transaction.
+ * Please use `iscsi_session_address_get()` for target network address of
+ * iSCSI transaction.
+ *
+ * @se:
+ *     Pointer of 'struct iscsi_session'.
+ *     If this pointer is NULL, your program will be terminated by assert.
+ *
+ * Return:
+ *     const char *. Empty string if not supported.
+ *     No need to free this memory, the resources will get freed by
+ *     iscsi_session_free() or iscsi_sessions_free().
+ */
+__DLL_EXPORT const char *iscsi_session_persistent_address_get
+       (struct iscsi_session *se);
+
+/**
+ * iscsi_session_persistent_port_get() - Retrieve iSCSI target persistent
+ * port of specified session
+ *
+ * Retrieve the iSCSI target persistent port of specified iSCSI session.
+ * The 'persistent port' is the network port where iSCSI initiator send
+ * initial request. When iSCSI redirection in use, this port might not be
+ * the network port used for actual iSCSI transaction.
+ * Please use `iscsi_session_port_get()` for target network address of
+ * iSCSI transaction.
+ *
+ * @se:
+ *     Pointer of 'struct iscsi_session'.
+ *     If this pointer is NULL, your program will be terminated by assert.
+ *
+ * Return:
+ *     int32_t. -1 if not supported.
+ */
+__DLL_EXPORT int32_t iscsi_session_persistent_port_get
+       (struct iscsi_session *se);
+
+/**
+ * iscsi_session_target_name_get() - Retrieve iSCSI target name of specified
+ * session
+ *
+ * Retrieve the iSCSI target name of specified iSCSI session.
+ * The iSCSI Target Name specifies the worldwide unique name of the target.
+ *
+ * @se:
+ *     Pointer of 'struct iscsi_session'.
+ *     If this pointer is NULL, your program will be terminated by assert.
+ *
+ * Return:
+ *     const char *.
+ *     No need to free this memory, the resources will get freed by
+ *     iscsi_session_free() or iscsi_sessions_free().
+ */
+__DLL_EXPORT const char *iscsi_session_target_name_get
+       (struct iscsi_session *se);
+
+/**
+ * iscsi_session_username_get() - Retrieve authentication username of specified
+ * session.
+ *
+ * Retrieve the authentication username of specified iSCSI session.
+ * Currently open-iscsi only support CHAP authentication method.
+ * It's controlled this setting in iscsid.conf:
+ * 'node.session.auth.username'
+ *
+ * @se:
+ *     Pointer of 'struct iscsi_session'.
+ *     If this pointer is NULL, your program will be terminated by assert.
+ *
+ * Return:
+ *     const char *. Empty string if not using CHAP authentication or failed
+ *     to read authentication information.
+ *     No need to free this memory, the resources will get freed by
+ *     iscsi_session_free() or iscsi_sessions_free().
+ */
+__DLL_EXPORT const char *iscsi_session_username_get(struct iscsi_session *se);
+
+/**
+ * iscsi_session_password_get() - Retrieve authentication password of specified
+ * session.
+ *
+ * Retrieve the authentication password of specified iSCSI session.
+ * Currently open-iscsi only support CHAP authentication method.
+ * It's controlled this setting in iscsid.conf:
+ * 'node.session.auth.password'
+ *
+ * @se:
+ *     Pointer of 'struct iscsi_session'.
+ *     If this pointer is NULL, your program will be terminated by assert.
+ *
+ * Return:
+ *     const char *. Empty string if not using CHAP authentication or failed
+ *     to read authentication information.
+ *     No need to free this memory, the resources will get freed by
+ *     iscsi_session_free() or iscsi_sessions_free().
+ */
+__DLL_EXPORT const char *iscsi_session_password_get(struct iscsi_session *se);
+
+/**
+ * iscsi_session_username_in_get() - Retrieve authentication username of
+ * specified session.
+ *
+ * Retrieve the inbound authentication username of specified iSCSI session.
+ * Currently open-iscsi only support CHAP authentication method.
+ * The inbound authentication here means the iSCSI initiator authenticates the
+ * iSCSI target using CHAP.
+ * It's controlled this setting in iscsid.conf:
+ * 'node.session.auth.username_in'
+ *
+ * @se:
+ *     Pointer of 'struct iscsi_session'.
+ *     If this pointer is NULL, your program will be terminated by assert.
+ *
+ * Return:
+ *     const char *. Empty string if not using inbound CHAP authentication or
+ *     failed to read authentication information.
+ *     No need to free this memory, the resources will get freed by
+ *     iscsi_session_free() or iscsi_sessions_free().
+ */
+__DLL_EXPORT const char *iscsi_session_username_in_get
+       (struct iscsi_session *se);
+
+/**
+ * iscsi_session_password_in_get() - Retrieve authentication password of
+ * specified session.
+ *
+ * Retrieve the inbound authentication password of specified iSCSI session.
+ * Currently open-iscsi only support CHAP authentication method.
+ * The inbound authentication here means the iSCSI initiator authenticates the
+ * iSCSI target using CHAP.
+ * It's controlled this setting in iscsid.conf:
+ * 'node.session.auth.password_in'
+ *
+ * @se:
+ *     Pointer of 'struct iscsi_session'.
+ *     If this pointer is NULL, your program will be terminated by assert.
+ *
+ * Return:
+ *     const char *. Empty string if not using inbound CHAP authentication or
+ *     failed to read authentication information.
+ *     No need to free this memory, the resources will get freed by
+ *     iscsi_session_free() or iscsi_sessions_free().
+ */
+__DLL_EXPORT const char *iscsi_session_password_in_get
+       (struct iscsi_session *se);
+
+/**
+ * iscsi_session_recovery_tmo_get() - Retrieve recovery timeout value of
+ * specified session
+ *
+ * Retrieve the recovery timeout value of specified iSCSI session.
+ * The recovery timeout here means the seconds of time to wait for session
+ * re-establishment before failing SCSI commands back to the application when
+ * running the Linux SCSI Layer error handler.
+ * It could be controlled via this setting in iscsid.conf:
+ * 'node.session.timeo.replacement_timeout'.
+ *
+ * @se:
+ *     Pointer of 'struct iscsi_session'.
+ *     If this pointer is NULL, your program will be terminated by assert.
+ *
+ * Return:
+ *     int32_t. If the value is 0, IO will be failed immediately. If the value
+ *     is less than 0, IO will remain queued until the session is logged back
+ *     in, or until the user runs the logout command.
+ */
+__DLL_EXPORT int32_t iscsi_session_recovery_tmo_get(struct iscsi_session *se);
+
+/**
+ * iscsi_session_lu_reset_tmo_get() - Retrieve logical unit timeout value of
+ * specified session
+ *
+ * Retrieve the logical unit timeout value of specified iSCSI session.
+ * The logical unit timeout here means the seconds of time to wait for a logical
+ * unit response before before failing the operation and trying session
+ * re-establishment.
+ * It could be controlled via this setting in iscsid.conf:
+ * 'node.session.err_timeo.lu_reset_timeout'
+ *
+ * @se:
+ *     Pointer of 'struct iscsi_session'.
+ *     If this pointer is NULL, your program will be terminated by assert.
+ *
+ * Return:
+ *     int32_t. -1 if not supported.
+ */
+__DLL_EXPORT int32_t iscsi_session_lu_reset_tmo_get(struct iscsi_session *se);
+
+/**
+ * iscsi_session_tgt_reset_tmo_get() - Retrieve target response timeout value of
+ * of specified session
+ *
+ * Retrieve the target response timeout value of specified iSCSI session.
+ * The target response timeout here means the seconds of time to wait for a
+ * target response before before failing the operation and trying session
+ * re-establishment.
+ * It could be controlled via this setting in iscsid.conf:
+ * 'node.session.err_timeo.tgt_reset_timeout'.
+ *
+ * @se:
+ *     Pointer of 'struct iscsi_session'.
+ *     If this pointer is NULL, your program will be terminated by assert.
+ *
+ * Return:
+ *     int32_t. -1 if not supported.
+ */
+__DLL_EXPORT int32_t iscsi_session_tgt_reset_tmo_get(struct iscsi_session *se);
+
+/**
+ * iscsi_session_abort_tmo_get() - Retrieve abort response timeout value of
+ * specified session
+ *
+ * Retrieve the abort response timeout value of specified iSCSI session.
+ * The abort response timeout here means the seconds of time to wait for a
+ * abort response before before failing the operation and trying session
+ * re-establishment.
+ * It could be controlled via this setting in iscsid.conf:
+ * 'node.session.err_timeo.abort_timeout'.
+ *
+ * @se:
+ *     Pointer of 'struct iscsi_session'.
+ *     If this pointer is NULL, your program will be terminated by assert.
+ *
+ * Return:
+ *     int32_t. -1 if not supported.
+ */
+__DLL_EXPORT int32_t iscsi_session_abort_tmo_get(struct iscsi_session *se);
+
+/**
+ * iscsi_session_tpgt_get() - Retrieve target portal group tag of specified
+ * session
+ *
+ * Retrieve the target portal group tag of specified iSCSI session.
+ *
+ * The target portal group tag is a value that uniquely identifies a portal
+ * group within an iSCSI target node. This key carries the value of the tag of
+ * the portal group that is servicing the Login request. The iSCSI target
+ * returns this key to the initiator in the Login Response PDU to the first
+ * Login Request PDU that has the C bit set to 0 when TargetName is given by the
+ * initiator.
+ *
+ * @se:
+ *     Pointer of 'struct iscsi_session'.
+ *     If this pointer is NULL, your program will be terminated by assert.
+ *
+ * Return:
+ *     int32_t. -1 if not supported.
+ */
+__DLL_EXPORT int32_t iscsi_session_tpgt_get(struct iscsi_session *se);
+
+/**
+ * iscsi_session_address_get() - Retrieve iSCSI target address of specified
+ * session
+ *
+ * Retrieve the iSCSI target network address of specified iSCSI session.
+ *
+ * @se:
+ *     Pointer of 'struct iscsi_session'.
+ *     If this pointer is NULL, your program will be terminated by assert.
+ *
+ * Return:
+ *     const char *. Empty string if not supported.
+ *     No need to free this memory, the resources will get freed by
+ *     iscsi_session_free() or iscsi_sessions_free().
+ */
+__DLL_EXPORT const char *iscsi_session_address_get
+       (struct iscsi_session *se);
+
+/**
+ * iscsi_session_port_get() - Retrieve iSCSI target port of specified session
+ *
+ * Retrieve the iSCSI target port of specified iSCSI session.
+ *
+ * @se:
+ *     Pointer of 'struct iscsi_session'.
+ *     If this pointer is NULL, your program will be terminated by assert.
+ *
+ * Return:
+ *     int32_t. -1 if not supported.
+ */
+__DLL_EXPORT int32_t iscsi_session_port_get(struct iscsi_session *se);
+
+/**
+ * iscsi_session_iface_get() - Retrieve iSCSI interface information of
+ * specified session
+ *
+ * Retrieve the iSCSI interface information of specified iSCSI session.
+ * For the properties of 'struct iscsi_iface', please refer to the functions
+ * defined in 'libopeniscsiusr_iface.h' file.
+ *
+ * @se:
+ *     Pointer of 'struct iscsi_session'.
+ *     If this pointer is NULL, your program will be terminated by assert.
+ *
+ * Return:
+ *     Pointer of 'struct iscsi_iface'. NULL if not supported.
+ *     No need to free this memory, the resources will get freed by
+ *     iscsi_session_free() or iscsi_sessions_free().
+ */
+__DLL_EXPORT struct iscsi_iface *iscsi_session_iface_get
+       (struct iscsi_session *se);
+
+#endif /* End of _LIB_OPEN_ISCSI_USR_SESSION_H_ */
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/misc.c b/pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/misc.c
new file mode 100644 (file)
index 0000000..9111966
--- /dev/null
@@ -0,0 +1,331 @@
+/*
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Gris Ge <fge@redhat.com>
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <dirent.h>
+#include <string.h>
+#include <unistd.h>
+#include <net/if.h>
+#include <sys/socket.h>
+#include <linux/ethtool.h>
+#include <sys/ioctl.h>
+#include <linux/sockios.h>
+#include <net/if_arp.h>
+
+#include "libopeniscsiusr/libopeniscsiusr.h"
+#include "misc.h"
+#include "context.h"
+
+#define _UNUSED(x) (void)(x)
+
+#define _ISCSI_LOG_STRERR_ALIGN_WIDTH  80
+/* ^ Only used in _iscsi_log_stderr() for pretty log output.
+ *   When provided log message is less than 80 bytes, fill it with space, then
+ *   print code file name, function name, line after the 80th bytes.
+ */
+
+struct _num_str_conv {
+       const uint32_t value;
+       const char *str;
+};
+
+#define _iscsi_str_func_gen(func_name, var_type, var, conv_array) \
+const char *func_name(var_type var) { \
+       size_t i = 0; \
+       uint32_t tmp_var = var & UINT32_MAX; \
+       errno = 0; \
+       /* In the whole libopeniscsiusr, we don't have negative value */ \
+       for (; i < sizeof(conv_array)/sizeof(conv_array[0]); ++i) { \
+               if ((conv_array[i].value) == tmp_var) \
+                       return conv_array[i].str; \
+       } \
+       errno = EINVAL; \
+       return "Invalid argument"; \
+}
+
+static const struct _num_str_conv _ISCSI_RC_MSG_CONV[] = {
+       {LIBISCSI_OK, "OK"},
+       {LIBISCSI_ERR_BUG, "BUG of libopeniscsiusr library"},
+       {LIBISCSI_ERR_SESS_NOT_FOUND, "Specified iSCSI session not found"},
+       {LIBISCSI_ERR_ACCESS, "Permission deny"},
+       {LIBISCSI_ERR_NOMEM, "Out of memory"},
+       {LIBISCSI_ERR_SYSFS_LOOKUP, "Could not lookup object in sysfs"},
+       {LIBISCSI_ERR_IDBM, "Error accessing/managing iSCSI DB"},
+       {LIBISCSI_ERR_TRANS_NOT_FOUND,
+               "iSCSI transport module not loaded in kernel or iscsid"},
+       {LIBISCSI_ERR_INVAL, "Invalid argument"},
+};
+
+_iscsi_str_func_gen(iscsi_strerror, int, rc, _ISCSI_RC_MSG_CONV);
+
+static const struct _num_str_conv _ISCSI_PRI_CONV[] = {
+       {LIBISCSI_LOG_PRIORITY_DEBUG, "DEBUG"},
+       {LIBISCSI_LOG_PRIORITY_INFO, "INFO"},
+       {LIBISCSI_LOG_PRIORITY_WARNING, "WARNING"},
+       {LIBISCSI_LOG_PRIORITY_ERROR, "ERROR"},
+};
+
+_iscsi_str_func_gen(iscsi_log_priority_str, int, priority, _ISCSI_PRI_CONV);
+
+void _iscsi_log_stderr(struct iscsi_context *ctx, int priority,
+                      const char *file, int line, const char *func_name,
+                      const char *format, va_list args)
+{
+       int printed_bytes = 0;
+
+       _UNUSED(ctx);
+
+       printed_bytes += fprintf(stderr, "iSCSI %s: ",
+                                iscsi_log_priority_str(priority));
+       printed_bytes += vfprintf(stderr, format, args);
+
+       if (printed_bytes < _ISCSI_LOG_STRERR_ALIGN_WIDTH) {
+               fprintf(stderr, "%*s # %s:%s():%d\n",
+                       _ISCSI_LOG_STRERR_ALIGN_WIDTH - printed_bytes, "", file,
+                       func_name, line);
+       } else {
+               fprintf(stderr, " # %s:%s():%d\n", file, func_name, line);
+       }
+}
+
+void _iscsi_log(struct iscsi_context *ctx, int priority, const char *file,
+               int line, const char *func_name, const char *format, ...)
+{
+       va_list args;
+
+       if (ctx->log_func == NULL)
+               return;
+
+       va_start(args, format);
+       ctx->log_func(ctx, priority, file, line, func_name, format, args);
+       va_end(args);
+}
+
+int _scan_filter_skip_dot(const struct dirent *dir)
+{
+       return strcmp(dir->d_name, ".") && strcmp(dir->d_name, "..");
+}
+
+bool _file_exists(const char *path)
+{
+       if (access(path, F_OK) == 0)
+               return true;
+       else
+               return false;
+}
+
+static bool _is_eth(struct iscsi_context *ctx, const char *if_name)
+{
+       struct ifreq ifr;
+       int sockfd = -1;
+       char strerr_buff[_STRERR_BUFF_LEN];
+
+       assert(if_name != NULL);
+
+       memset(&ifr, 0, sizeof(ifr));
+
+       _strncpy(ifr.ifr_name, if_name, IFNAMSIZ);
+
+       sockfd = socket(AF_INET, SOCK_DGRAM, 0);
+       if (sockfd < 0) {
+               _warn(ctx, "Failed to create SOCK_DGRAM AF_INET socket: %d %s",
+                     errno, _strerror(errno, strerr_buff));
+               return false;
+       }
+
+       if (ioctl(sockfd, SIOCGIFHWADDR, &ifr) != 0) {
+               _warn(ctx, "IOCTL SIOCGIFHWADDR to %s failed: %d %s", if_name,
+                     errno, _strerror(errno, strerr_buff));
+               close(sockfd);
+               return false;
+       }
+
+       close(sockfd);
+
+       if (ifr.ifr_hwaddr.sa_family == ARPHRD_ETHER)
+               return true;
+
+       return false;
+}
+
+/*
+ * driver_name should be char[_ETH_DRIVER_NAME_MAX_LEN]
+ */
+static int _eth_driver_get(struct iscsi_context *ctx, const char *if_name,
+                          char *driver_name)
+{
+       int sockfd = -1;
+       struct ethtool_drvinfo drvinfo;
+       struct ifreq ifr;
+       char strerr_buff[_STRERR_BUFF_LEN];
+
+       assert(ctx != NULL);
+       assert(if_name != NULL);
+       assert(driver_name != NULL);
+
+       memset(&ifr, 0, sizeof(ifr));
+       memset(&drvinfo, 0, sizeof(drvinfo));
+
+       _strncpy(ifr.ifr_name, if_name, IFNAMSIZ);
+       drvinfo.cmd = ETHTOOL_GDRVINFO;
+       ifr.ifr_data = (caddr_t) &drvinfo;
+
+       sockfd = socket(AF_INET, SOCK_DGRAM, 0);
+       if (sockfd < 0) {
+               _error(ctx, "Failed to create SOCK_DGRAM AF_INET socket: %d %s",
+                      errno, _strerror(errno, strerr_buff));
+               return LIBISCSI_ERR_BUG;
+       }
+
+       if (ioctl(sockfd, SIOCETHTOOL, &ifr) != 0) {
+               _warn(ctx, "IOCTL SIOCETHTOOL to %s failed: %d %s", if_name,
+                     errno, _strerror(errno, strerr_buff));
+               close(sockfd);
+               return LIBISCSI_ERR_BUG;
+       }
+       close(sockfd);
+       snprintf(driver_name, _ETH_DRIVER_NAME_MAX_LEN, "%s", drvinfo.driver);
+
+       return LIBISCSI_OK;
+}
+
+int _eth_ifs_get(struct iscsi_context *ctx, struct _eth_if ***eifs,
+                uint32_t *eif_count)
+{
+       int rc = LIBISCSI_OK;
+       struct if_nameindex *if_ni = NULL;
+       struct if_nameindex *if_i = NULL;
+       struct _eth_if *eif = NULL;
+       uint32_t tmp_count = 0;
+
+       assert(ctx != NULL);
+       assert(eifs != NULL);
+       assert(eif_count != NULL);
+
+       *eifs = NULL;
+       *eif_count = 0;
+
+       if_ni = if_nameindex();
+       _alloc_null_check(ctx, if_ni, rc, out);
+
+       for (if_i = if_ni; if_i && if_i->if_index && if_i->if_name; ++if_i)
+               tmp_count++;
+
+       if (tmp_count == 0)
+               goto out;
+
+       *eifs = calloc(tmp_count, sizeof(struct _eth_if *));
+       _alloc_null_check(ctx, *eifs, rc, out);
+
+       for (if_i = if_ni; if_i && if_i->if_index && if_i->if_name; ++if_i) {
+               if (! _is_eth(ctx, if_i->if_name))
+                       continue;
+               eif = calloc(1, sizeof(struct _eth_if));
+               _alloc_null_check(ctx, eif, rc, out);
+               (*eifs)[(*eif_count)++] = eif;
+               snprintf(eif->if_name, sizeof(eif->if_name)/sizeof(char),
+                        "%s", if_i->if_name);
+               _good(_eth_driver_get(ctx, eif->if_name, eif->driver_name),
+                     rc, out);
+       }
+
+out:
+       if (rc != LIBISCSI_OK) {
+               _eth_ifs_free(*eifs, *eif_count);
+               *eifs = NULL;
+               *eif_count = 0;
+       }
+       if (if_ni != NULL)
+               if_freenameindex(if_ni);
+       return rc;
+}
+
+void _eth_ifs_free(struct _eth_if **eifs, uint32_t eif_count)
+{
+       uint32_t i = 0;
+
+       if ((eif_count == 0) || (eifs == NULL))
+               return;
+
+       for (; i < eif_count; ++i)
+               free(eifs[i]);
+       free(eifs);
+}
+
+void _scandir_free(struct dirent **namelist, int count)
+{
+       int i = 0;
+
+       if ((namelist == NULL) || (count == 0))
+               return;
+
+       for (i = count - 1; i >= 0; --i)
+               free(namelist[i]);
+       free(namelist);
+}
+
+int _scandir(struct iscsi_context *ctx, const char *dir_path,
+            struct dirent ***namelist, int *count)
+{
+       int rc = LIBISCSI_OK;
+       int errno_save = 0;
+
+       assert(ctx != NULL);
+       assert(dir_path != NULL);
+       assert(namelist != NULL);
+       assert(count != NULL);
+
+       *namelist = NULL;
+       *count = 0;
+
+       *count = scandir(dir_path, namelist, _scan_filter_skip_dot, alphasort);
+       if (*count < 0) {
+               errno_save = errno;
+               if (errno_save == ENOENT) {
+                       *count = 0;
+                       goto out;
+               }
+               if (errno_save == ENOMEM) {
+                       rc = LIBISCSI_ERR_NOMEM;
+                       goto out;
+               }
+               if (errno_save == ENOTDIR) {
+                       rc = LIBISCSI_ERR_BUG;
+                       _error(ctx, "Got ENOTDIR error when scandir %s",
+                              dir_path);
+                       goto out;
+               }
+               rc = LIBISCSI_ERR_BUG;
+               _error(ctx, "Got unexpected error %d when scandir %s",
+                      errno_save, dir_path);
+               goto out;
+       }
+
+out:
+       if (rc != LIBISCSI_OK) {
+               _scandir_free(*namelist, *count);
+               *namelist = NULL;
+               *count = 0;
+       }
+
+       return rc;
+}
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/misc.h b/pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/misc.h
new file mode 100644 (file)
index 0000000..ca46726
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Gris Ge <fge@redhat.com>
+ */
+#ifndef __ISCSI_USR_MISC_H__
+#define __ISCSI_USR_MISC_H__
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <assert.h>
+#include <stdarg.h>
+#include <dirent.h>
+#include <net/if.h>
+
+#include "libopeniscsiusr/libopeniscsiusr.h"
+
+#define _good(rc, rc_val, out) \
+       do { \
+               rc_val = rc; \
+               if (rc_val != LIBISCSI_OK) \
+                       goto out; \
+       } while(0)
+
+#define _asprintf(...) \
+       (asprintf(__VA_ARGS__) == -1 ? LIBISCSI_ERR_NOMEM : LIBISCSI_OK)
+
+__DLL_LOCAL void _iscsi_log(struct iscsi_context *ctx, int priority,
+                           const char *file, int line, const char *func_name,
+                           const char *format, ...);
+__DLL_LOCAL void _iscsi_log_stderr(struct iscsi_context *ctx, int priority,
+                                  const char *file, int line,
+                                  const char *func_name, const char *format,
+                                  va_list args);
+
+#define _iscsi_log_cond(ctx, prio, arg...) \
+       do { \
+               if ((ctx != NULL) && \
+                   (iscsi_context_log_priority_get(ctx) >= prio)) \
+                       _iscsi_log(ctx, prio, __FILE__, __LINE__, \
+                                  __FUNCTION__, ## arg); \
+       } while (0)
+
+#define _debug(ctx, arg...) \
+       _iscsi_log_cond(ctx, LIBISCSI_LOG_PRIORITY_DEBUG, ## arg)
+#define _info(ctx, arg...) \
+       _iscsi_log_cond(ctx, LIBISCSI_LOG_PRIORITY_INFO, ## arg)
+#define _warn(ctx, arg...) \
+       _iscsi_log_cond(ctx, LIBISCSI_LOG_PRIORITY_WARNING, ## arg)
+#define _error(ctx, arg...) \
+       _iscsi_log_cond(ctx, LIBISCSI_LOG_PRIORITY_ERROR, ## arg)
+
+#define _iscsi_getter_func_gen(struct_name, prop_name, prop_type) \
+       prop_type struct_name##_##prop_name##_get(struct struct_name *d) \
+       { \
+               assert(d != NULL); \
+               return d->prop_name; \
+       }
+
+/*
+ * Check pointer returned by malloc() or strdup() or calloc(), if NULL, set
+ * rc as LIBISCSI_ERR_NO_MEMORY, report error and goto goto_out.
+ */
+#define _alloc_null_check(ctx, ptr, rc, goto_out) \
+       do { \
+               if (ptr == NULL) { \
+                       rc = LIBISCSI_ERR_NOMEM; \
+                       _error(ctx, iscsi_strerror(rc)); \
+                       goto goto_out; \
+               } \
+       } while(0)
+
+#define _STRERR_BUFF_LEN       1024
+#define _strerror(err_no, buff) \
+       strerror_r(err_no, buff, _STRERR_BUFF_LEN)
+
+/* Workaround for suppress GCC 8 `stringop-truncation` warnings. */
+#define _strncpy(dst, src, size) \
+       do { \
+               memcpy(dst, src, \
+                      (size_t) size > strlen(src) ? \
+                      strlen(src) : (size_t) size); \
+               * (char *) (dst + \
+                           ((size_t) size - 1 > strlen(src) ? \
+                            strlen(src) : (size_t) (size - 1))) = '\0'; \
+       } while(0)
+
+__DLL_LOCAL int _scan_filter_skip_dot(const struct dirent *dir);
+
+__DLL_LOCAL bool _file_exists(const char *path);
+
+
+#define _ETH_DRIVER_NAME_MAX_LEN       32
+/* ^ Defined in linux/ethtool.h `struct ethtool_drvinfo`. */
+
+struct _eth_if {
+       char driver_name[_ETH_DRIVER_NAME_MAX_LEN];
+       char if_name[IF_NAMESIZE];
+};
+
+__DLL_LOCAL int _eth_ifs_get(struct iscsi_context *ctx,
+                            struct _eth_if ***eifs, uint32_t *eif_count);
+
+__DLL_LOCAL void _eth_ifs_free(struct _eth_if **eifs, uint32_t eif_count);
+
+__DLL_LOCAL int _scandir(struct iscsi_context *ctx, const char *dir_path,
+                        struct dirent ***namelist, int *count);
+__DLL_LOCAL void _scandir_free(struct dirent **namelist, int count);
+
+#endif /* End of __ISCSI_USR_MISC_H__ */
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/node.c b/pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/node.c
new file mode 100644 (file)
index 0000000..0bf357b
--- /dev/null
@@ -0,0 +1,297 @@
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Gris Ge <fge@redhat.com>
+ */
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+/* ^ For strerror_r() */
+#endif
+
+#include <stdlib.h>
+#include <stdbool.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+
+#include "libopeniscsiusr/libopeniscsiusr.h"
+#include "misc.h"
+#include "node.h"
+
+/* ptr is both input and output pointer.
+ * count is both input and output pointer.
+ * When success, both count and ptr will be updated.
+ * If fail, return LIBISCSI_ERR_NOMEM and no touch to old memory.
+ */
+static int _grow_node_array(struct iscsi_context *ctx,
+                           struct iscsi_node ***nodes, uint32_t *count)
+{
+       int rc = LIBISCSI_OK;
+       struct iscsi_node **tmp = NULL;
+       uint32_t i = 0;
+
+       _debug(ctx, "Growing node array from size %" PRIu32 " to %" PRIu32,
+              *count, *count * 2);
+
+       tmp = realloc(*nodes, *count * 2 * sizeof(struct iscsi_node *));
+       _alloc_null_check(ctx, tmp, rc, out);
+       for (i = *count; i < *count * 2; ++i)
+               tmp[i] = NULL;
+
+       *count *= 2;
+       *nodes = tmp;
+
+out:
+       return rc;
+}
+
+static int nodes_append(struct iscsi_context *ctx, struct iscsi_node ***nodes,
+                       uint32_t *real_node_count, uint32_t *array_size,
+                       struct iscsi_node *node)
+{
+       int rc = LIBISCSI_OK;
+       if (*real_node_count >= *array_size)
+               _good(_grow_node_array(ctx, nodes, array_size), rc, out);
+
+       (*nodes)[(*real_node_count)++] = node;
+
+out:
+       return rc;
+}
+
+int iscsi_nodes_get(struct iscsi_context *ctx, struct iscsi_node ***nodes,
+                   uint32_t *node_count)
+{
+       int rc = LIBISCSI_OK;
+       struct dirent **namelist = NULL;
+       int n = 0;
+       int i = 0;
+       int j = 0;
+       int k = 0;
+       struct iscsi_node *node = NULL;
+       uint32_t real_node_count = 0;
+       const char *target_name = NULL;
+       const char *portal = NULL;
+       const char *iface_name = NULL;
+       struct dirent **namelist_portals = NULL;
+       int p = 0;
+       struct dirent **namelist_ifaces = NULL;
+       int f = 0;
+       char *target_path = NULL;
+       char *path = NULL;
+       struct stat path_stat;
+       char strerr_buff[_STRERR_BUFF_LEN];
+
+       assert(ctx != NULL);
+       assert(nodes != NULL);
+       assert(node_count != NULL);
+
+       *nodes = NULL;
+       *node_count = 0;
+
+       _good(_idbm_lock(ctx), rc, out);
+
+       _good(_scandir(ctx, NODE_CONFIG_DIR, &namelist, &n), rc, out);
+       _debug(ctx, "Got %d target from %s nodes folder", n, NODE_CONFIG_DIR);
+       /*
+        * If continue with n == 0, calloc() might return a memory which failed
+        * to be freed in iscsi_nodes_free()
+        *
+        * So here just goto out to exit if n == 0
+        */
+       if (n == 0)
+               goto out;
+
+       *node_count = n & UINT32_MAX;
+       *nodes = (struct iscsi_node **) calloc(*node_count,
+                                              sizeof(struct iscsi_node *));
+       _alloc_null_check(ctx, *nodes, rc, out);
+
+       // New style of nodes folder:
+       //      <target_name>/<address>,<port>,<tpgt>/<iface_name>
+       // Old style of nodes folder:
+       //      <target_name>/<address>,<port>
+
+       for (i = 0; i < n; ++i) {
+               target_name = namelist[i]->d_name;
+               _good(_asprintf(&target_path, "%s/%s", NODE_CONFIG_DIR,
+                               target_name), rc, out);
+               _good(_scandir(ctx, target_path, &namelist_portals, &p),
+                     rc, out);
+               _debug(ctx, "Got %d portals from %s folder", p, target_path);
+               free(target_path);
+               target_path = NULL;
+               for (j = 0; j < p; ++j) {
+                       portal = namelist_portals[j]->d_name;
+                       _good(_asprintf(&path, "%s/%s/%s", NODE_CONFIG_DIR,
+                                       target_name, portal), rc, out);
+                       if (stat(path, &path_stat) != 0) {
+                               _warn(ctx, "Cannot stat path '%s': %d, %s",
+                                     path, errno,
+                                     _strerror(errno, strerr_buff));
+                               continue;
+                       }
+                       if (S_ISREG(path_stat.st_mode)) {
+                               // Old style of node
+                               _good(_idbm_node_get(ctx, target_name, portal,
+                                                    NULL, &node),
+                                     rc, out);
+                               _good(nodes_append(ctx, nodes,
+                                                  &real_node_count,
+                                                  node_count, node),
+                                     rc, out);
+                               continue;
+                       }
+                       if (! S_ISDIR(path_stat.st_mode)) {
+                               _warn(ctx, "Invalid iSCSI node configuration "
+                                     "file %s, it should be a file or "
+                                     "directory.", path);
+                               rc = LIBISCSI_ERR_IDBM;
+                               goto out;
+                       }
+                       _good(_scandir(ctx, path, &namelist_ifaces, &f), rc,
+                             out);
+                       _debug(ctx, "Got %d ifaces from %s folder", f, path);
+                       for (k = 0; k < f; ++k) {
+                               iface_name = namelist_ifaces[k]->d_name;
+                               _good(_idbm_node_get(ctx, target_name, portal,
+                                                    iface_name, &node),
+                                     rc, out);
+                               _good(nodes_append(ctx, nodes,
+                                                  &real_node_count,
+                                                  node_count, node),
+                                     rc, out);
+                       }
+                       free(path);
+                       path = NULL;
+                       _scandir_free(namelist_ifaces, f);
+                       namelist_ifaces = NULL;
+                       f = 0;
+               }
+               _scandir_free(namelist_portals, p);
+               namelist_portals = NULL;
+               p = 0;
+       }
+
+       *node_count = real_node_count;
+
+out:
+       free(path);
+       free(target_path);
+       _scandir_free(namelist, n);
+       _scandir_free(namelist_portals, p);
+       _scandir_free(namelist_ifaces, f);
+       _idbm_unlock(ctx);
+       if (rc != LIBISCSI_OK) {
+               iscsi_nodes_free(*nodes, *node_count);
+               *nodes = NULL;
+               *node_count = 0;
+       }
+       return rc;
+}
+
+void iscsi_nodes_free(struct iscsi_node **nodes, uint32_t node_count)
+{
+       uint32_t i = 0;
+
+       if ((nodes == NULL) || (node_count == 0))
+               return;
+
+       for (i = 0; i < node_count; ++i)
+               iscsi_node_free(nodes[i]);
+       free (nodes);
+}
+
+void iscsi_node_free(struct iscsi_node *node)
+{
+       free(node);
+}
+
+const char *iscsi_node_dump_config(struct iscsi_node *node, bool show_secret)
+{
+       FILE *f = NULL;
+       char *buff = NULL;
+
+       assert(node != NULL);
+
+       buff = calloc(1, IDBM_DUMP_SIZE);
+       if (buff == NULL)
+               return NULL;
+
+       f = fmemopen(buff, IDBM_DUMP_SIZE - 1, "w");
+       if (f == NULL) {
+               free(buff);
+               return NULL;
+       }
+
+       _idbm_node_print(node, f, show_secret);
+
+       fclose(f);
+
+       return buff;
+}
+
+void iscsi_node_print_config(struct iscsi_node *node, bool show_secret)
+{
+       assert(node != NULL);
+       _idbm_node_print(node, stdout, show_secret);
+}
+
+// TODO(Gris Ge): Convert below duplicated codes to macros.
+bool iscsi_node_conn_is_ipv6(struct iscsi_node *node)
+{
+       assert(node != NULL);
+       return node->conn.is_ipv6;
+}
+
+const char *iscsi_node_conn_address_get(struct iscsi_node *node)
+{
+       assert(node != NULL);
+       return node->conn.address;
+}
+
+uint32_t iscsi_node_conn_port_get(struct iscsi_node *node)
+{
+       assert(node != NULL);
+       return node->conn.port;
+}
+
+int32_t iscsi_node_tpgt_get(struct iscsi_node *node)
+{
+       assert(node != NULL);
+       return node->tpgt;
+}
+
+const char *iscsi_node_target_name_get(struct iscsi_node *node)
+{
+       assert(node != NULL);
+       return node->target_name;
+}
+
+const char *iscsi_node_iface_name_get(struct iscsi_node *node)
+{
+       assert(node != NULL);
+       return node->iface.name;
+}
+
+const char *iscsi_node_portal_get(struct iscsi_node *node)
+{
+       assert(node != NULL);
+       return node->portal;
+}
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/node.h b/pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/node.h
new file mode 100644 (file)
index 0000000..575c5d6
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Gris Ge <fge@redhat.com>
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE                    /* For NI_MAXHOST */
+#endif
+
+#ifndef __ISCSI_USR_NODE_H__
+#define __ISCSI_USR_NODE_H__
+
+#include <netdb.h>
+#include <stdint.h>
+
+#include "idbm.h"
+#include "iface.h"
+
+struct iscsi_node {
+       char                                    target_name[TARGET_NAME_MAXLEN];
+       int32_t                                 tpgt;
+       enum iscsi_startup_type                 startup;
+       enum leading_login_type                 leading_login;
+       struct iscsi_session_idbm               session;
+       struct iscsi_conn                       conn;
+       struct iscsi_iface                      iface;
+       enum discovery_type                     disc_type;
+       char                                    disc_address[NI_MAXHOST];
+       int32_t                                 disc_port;
+       char                                    portal[NI_MAXHOST * 2];
+};
+
+#define NODE_CONFIG_DIR                ISCSI_DB_ROOT"/nodes"
+
+/* Might be public in the future */
+__DLL_LOCAL void iscsi_node_free(struct iscsi_node *node);
+
+#endif /* End of __ISCSI_USR_NODE_H__ */
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/rfc.h b/pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/rfc.h
new file mode 100644 (file)
index 0000000..8f60652
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Gris Ge <fge@redhat.com>
+ */
+
+
+#ifndef _LIB_OPEN_ISCSI_USR_RFC_H_
+#define _LIB_OPEN_ISCSI_USR_RFC_H_
+
+#define ISCSI_DEFAULT_PORT             3260
+#define ISCSI_DEF_TIME2WAIT                    2
+
+#endif /* End of _LIB_OPEN_ISCSI_USR_RFC_H_ */
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/session.c b/pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/session.c
new file mode 100644 (file)
index 0000000..4d47592
--- /dev/null
@@ -0,0 +1,331 @@
+/*
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Gris Ge <fge@redhat.com>
+ */
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE                    /* For NI_MAXHOST */
+#endif
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <dirent.h>
+#include <limits.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <netdb.h>
+#include <string.h>
+#include <errno.h>
+
+#include "libopeniscsiusr/libopeniscsiusr.h"
+#include "misc.h"
+#include "sysfs.h"
+#include "iface.h"
+
+#define _ISCSI_NAME_MAX_LEN            223
+/* ^ RFC 3720:
+ *     Each iSCSI node, whether an initiator or target, MUST have an iSCSI
+ *     name.
+ *
+ *     Initiators and targets MUST support the receipt of iSCSI names of up
+ *     to the maximum length of 223 bytes.
+ */
+
+#define _ISCSI_CHAP_AUTH_STR_MAX_LEN   256
+/* ^ No official document found for this value, just copy from usr/auth.h
+ */
+
+struct iscsi_session {
+       uint32_t sid;
+       /* ^ It's actually a int according to Linux kernel code but
+        * the dev_set_name() in iscsi_add_session() of scsi_transport_iscsi.c
+        * are using %u to output this.
+        */
+       char persistent_address[NI_MAXHOST + 1];
+       int32_t persistent_port;
+       char target_name[_ISCSI_NAME_MAX_LEN + 1];
+       char username[_ISCSI_CHAP_AUTH_STR_MAX_LEN];
+       char password[_ISCSI_CHAP_AUTH_STR_MAX_LEN];
+       char username_in[_ISCSI_CHAP_AUTH_STR_MAX_LEN];
+       char password_in[_ISCSI_CHAP_AUTH_STR_MAX_LEN];
+       int32_t recovery_tmo;
+       /* ^ It's actually a int according to Linux kernel code.
+        */
+       int32_t lu_reset_tmo;
+       /* ^ It's actually a int according to Linux kernel code.
+        */
+       int32_t tgt_reset_tmo;
+       /* ^ It's actually a int according to Linux kernel code.
+        */
+       int32_t abort_tmo;
+       /* ^ It's actually a int according to Linux kernel code.
+        */
+       int32_t tpgt;
+       /* ^ It's actually a int according to Linux kernel code.
+        */
+       char address[NI_MAXHOST + 1];
+
+       int32_t port;
+       struct iscsi_iface *iface;
+};
+
+_iscsi_getter_func_gen(iscsi_session, sid, uint32_t);
+_iscsi_getter_func_gen(iscsi_session, persistent_address, const char *);
+_iscsi_getter_func_gen(iscsi_session, persistent_port, int32_t);
+_iscsi_getter_func_gen(iscsi_session, target_name, const char *);
+_iscsi_getter_func_gen(iscsi_session, username, const char *);
+_iscsi_getter_func_gen(iscsi_session, password, const char *);
+_iscsi_getter_func_gen(iscsi_session, username_in, const char *);
+_iscsi_getter_func_gen(iscsi_session, password_in, const char *);
+_iscsi_getter_func_gen(iscsi_session, recovery_tmo, int32_t);
+_iscsi_getter_func_gen(iscsi_session, lu_reset_tmo, int32_t);
+_iscsi_getter_func_gen(iscsi_session, tgt_reset_tmo, int32_t);
+_iscsi_getter_func_gen(iscsi_session, abort_tmo, int32_t);
+_iscsi_getter_func_gen(iscsi_session, tpgt, int32_t);
+_iscsi_getter_func_gen(iscsi_session, address, const char *);
+_iscsi_getter_func_gen(iscsi_session, port, int32_t);
+_iscsi_getter_func_gen(iscsi_session, iface, struct iscsi_iface *);
+
+int _iscsi_session_get(struct iscsi_context *ctx, uint32_t sid,
+                     struct iscsi_session **se, bool verbose)
+{
+       int rc = LIBISCSI_OK;
+       char *sysfs_se_dir_path = NULL;
+       char *sysfs_con_dir_path = NULL;
+       uint32_t host_id = 0;
+
+       assert(ctx != NULL);
+       assert(se != NULL);
+
+       _debug(ctx, "Querying iSCSI session for sid %" PRIu32, sid);
+
+       _good(_asprintf(&sysfs_se_dir_path, "%s/session%" PRIu32,
+                       _ISCSI_SYS_SESSION_DIR, sid), rc, out);
+       _good(_asprintf(&sysfs_con_dir_path, "%s/connection%" PRIu32 ":0",
+                       _ISCSI_SYS_CONNECTION_DIR, sid), rc, out);
+       /* ^ BUG(Gris Ge): ':0' here in kernel is referred as connection id.
+        *                 but the open-iscsi assuming it's always 0, need
+        *                 investigation.
+        */
+
+       *se = (struct iscsi_session *) calloc(1, sizeof(struct iscsi_session));
+       _alloc_null_check(ctx, *se , rc, out);
+
+       if (! _file_exists(sysfs_se_dir_path)) {
+               _info(ctx, "Sysfs path '%s' does not exist",
+                     sysfs_se_dir_path);
+               rc = LIBISCSI_ERR_SESS_NOT_FOUND;
+       }
+       if (! _file_exists(sysfs_con_dir_path)) {
+               _info(ctx, "Sysfs path '%s' does not exist",
+                     sysfs_se_dir_path);
+               rc = LIBISCSI_ERR_SESS_NOT_FOUND;
+       }
+       if (rc == LIBISCSI_ERR_SESS_NOT_FOUND) {
+               /* don't complain loudly if called through iscsi_sessions_get()
+                * the caller is not looking for a specific session,
+                * and the list could be changing as we work through it
+                */
+               if (verbose) {
+                       _error(ctx, "Specified SID %" PRIu32 " does not exist",
+                              sid);
+               }
+               goto out;
+       }
+
+       (*se)->sid = sid;
+       _good(_sysfs_prop_get_str(ctx, sysfs_se_dir_path, "targetname",
+                                (*se)->target_name,
+                                sizeof((*se)->target_name) / sizeof(char),
+                                NULL), rc, out);
+
+       _good(_sysfs_prop_get_str(ctx, sysfs_se_dir_path, "username",
+                                 (*se)->username,
+                                 sizeof((*se)->username) / sizeof(char),
+                                 ""),
+             rc, out);
+
+       _good(_sysfs_prop_get_str(ctx, sysfs_se_dir_path, "password",
+                                 (*se)->password,
+                                 sizeof((*se)->password) / sizeof(char),
+                                 ""),
+             rc, out);
+
+       _good(_sysfs_prop_get_str(ctx, sysfs_se_dir_path, "username_in",
+                                 (*se)->username_in,
+                                 sizeof((*se)->username_in) / sizeof(char),
+                                 ""),
+             rc, out);
+
+       _good(_sysfs_prop_get_str(ctx, sysfs_se_dir_path, "password_in",
+                                 (*se)->password_in,
+                                 sizeof((*se)->password_in) / sizeof(char),
+                                 ""),
+             rc, out);
+
+       _good(_sysfs_prop_get_i32(ctx, sysfs_se_dir_path, "recovery_tmo",
+                                 &((*se)->recovery_tmo), -1, true),
+             rc, out);
+
+       _good(_sysfs_prop_get_i32(ctx, sysfs_se_dir_path, "lu_reset_tmo",
+                                 &((*se)->lu_reset_tmo), -1, true),
+             rc, out);
+
+       _good(_sysfs_prop_get_i32(ctx, sysfs_se_dir_path, "tgt_reset_tmo",
+                                 &((*se)->tgt_reset_tmo), -1, true),
+             rc, out);
+
+       _good(_sysfs_prop_get_i32(ctx, sysfs_se_dir_path, "abort_tmo",
+                                 &((*se)->abort_tmo), -1, true),
+             rc, out);
+
+       _good(_sysfs_prop_get_i32(ctx, sysfs_se_dir_path, "tpgt",
+                                 &((*se)->tpgt), -1, true),
+             rc, out);
+
+       _good(_sysfs_prop_get_str(ctx, sysfs_con_dir_path, "persistent_address",
+                                 (*se)->persistent_address,
+                                 sizeof((*se)->persistent_address) /
+                                 sizeof(char), ""),
+             rc, out);
+
+       _good(_sysfs_prop_get_i32(ctx, sysfs_con_dir_path, "persistent_port",
+                                 &((*se)->persistent_port), -1, true),
+             rc, out);
+
+       _sysfs_prop_get_str(ctx, sysfs_con_dir_path, "address", (*se)->address,
+                           sizeof((*se)->address) / sizeof(char), "");
+
+       _sysfs_prop_get_i32(ctx, sysfs_con_dir_path, "port",
+                           &((*se)->port), -1, true);
+
+       if ((strcmp((*se)->address, "") != 0) &&
+           (strcmp((*se)->persistent_address, "") == 0))
+               _strncpy((*se)->persistent_address, (*se)->address,
+                        sizeof((*se)->persistent_address) / sizeof(char));
+       else if ((strcmp((*se)->address, "") == 0) &&
+           (strcmp((*se)->persistent_address, "") != 0))
+               _strncpy((*se)->address, (*se)->persistent_address,
+                        sizeof((*se)->address) / sizeof(char));
+
+       if (((*se)->persistent_port == -1) &&
+           ((*se)->port != -1))
+               (*se)->persistent_port = (*se)->port;
+       else if (((*se)->persistent_port != -1) &&
+                ((*se)->port == -1))
+               (*se)->port = (*se)->persistent_port;
+
+       _good(_iscsi_host_id_of_session(ctx, sid, &host_id), rc, out);
+
+       /* does this need to the correct iface_kern_id for the session? */
+       _good(_iscsi_iface_get_from_sysfs(ctx, host_id, sid, NULL, &((*se)->iface)),
+             rc, out);
+
+out:
+       if (rc != LIBISCSI_OK) {
+               iscsi_session_free(*se);
+               *se = NULL;
+       }
+       free(sysfs_se_dir_path);
+       free(sysfs_con_dir_path);
+       return rc;
+}
+
+int iscsi_session_get(struct iscsi_context *ctx, uint32_t sid,
+                     struct iscsi_session **se) {
+       return _iscsi_session_get(ctx, sid, se, true);
+}
+
+int iscsi_sessions_get(struct iscsi_context *ctx,
+                      struct iscsi_session ***sessions,
+                      uint32_t *session_count)
+{
+       int rc = LIBISCSI_OK;
+       uint32_t i = 0;
+       uint32_t j = 0;
+       uint32_t *sids = NULL;
+
+       assert(ctx != NULL);
+       assert(sessions != NULL);
+       assert(session_count != NULL);
+
+       *sessions = NULL;
+       *session_count = 0;
+
+       _good(_iscsi_sids_get(ctx, &sids, session_count), rc ,out);
+       if (!*session_count)
+               goto out;
+
+       *sessions = calloc (*session_count, sizeof(struct iscsi_session *));
+       _alloc_null_check(ctx, *sessions, rc, out);
+
+       for (i = 0; i < *session_count; ++i) {
+               _debug(ctx, "sid %" PRIu32, sids[i]);
+               rc = _iscsi_session_get(ctx, sids[i], &((*sessions)[j]), false);
+               if (rc == LIBISCSI_OK) {
+                       /* if session info was successfully read from sysfs, advance the sessions pointer */
+                       j++;
+               } else {
+                       /* if not, just ignore the issue and keep trying with the next session ID,
+                        * there's always going to be an inherent race against session removal when collecting
+                        * attribute data from sysfs
+                        */
+                       _debug(ctx, "Problem reading session %" PRIu32 ", skipping.", sids[i]);
+                       rc = LIBISCSI_OK;
+               }
+       }
+       /*
+        * reset session count and sessions array length to what we were able to read from sysfs
+        *
+        * do not use reallocarray() for the sessions array, since not all platforms
+        * have that function call
+        */
+       *session_count = j;
+       /* assert that there is no integer overflow in the realloc call */
+       assert(!(*session_count > (UINT_MAX / sizeof(struct iscsi_session *))));
+       *sessions =
+           realloc(*sessions, *session_count * sizeof(struct iscsi_session *));
+
+out:
+       free(sids);
+       if (rc != LIBISCSI_OK) {
+               iscsi_sessions_free(*sessions, *session_count);
+               *sessions = NULL;
+               *session_count = 0;
+       }
+       return rc;
+}
+
+void iscsi_session_free(struct iscsi_session *se)
+{
+       if (se != NULL)
+               iscsi_iface_free(se->iface);
+       free(se);
+}
+
+void iscsi_sessions_free(struct iscsi_session **ses, uint32_t se_count)
+{
+       uint32_t i = 0;
+
+       if ((ses == NULL) || (se_count == 0))
+               return;
+
+       for (i = 0; i < se_count; ++i)
+               iscsi_session_free(ses[i]);
+       free (ses);
+}
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/sysfs.c b/pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/sysfs.c
new file mode 100644 (file)
index 0000000..93cc1fe
--- /dev/null
@@ -0,0 +1,570 @@
+/*
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Gris Ge <fge@redhat.com>
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+#include <assert.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <regex.h>
+#include <dirent.h>
+#include <errno.h>
+
+#include "libopeniscsiusr/libopeniscsiusr_common.h"
+#include "sysfs.h"
+#include "misc.h"
+
+#define _INT32_STR_MAX_LEN             12
+/* ^ The max uint32_t is 4294967296 which requires 11 bytes for string.
+ *   The max/min in32_t is 2147483647 or -2147483646 which requires 12 bytes.
+ */
+
+#define _SYS_NULL_STR                  "(null)"
+
+#define _sysfs_prop_get_uint_func_gen(func_name, out_type, type_max_value) \
+       int func_name(struct iscsi_context *ctx, const char *dir_path, \
+                     const char *prop_name, out_type *val, \
+                     out_type default_value, bool ignore_error) \
+       { \
+               long long int tmp_val = 0; \
+               int rc = LIBISCSI_OK; \
+               long long int dv = default_value; \
+               rc = iscsi_sysfs_prop_get_ll(ctx, dir_path, prop_name, \
+                                            &tmp_val, (long long int) dv, \
+                                            ignore_error); \
+               if (rc == LIBISCSI_OK) \
+                       *val = tmp_val & type_max_value; \
+               return rc; \
+       }
+
+#define _sysfs_prop_get_int_func_gen(func_name, out_type, type_min_value, type_max_value) \
+       int func_name(struct iscsi_context *ctx, const char *dir_path, \
+                     const char *prop_name, out_type *val, \
+                     out_type default_value, bool ignore_error) \
+       { \
+               long long int tmp_val = 0; \
+               int rc = LIBISCSI_OK; \
+               long long int dv = default_value; \
+               rc = iscsi_sysfs_prop_get_ll(ctx, dir_path, prop_name, \
+                                            &tmp_val, (long long int) dv, \
+                                            ignore_error); \
+               if (rc == LIBISCSI_OK) { \
+                       if (tmp_val > type_max_value) \
+                               *val = type_max_value; \
+                       else if (tmp_val < type_min_value) \
+                               *val = type_min_value; \
+                       else \
+                               *val = tmp_val; \
+               } \
+               return rc; \
+       }
+
+
+enum _sysfs_dev_class {
+       _SYSFS_DEV_CLASS_ISCSI_SESSION,
+       _SYSFS_DEV_CLASS_ISCSI_HOST,
+};
+
+static int sysfs_read_file(const char *path, uint8_t *buff, size_t buff_size);
+static int iscsi_sysfs_prop_get_ll(struct iscsi_context *ctx,
+                                  const char *dir_path, const char *prop_name,
+                                  long long int *val,
+                                  long long int default_value,
+                                  bool ignore_error);
+
+/*
+ * dev_path needs to be freed by the caller on success
+ */
+static int sysfs_get_dev_path(struct iscsi_context *ctx, const char *path,
+                             enum _sysfs_dev_class class, char **dev_path);
+
+_sysfs_prop_get_uint_func_gen(_sysfs_prop_get_u8, uint8_t, UINT8_MAX);
+_sysfs_prop_get_uint_func_gen(_sysfs_prop_get_u16, uint16_t, UINT16_MAX);
+_sysfs_prop_get_int_func_gen(_sysfs_prop_get_i32, int32_t, INT32_MIN, INT32_MAX);
+_sysfs_prop_get_uint_func_gen(_sysfs_prop_get_u32, uint32_t, UINT32_MAX);
+
+static int sysfs_read_file(const char *path, uint8_t *buff, size_t buff_size)
+{
+       int fd = -1;
+       int errno_save = 0;
+       ssize_t readed = 0;
+       ssize_t i = 0;
+
+       assert(path != NULL);
+       assert(buff != NULL);
+       assert(buff_size != 0);
+
+       memset(buff, 0, buff_size);
+
+       fd = open(path, O_RDONLY);
+       if (fd < 0)
+               return errno;
+       readed = read(fd, buff, buff_size);
+       errno_save = errno;
+       close(fd);
+
+       if (readed < 0) {
+               buff[0] = '\0';
+               return errno_save;
+       }
+
+       buff[buff_size - 1] = '\0';
+       /* Remove the trailing \n */
+       for (i = readed - 1; i >= 0; --i) {
+               if (buff[i] == '\n') {
+                       buff[i] = '\0';
+                       break;
+               }
+       }
+
+       if (strcmp((char *) buff, _SYS_NULL_STR) == 0)
+               buff[0] = '\0';
+
+       return 0;
+}
+
+int _sysfs_prop_get_str(struct iscsi_context *ctx, const char *dir_path,
+                       const char *prop_name, char *buff, size_t buff_size,
+                       const char *default_value)
+{
+       char *file_path = NULL;
+       int rc = LIBISCSI_OK;
+       int errno_save = 0;
+
+       assert(dir_path != NULL);
+       assert(prop_name != NULL);
+       assert(buff != NULL);
+
+       _good(_asprintf(&file_path, "%s/%s", dir_path, prop_name), rc, out);
+
+       errno_save = sysfs_read_file(file_path, (uint8_t *) buff, buff_size);
+       if (errno_save != 0) {
+               if (errno_save == ENOENT) {
+                       if (default_value == NULL) {
+                               rc = LIBISCSI_ERR_SYSFS_LOOKUP;
+                               _error(ctx, "Failed to read '%s': "
+                                      "file '%s' does not exist", prop_name,
+                                      file_path);
+                       } else {
+                               _info(ctx, "Failed to read '%s': "
+                                     "file '%s' does not exist, "
+                                     "using default value %s", prop_name,
+                                     file_path, default_value);
+                               memcpy(buff, (void *) default_value,
+                                      strlen(default_value) + 1);
+                       }
+               } else if (errno_save == EACCES) {
+                       rc = LIBISCSI_ERR_ACCESS;
+                       _error(ctx, "Failed to read '%s': "
+                              "permission deny when reading '%s'", prop_name,
+                              file_path);
+               } else if (errno_save == ENOTCONN) {
+                       if (default_value == NULL) {
+                               rc = LIBISCSI_ERR_SYSFS_LOOKUP;
+                               _error(ctx, "Failed to read '%s': "
+                                      "error when reading '%s': "
+                                      "Target unavailable",
+                                      prop_name, file_path);
+                       } else {
+                               _info(ctx, "Failed to read '%s': "
+                                      "error when reading '%s': "
+                                      "Target unavailable, using default value '%s'",
+                                      prop_name, file_path, default_value);
+                               memcpy(buff, (void *) default_value,
+                                      strlen(default_value) + 1);
+                       }
+               } else {
+                       rc = LIBISCSI_ERR_BUG;
+                       _error(ctx, "Failed to read '%s': "
+                              "error when reading '%s': %d", prop_name,
+                              file_path, errno_save);
+               }
+       } else {
+               if ((buff[0] == '\0') && (default_value != NULL)) {
+                       memcpy(buff, (void *) default_value,
+                              strlen(default_value) + 1);
+                       _debug(ctx, "Open '%s', got NULL, using default value",
+                              file_path, default_value);
+               } else
+                       _debug(ctx, "Open '%s', got '%s'", file_path, buff);
+       }
+out:
+       free(file_path);
+       return rc;
+}
+
+static int iscsi_sysfs_prop_get_ll(struct iscsi_context *ctx,
+                                const char *dir_path, const char *prop_name,
+                                long long int *val,
+                                long long int default_value, bool ignore_error)
+{
+       char *file_path = NULL;
+       int rc = LIBISCSI_OK;
+       int errno_save = 0;
+       uint8_t buff[_INT32_STR_MAX_LEN];
+       long long int tmp_val = 0;
+
+       assert(dir_path != NULL);
+       assert(prop_name != NULL);
+       assert(val != NULL);
+
+       *val = 0;
+
+       _good(_asprintf(&file_path, "%s/%s", dir_path, prop_name), rc, out);
+
+       errno_save = sysfs_read_file(file_path, buff, _INT32_STR_MAX_LEN);
+       if (errno_save != 0) {
+               if (errno_save == ENOENT || errno_save == EINVAL) {
+                       if (! ignore_error) {
+                               rc = LIBISCSI_ERR_SYSFS_LOOKUP;
+                               _error(ctx, "Failed to read '%s': "
+                                      "file '%s' does not exist",
+                                      prop_name, file_path);
+                               goto out;
+                       } else {
+                               _info(ctx,
+                                      "Failed to read '%s': "
+                                     "File '%s' does not exist, using ",
+                                     "default value %lld",
+                                     prop_name, file_path, default_value);
+                               *val = default_value;
+                               goto out;
+                       }
+               } else if (errno_save == EACCES) {
+                       rc = LIBISCSI_ERR_ACCESS;
+                       _error(ctx, "Permission deny when reading '%s'",
+                              file_path);
+                       goto out;
+               } else if (errno_save == ENOTCONN) {
+                       if (!ignore_error) {
+                               rc = LIBISCSI_ERR_SYSFS_LOOKUP;
+                               _error(ctx, "Failed to read '%s': "
+                                       "error when reading '%s': "
+                                       "Target unavailable",
+                                       prop_name, file_path);
+                               goto out;
+                       } else {
+                               _info(ctx, "Failed to read '%s': "
+                                       "error when reading '%s': "
+                                       "Target unavailable, using default value %lld",
+                                       prop_name, file_path, default_value);
+                               *val = default_value;
+                               goto out;
+                       }
+               } else {
+                       rc = LIBISCSI_ERR_BUG;
+                       _error(ctx, "Error when reading '%s': %d", file_path,
+                              errno_save);
+                       goto out;
+               }
+       }
+
+       errno = 0;
+       tmp_val = strtoll((const char *) buff, NULL, 10 /* base */);
+       errno_save = errno;
+       if ((errno_save != 0) && (! ignore_error)) {
+               rc = LIBISCSI_ERR_BUG;
+               _error(ctx, "Sysfs: %s: Error when converting '%s' "
+                      "to number", file_path,  (char *) buff, errno_save);
+               goto out;
+       }
+
+       *val = tmp_val;
+
+       _debug(ctx, "Open '%s', got %lld", file_path, tmp_val);
+out:
+       free(file_path);
+       return rc;
+}
+
+static int sysfs_get_dev_path(struct iscsi_context *ctx, const char *path,
+                             enum _sysfs_dev_class class, char **dev_path)
+{
+       int rc = LIBISCSI_OK;
+       int errno_save = 0;
+       regex_t regex;
+       regmatch_t reg_match[2];
+       int reg_rc = 0;
+       int need_free_reg = 0;
+
+       assert(ctx != NULL);
+       assert(path != NULL);
+       assert(dev_path != NULL);
+
+       *dev_path = realpath(path, NULL);
+       if (*dev_path == NULL) {
+               errno_save = errno;
+               rc = LIBISCSI_ERR_SYSFS_LOOKUP;
+               _error(ctx, "realpath() failed on %s with error %d", path,
+                      errno_save);
+               goto out;
+       }
+
+       switch (class) {
+       case _SYSFS_DEV_CLASS_ISCSI_SESSION:
+               reg_rc = regcomp(&regex,
+                                "\\(.\\{1,\\}/devices/.\\{1,\\}/"
+                                "host[0-9]\\{1,\\}\\)/"
+                                "session[0-9]\\{1,\\}/iscsi_session/",
+                                0 /* no flag */);
+               break;
+       case _SYSFS_DEV_CLASS_ISCSI_HOST:
+               reg_rc = regcomp(&regex,
+                                "\\(.\\{1,\\}/devices/.\\{1,\\}/"
+                                "host[0-9]\\{1,\\}\\)/"
+                                "iscsi_host/",
+                                0 /* no flag */);
+               break;
+       default:
+               rc = LIBISCSI_ERR_BUG;
+               _error(ctx, "BUG: sysfs_get_dev_path(): got unknown class %d",
+                      class);
+               goto out;
+       }
+       if (reg_rc != 0) {
+               rc = LIBISCSI_ERR_SYSFS_LOOKUP;
+               _error(ctx, "regcomp() failed %d", reg_rc);
+               goto out;
+       }
+       need_free_reg = 1;
+       if (regexec(&regex, *dev_path, 2 /* count of max matches */,
+                   reg_match, 0 /* no flags */) != 0) {
+               rc = LIBISCSI_ERR_SYSFS_LOOKUP;
+               _error(ctx, "regexec() not match for %s", *dev_path);
+               goto out;
+       }
+
+       *(*dev_path + reg_match[1].rm_eo ) = '\0';
+
+       _debug(ctx, "Got dev path of '%s': '%s'", path, *dev_path);
+
+out:
+       if (need_free_reg)
+               regfree(&regex);
+       if (rc != LIBISCSI_OK) {
+               free(*dev_path);
+               *dev_path = NULL;
+       }
+       return rc;
+}
+
+int _iscsi_host_id_of_session(struct iscsi_context *ctx, uint32_t sid,
+                             uint32_t *host_id)
+{
+       int rc = LIBISCSI_OK;
+       char *sys_se_dir_path = NULL;
+       char *sys_dev_path = NULL;
+       char *sys_scsi_host_dir_path = NULL;
+       struct dirent **namelist = NULL;
+       int n = 0;
+       const char *host_id_str = NULL;
+       const char iscsi_host_dir_str[] = "/iscsi_host/";
+
+       assert(ctx != NULL);
+       assert(sid != 0);
+       assert(host_id != NULL);
+
+       _good(_asprintf(&sys_se_dir_path, "%s/session%" PRIu32,
+                       _ISCSI_SYS_SESSION_DIR, sid), rc, out);
+
+       *host_id = 0;
+
+       _good(sysfs_get_dev_path(ctx, sys_se_dir_path,
+                                _SYSFS_DEV_CLASS_ISCSI_SESSION, &sys_dev_path),
+             rc, out);
+
+       _good(_asprintf(&sys_scsi_host_dir_path, "%s%s",
+                       sys_dev_path, iscsi_host_dir_str), rc, out);
+
+       _good(_scandir(ctx, sys_scsi_host_dir_path, &namelist, &n), rc, out);
+
+       if (n != 1) {
+               rc = LIBISCSI_ERR_SYSFS_LOOKUP;
+               _error(ctx, "Got unexpected(should be 1) file in folder %s",
+                      sys_scsi_host_dir_path);
+               goto out;
+       }
+       host_id_str = namelist[0]->d_name;
+
+       if (sscanf(host_id_str, "host%" SCNu32, host_id) != 1) {
+               rc = LIBISCSI_ERR_SYSFS_LOOKUP;
+               _error(ctx, "sscanf() failed on string %s", host_id_str);
+               goto out;
+       }
+
+out:
+       _scandir_free(namelist, n);
+       free(sys_se_dir_path);
+       free(sys_dev_path);
+       free(sys_scsi_host_dir_path);
+       return rc;
+}
+
+static int _iscsi_ids_get(struct iscsi_context *ctx,
+                         uint32_t **ids, uint32_t *id_count,
+                         const char *dir_path, const char *file_prefix)
+{
+       int rc = LIBISCSI_OK;
+       struct dirent **namelist = NULL;
+       int n = 0;
+       uint32_t i = 0;
+       const char *id_str = NULL;
+       char fmt_buff[128];
+
+       assert(ctx != NULL);
+       assert(ids != 0);
+       assert(id_count != NULL);
+
+       *ids = NULL;
+       *id_count = 0;
+
+       _good(_scandir(ctx, dir_path, &namelist, &n), rc, out);
+       _debug(ctx, "Got %d iSCSI %s", n, file_prefix);
+
+       *id_count = n & UINT32_MAX;
+
+       *ids = calloc(*id_count, sizeof(uint32_t));
+       _alloc_null_check(ctx, *ids, rc, out);
+
+       snprintf(fmt_buff, sizeof(fmt_buff)/sizeof(char), "%s%%" SCNu32,
+                file_prefix);
+
+       for (i = 0; i < *id_count; ++i) {
+               id_str = namelist[i]->d_name;
+               if (sscanf(id_str, fmt_buff, &((*ids)[i])) != 1) {
+                       rc = LIBISCSI_ERR_SYSFS_LOOKUP;
+                       _error(ctx, "sscanf() failed on string %s",
+                              id_str);
+                       goto out;
+               }
+               _debug(ctx, "Got iSCSI %s id %" PRIu32, file_prefix, (*ids)[i]);
+       }
+
+out:
+       _scandir_free(namelist, n);
+       if (rc != LIBISCSI_OK) {
+               free(*ids);
+               *ids = NULL;
+               *id_count = 0;
+       }
+       return rc;
+}
+
+int _iscsi_sids_get(struct iscsi_context *ctx, uint32_t **sids,
+                   uint32_t *sid_count)
+{
+       return _iscsi_ids_get(ctx, sids, sid_count, _ISCSI_SYS_SESSION_DIR,
+                             "session");
+}
+
+int _iscsi_hids_get(struct iscsi_context *ctx, uint32_t **hids,
+                   uint32_t *hid_count)
+{
+       return _iscsi_ids_get(ctx, hids, hid_count, _ISCSI_SYS_HOST_DIR,
+                             "host");
+}
+
+bool _iscsi_transport_is_loaded(const char *transport_name)
+{
+       int rc = LIBISCSI_OK;
+       char *path = NULL;
+
+       if (transport_name == NULL)
+               return false;
+
+       _good(_asprintf(&path, "%s/%s", _ISCSI_SYS_TRANSPORT_DIR,
+                       transport_name), rc, out);
+
+       if (access(path, F_OK) == 0) {
+               free(path);
+               return true;
+       }
+out:
+       free(path);
+       return false;
+}
+
+int _iscsi_iface_kern_ids_of_host_id(struct iscsi_context *ctx,
+                                   uint32_t host_id,
+                                   char ***iface_kern_ids,
+                                   uint32_t *iface_count)
+{
+       char *sysfs_sh_path = NULL;
+       char *dev_path = NULL;
+       char *sysfs_iface_path = NULL;
+       int rc = LIBISCSI_OK;
+       struct dirent **namelist = NULL;
+       int n = 0;
+       uint32_t i = 0;
+
+       _good(_asprintf(&sysfs_sh_path, "%s/host%" PRIu32,
+                       _ISCSI_SYS_HOST_DIR, host_id), rc, out);
+
+       _good(sysfs_get_dev_path(ctx, sysfs_sh_path,
+                                _SYSFS_DEV_CLASS_ISCSI_HOST, &dev_path),
+             rc, out);
+
+       _good(_asprintf(&sysfs_iface_path, "%s/iscsi_iface", dev_path),
+             rc, out);
+
+       _good(_scandir(ctx, sysfs_iface_path, &namelist, &n), rc, out);
+
+       if (n == 0) {
+               /* this is OK, and needed for transport drivers like
+                * bnx2i and qedi */
+               rc = LIBISCSI_OK;
+               _debug(ctx, "No iSCSI interface for iSCSI host %" PRIu32,
+                      host_id);
+               goto out;
+       }
+
+       *iface_count = n;
+       *iface_kern_ids = calloc(*iface_count, sizeof(char *));
+       _alloc_null_check(ctx, *iface_kern_ids, rc, out);
+       for (i = 0; i < *iface_count; i++) {
+               (*iface_kern_ids)[i] = strdup(namelist[i]->d_name);
+               _alloc_null_check(ctx, (*iface_kern_ids)[i], rc, out);
+               _debug(ctx, "Found iSCSI iface '%s' for iSCSI host %" PRIu32,
+                      (*iface_kern_ids)[i], host_id);
+       }
+out:
+       if (rc != LIBISCSI_OK) {
+               for (i = 0; i < *iface_count; i++ ) {
+                       free((*iface_kern_ids)[i]);
+               }
+               free(*iface_kern_ids);
+               *iface_kern_ids = NULL;
+               *iface_count = 0;
+       }
+       _scandir_free(namelist, n);
+       free(sysfs_sh_path);
+       free(dev_path);
+       free(sysfs_iface_path);
+       return rc;
+}
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/sysfs.h b/pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/sysfs.h
new file mode 100644 (file)
index 0000000..768b989
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Gris Ge <fge@redhat.com>
+ */
+#ifndef __ISCSI_USR_SYSFS_H__
+#define __ISCSI_USR_SYSFS_H__
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include "libopeniscsiusr/libopeniscsiusr_common.h"
+
+#define _ISCSI_SYS_SESSION_DIR         "/sys/class/iscsi_session"
+#define _ISCSI_SYS_CONNECTION_DIR      "/sys/class/iscsi_connection"
+#define _ISCSI_SYS_HOST_DIR            "/sys/class/iscsi_host"
+#define _ISCSI_SYS_IFACE_DIR           "/sys/class/iscsi_iface"
+#define _ISCSI_SYS_TRANSPORT_DIR       "/sys/class/iscsi_transport"
+#define _SCSI_SYS_HOST_DIR             "/sys/class/scsi_host"
+
+/*
+ * When default_value == NULL, treat no such file as LIB_BUG.
+ */
+__DLL_LOCAL int _sysfs_prop_get_str(struct iscsi_context *ctx,
+                                   const char *dir_path, const char *prop_name,
+                                   char *buff, size_t buff_size,
+                                   const char *default_value);
+
+int _sysfs_prop_get_u8(struct iscsi_context *ctx, const char *dir_path,
+                      const char *prop_name, uint8_t *val,
+                      uint8_t default_value, bool ignore_error);
+
+int _sysfs_prop_get_u16(struct iscsi_context *ctx, const char *dir_path,
+                       const char *prop_name, uint16_t *val,
+                       uint16_t default_value, bool ignore_error);
+
+/*
+ * When default_value == UINT32_MAX, treat no such file as LIB_BUG.
+ */
+__DLL_LOCAL int _sysfs_prop_get_u32(struct iscsi_context *ctx,
+                                   const char *dir_path, const char *prop_name,
+                                   uint32_t *val, uint32_t default_value,
+                                   bool ignore_error);
+
+/*
+ * When default_value == INT32_MAX, treat no such file as LIB_BUG.
+ */
+__DLL_LOCAL int _sysfs_prop_get_i32(struct iscsi_context *ctx,
+                                   const char *dir_path, const char *prop_name,
+                                   int32_t *val, int32_t default_value,
+                                   bool ignore_error);
+
+__DLL_LOCAL int _iscsi_host_id_of_session(struct iscsi_context *ctx,
+                                         uint32_t sid, uint32_t *host_id);
+
+/*
+ * iface_kern_id returns an allocated (char *)[iface_count]
+ * that needs to be freed by the caller
+ */
+__DLL_LOCAL int _iscsi_iface_kern_ids_of_host_id(struct iscsi_context *ctx,
+                                                uint32_t host_id,
+                                                char ***iface_kern_ids,
+                                                uint32_t *iface_count);
+
+/*
+ * The memory of (uint32_t *sids) should be freed by free().
+ */
+__DLL_LOCAL int _iscsi_sids_get(struct iscsi_context *ctx,
+                               uint32_t **sids, uint32_t *sid_count);
+
+/*
+ * The memory of (uint32_t *hids) should be freed by free().
+ */
+__DLL_LOCAL int _iscsi_hids_get(struct iscsi_context *ctx, uint32_t **hids,
+                               uint32_t *hid_count);
+
+__DLL_LOCAL bool _iscsi_transport_is_loaded(const char *transport_name);
+
+#endif /* End of __ISCSI_USR_SYSFS_H__ */
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/tests/runtest.sh b/pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/tests/runtest.sh
new file mode 100755 (executable)
index 0000000..a4cedf2
--- /dev/null
@@ -0,0 +1,33 @@
+#!/bin/bash
+
+if [ "CHK$TESTS"  == "CHK" ];then
+    echo "# No test cases defined"
+    exit 1
+fi
+
+VALGRIND_ERR_RC=2
+VALGRIND_OPTS="--quiet --leak-check=full \
+               --show-reachable=no --show-possibly-lost=no \
+               --trace-children=yes --error-exitcode=$VALGRIND_ERR_RC"
+
+TEST_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+
+for TEST in $TESTS; do
+    echo
+    TEST=$(basename $TEST)
+    echo "## RUN  '$TEST'"
+    valgrind $VALGRIND_OPTS $TEST_DIR/$TEST
+    rc=$?
+    if [ $rc -ne 0 ]; then
+        if [ $rc -eq $VALGRIND_ERR_RC ];then
+            echo
+            echo "### Found memory leak"
+            exit $rc
+        fi
+        exit $rc
+    fi
+    echo "## PASS '$TEST'"
+done
+
+echo
+echo "# All PASS"
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/tests/test_context.c b/pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/tests/test_context.c
new file mode 100644 (file)
index 0000000..d1b8fc8
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Gris Ge <fge@redhat.com>
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include <libopeniscsiusr/libopeniscsiusr.h>
+
+int main(void)
+{
+       struct iscsi_context *ctx = NULL;
+       int rc = EXIT_SUCCESS;
+       int i = 0;
+
+       ctx = iscsi_context_new();
+       assert(ctx != NULL);
+       iscsi_context_log_priority_set(ctx, LIBISCSI_LOG_PRIORITY_DEBUG);
+       assert(iscsi_context_log_priority_get(ctx) ==
+              LIBISCSI_LOG_PRIORITY_DEBUG);
+       iscsi_context_log_func_set(ctx, NULL);
+       iscsi_context_userdata_set(ctx, (void *) &i);
+       assert(* (int *) iscsi_context_userdata_get(ctx) == 0);
+
+       iscsi_context_free(ctx);
+       exit(rc);
+}
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/tests/test_iface.c b/pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/tests/test_iface.c
new file mode 100644 (file)
index 0000000..f3ad8c6
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenifaces/>.
+ *
+ * Author: Gris Ge <fge@redhat.com>
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <string.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <assert.h>
+
+#include <libopeniscsiusr/libopeniscsiusr.h>
+
+#define _assert_print_prop_str_can_empty(struct_name, obj, prop_name) \
+       do { \
+               assert(struct_name##_##prop_name##_get(obj) != NULL); \
+               printf("\t" # prop_name ": '%s'\n", \
+                      struct_name##_##prop_name##_get(obj)); \
+       } while(0)
+
+#define _assert_print_prop_str_not_empty(struct_name, obj, prop_name) \
+       do { \
+               assert(struct_name##_##prop_name##_get(obj) != NULL); \
+               assert(strlen(struct_name##_##prop_name##_get(obj)) != 0); \
+               printf("\t" # prop_name ": '%s'\n", \
+                      struct_name##_##prop_name##_get(obj)); \
+       } while(0)
+
+static void test_iface(struct iscsi_context *ctx, struct iscsi_iface *iface)
+{
+       struct iscsi_iface *tmp_iface = NULL;
+       const char *conf = NULL;
+
+       assert(iface != NULL);
+       printf("\t#### Interface info ####\n");
+       _assert_print_prop_str_not_empty(iscsi_iface, iface, name);
+       if (! iscsi_is_default_iface(iface)) {
+               assert(iscsi_iface_get(ctx, iscsi_iface_name_get(iface),
+                                      &tmp_iface) == LIBISCSI_OK);
+               _assert_print_prop_str_can_empty(iscsi_iface, tmp_iface,
+                                                ipaddress);
+               _assert_print_prop_str_can_empty(iscsi_iface, tmp_iface,
+                                                transport_name);
+               _assert_print_prop_str_can_empty(iscsi_iface, tmp_iface, iname);
+               _assert_print_prop_str_can_empty(iscsi_iface, tmp_iface,
+                                                hwaddress);
+               _assert_print_prop_str_can_empty(iscsi_iface, tmp_iface,
+                                                netdev);
+               _assert_print_prop_str_can_empty(iscsi_iface, tmp_iface,
+                                                port_state);
+               _assert_print_prop_str_can_empty(iscsi_iface, tmp_iface,
+                                                port_speed);
+               iscsi_iface_free(tmp_iface);
+       }
+       printf("\t########################\n");
+
+       conf = iscsi_iface_dump_config(iface);
+       assert(conf != NULL);
+       free((char *) conf);
+       iscsi_iface_print_config(iface);
+}
+
+int main()
+{
+       struct iscsi_context *ctx = NULL;
+       struct iscsi_iface **ifaces = NULL;
+       uint32_t iface_count = 0;
+       uint32_t i = 0;
+       int rc = EXIT_SUCCESS;
+
+       ctx = iscsi_context_new();
+       iscsi_context_log_priority_set(ctx, LIBISCSI_LOG_PRIORITY_DEBUG);
+
+       if (iscsi_default_iface_setup(ctx) != LIBISCSI_OK) {
+               printf("FAILED\n");
+               rc = EXIT_FAILURE;
+       }
+
+       if (iscsi_ifaces_get(ctx, &ifaces, &iface_count) != LIBISCSI_OK) {
+               printf("FAILED\n");
+               rc = EXIT_FAILURE;
+       } else {
+               assert(iface_count >= 2);
+               /* we will have at least the default ifaces:
+                * iser and iscsi_tcp
+                */
+               printf("\nGot %" PRIu32 " iSCSI ifaces\n", iface_count);
+               for (i = 0; i < iface_count; ++i) {
+                       test_iface(ctx, ifaces[i]);
+               }
+               iscsi_ifaces_free(ifaces, iface_count);
+       }
+       iscsi_context_free(ctx);
+       exit(rc);
+}
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/tests/test_node.c b/pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/tests/test_node.c
new file mode 100644 (file)
index 0000000..7ff7e9b
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Gris Ge <fge@redhat.com>
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <inttypes.h>
+
+#include <libopeniscsiusr/libopeniscsiusr.h>
+
+int main()
+{
+       struct iscsi_context *ctx = NULL;
+       struct iscsi_node **nodes = NULL;
+       uint32_t node_count = 0;
+       uint32_t i = 0;
+       const char *dump = NULL;
+       int rc = EXIT_SUCCESS;
+
+       ctx = iscsi_context_new();
+       iscsi_context_log_priority_set(ctx, LIBISCSI_LOG_PRIORITY_DEBUG);
+
+       if (iscsi_nodes_get(ctx, &nodes, &node_count) != LIBISCSI_OK) {
+               printf("FAILED\n");
+               rc = EXIT_FAILURE;
+       } else {
+               printf("\nGot %" PRIu32 " iSCSI nodes\n", node_count);
+               for (i = 0; i < node_count; ++i) {
+                       dump = iscsi_node_dump_config(nodes[i], true);
+                       assert(dump != NULL);
+                       free((void *) dump);
+                       iscsi_node_print_config(nodes[i], true);
+               }
+               iscsi_nodes_free(nodes, node_count);
+       }
+       iscsi_context_free(ctx);
+       exit(rc);
+}
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/tests/test_session.c b/pkgs/open-iscsi/open-iscsi-2.1.8/libopeniscsiusr/tests/test_session.c
new file mode 100644 (file)
index 0000000..0f23f2e
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Gris Ge <fge@redhat.com>
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <string.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <assert.h>
+
+#include <libopeniscsiusr/libopeniscsiusr.h>
+
+#define _assert_print_prop_str_can_empty(struct_name, obj, prop_name) \
+       do { \
+               assert(struct_name##_##prop_name##_get(obj) != NULL); \
+               printf("\t" # prop_name ": '%s'\n", \
+                      struct_name##_##prop_name##_get(obj)); \
+       } while(0)
+
+#define _assert_print_prop_str_not_empty(struct_name, obj, prop_name) \
+       do { \
+               assert(struct_name##_##prop_name##_get(obj) != NULL); \
+               assert(strlen(struct_name##_##prop_name##_get(obj)) != 0); \
+               printf("\t" # prop_name ": '%s'\n", \
+                      struct_name##_##prop_name##_get(obj)); \
+       } while(0)
+
+#define _assert_print_prop_u32_not_zero(struct_name, obj, prop_name) \
+       do { \
+               assert(struct_name##_##prop_name##_get(obj) != 0); \
+               printf("\t" # prop_name ": %" PRIu32 "\n", \
+                      struct_name##_##prop_name##_get(obj)); \
+       } while(0)
+
+#define _assert_print_prop_i32_not_zero(struct_name, obj, prop_name) \
+       do { \
+               assert(struct_name##_##prop_name##_get(obj) != 0); \
+               printf("\t" # prop_name ": %" PRIi32 "\n", \
+                      struct_name##_##prop_name##_get(obj)); \
+       } while(0)
+
+static void test_session(struct iscsi_session *se);
+static void test_iface(struct iscsi_iface *iface);
+
+static void test_iface(struct iscsi_iface *iface)
+{
+       assert(iface != NULL);
+       printf("\t#### Interface info ####\n");
+       _assert_print_prop_str_not_empty(iscsi_iface, iface, name);
+       _assert_print_prop_str_not_empty(iscsi_iface, iface, ipaddress);
+       _assert_print_prop_str_not_empty(iscsi_iface, iface, transport_name);
+       _assert_print_prop_str_not_empty(iscsi_iface, iface, iname);
+       _assert_print_prop_str_can_empty(iscsi_iface, iface, hwaddress);
+       _assert_print_prop_str_can_empty(iscsi_iface, iface, netdev);
+       _assert_print_prop_str_can_empty(iscsi_iface, iface, port_state);
+       _assert_print_prop_str_can_empty(iscsi_iface, iface, port_speed);
+       printf("\t########################\n");
+}
+
+static void test_session(struct iscsi_session *se)
+{
+       assert(se != NULL);
+       printf("Session %" PRIu32 ":\n", iscsi_session_sid_get(se));
+
+       _assert_print_prop_u32_not_zero(iscsi_session, se, sid);
+       _assert_print_prop_str_not_empty(iscsi_session, se, persistent_address);
+       _assert_print_prop_i32_not_zero(iscsi_session, se, persistent_port);
+       _assert_print_prop_str_not_empty(iscsi_session, se, target_name);
+       _assert_print_prop_str_can_empty(iscsi_session, se, username);
+       _assert_print_prop_str_can_empty(iscsi_session, se, password);
+       _assert_print_prop_str_can_empty(iscsi_session, se, username_in);
+       _assert_print_prop_str_can_empty(iscsi_session, se, password_in);
+       _assert_print_prop_u32_not_zero(iscsi_session, se, recovery_tmo);
+       _assert_print_prop_u32_not_zero(iscsi_session, se, lu_reset_tmo);
+       _assert_print_prop_u32_not_zero(iscsi_session, se, tgt_reset_tmo);
+       _assert_print_prop_u32_not_zero(iscsi_session, se, abort_tmo);
+       _assert_print_prop_u32_not_zero(iscsi_session, se, tpgt);
+       _assert_print_prop_str_not_empty(iscsi_session, se, address);
+       _assert_print_prop_i32_not_zero(iscsi_session, se, port);
+}
+
+int main()
+{
+       struct iscsi_context *ctx = NULL;
+       struct iscsi_session **ses = NULL;
+       uint32_t se_count = 0;
+       uint32_t i = 0;
+       int rc = EXIT_SUCCESS;
+
+       ctx = iscsi_context_new();
+       iscsi_context_log_priority_set(ctx, LIBISCSI_LOG_PRIORITY_DEBUG);
+
+       if (iscsi_sessions_get(ctx, &ses, &se_count) != LIBISCSI_OK) {
+               printf("FAILED\n");
+               rc = EXIT_FAILURE;
+       } else {
+               printf("\nGot %" PRIu32 " iSCSI sessions\n", se_count);
+               for (i = 0; i < se_count; ++i) {
+                       test_session(ses[i]);
+                       test_iface(iscsi_session_iface_get(ses[i]));
+               }
+               iscsi_sessions_free(ses, se_count);
+       }
+       iscsi_context_free(ctx);
+       exit(rc);
+}
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/meson_options.txt b/pkgs/open-iscsi/open-iscsi-2.1.8/meson_options.txt
new file mode 100644 (file)
index 0000000..b76f044
--- /dev/null
@@ -0,0 +1,20 @@
+# options for meson build system
+option('systemddir', type: 'string', value: '/usr/lib/systemd',
+  description: 'Systemd directory [/usr/lib/systemd], if systemd used')
+option('no_systemd', type: 'boolean', value: false,
+  description: 'Do not use systemd')
+option('source_date_epoch', type: 'string', value: 'NONE',
+  description: 'Set the Build Source Date (for iscsiuio), for repeatable builds')
+# these are in the 'sysconfigdir' (/etc by default) unless overridden
+option('homedir', type: 'string', value: 'iscsi',
+  description: 'Set the HOME directory [/etc/iscsi]')
+option('dbroot', type: 'string', value: 'iscsi',
+  description: 'Set the DATABASE root directory [/etc/iscsi]')
+option('lockdir', type: 'string', value: '/run/lock/iscsi',
+  description: 'Set the LOCK_DIR directory [/run/lock/iscsi]')
+option('rulesdir', type: 'string', value: 'udev/rules.d',
+  description: 'Set the directory where udev rules go [/etc/udev/rules.d]')
+# to be able to put binaries in /sbin or /usr/sbin, since
+# older version of meson do not allow overriding sbindir
+option('iscsi_sbindir', type: 'string', value: '/usr/sbin',
+  description: 'Set the directory where our binaries go [/usr/sbin]')
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/sysdeps/Makefile b/pkgs/open-iscsi/open-iscsi-2.1.8/sysdeps/Makefile
new file mode 100644 (file)
index 0000000..d419dba
--- /dev/null
@@ -0,0 +1,20 @@
+# This Makefile will work only with GNU make.
+
+CFLAGS ?= -O2 -fno-inline -g
+CFLAGS += $(WARNFLAGS) -Wall -Wstrict-prototypes
+
+SYSDEPS_OBJS=sysdeps.o
+
+all: $(SYSDEPS_OBJS)
+
+clean:
+       $(RM) *.o .depend
+
+distclean: ;
+
+.PHONY: all clean distclean depend
+
+depend:
+       $(CC) $(CFLAGS) -M `ls *.c` > .depend
+
+-include .depend
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/sysdeps/sysdeps.c b/pkgs/open-iscsi/open-iscsi-2.1.8/sysdeps/sysdeps.c
new file mode 100644 (file)
index 0000000..e39730d
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2003 Greg Kroah-Hartman <greg@kroah.com>
+ * Copyright (C) 2005-2006 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ *     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 version 2 of the License.
+ *
+ *     This program is distributed in the hope that it will be useful, but
+ *     WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *     General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License along
+ *     with this program; if not, write to the Free Software Foundation, Inc.,
+ *     51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/types.h>
+
+#ifdef __GLIBC__
+size_t strlcpy(char *dst, const char *src, size_t size)
+{
+       size_t bytes = 0;
+       char *q = dst;
+       const char *p = src;
+       char ch;
+
+       while ((ch = *p++)) {
+               if (bytes+1 < size)
+                       *q++ = ch;
+               bytes++;
+       }
+
+       /* If size == 0 there is no space for a final null... */
+       if (size)
+               *q = '\0';
+       return bytes;
+}
+
+size_t strlcat(char *dst, const char *src, size_t size)
+{
+       size_t bytes = 0;
+       char *q = dst;
+       const char *p = src;
+       char ch;
+
+       while (bytes < size && *q) {
+               q++;
+               bytes++;
+       }
+       if (bytes == size)
+               return (bytes + strlen(src));
+
+       while ((ch = *p++)) {
+               if (bytes+1 < size)
+                       *q++ = ch;
+               bytes++;
+       }
+
+       *q = '\0';
+       return bytes;
+}
+#endif /* __GLIBC__ */
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/sysfs-documentation b/pkgs/open-iscsi/open-iscsi-2.1.8/sysfs-documentation
new file mode 100644 (file)
index 0000000..3f3a5dd
--- /dev/null
@@ -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 Gratuitous 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/pkgs/open-iscsi/open-iscsi-2.1.8/test/.gitignore b/pkgs/open-iscsi/open-iscsi-2.1.8/test/.gitignore
new file mode 100644 (file)
index 0000000..8ac4f0c
--- /dev/null
@@ -0,0 +1,3 @@
+__pycache__
+\#*#
+.#*
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/test/README b/pkgs/open-iscsi/open-iscsi-2.1.8/test/README
new file mode 100644 (file)
index 0000000..c98175a
--- /dev/null
@@ -0,0 +1,239 @@
+---------------------------------------------------------------------------
+
+======
+README
+======
+
+--------------------
+Setting up the tests
+--------------------
+
+  This is the README for the updated "test" open-iscsi subdirectory.
+
+  Note that these tests are *not* performance tests. So no
+  attempt is made to track or display how long each test takes,
+  so it is not currently possible to track any improvement
+  nor degredation in IO performance. Please feel free to
+  add tests to measure performance, if you wish.
+
+  The tests here are based on the python unittest package. Please use
+  the included "test-open-iscsi.py" python script to run the tests.
+  You can run:
+
+    # ./test-open-iscsi.py --help
+
+  to get a list of options for this script. You will need the following
+  packages or commands to run these tests:
+
+  * fio
+  * bonie++
+  * mkfs.FSTYPE (e.g. mkfs.ext3)
+  * sgdisk
+  * dd
+  * parted
+  * mount/umount
+  * iscsiadm (with the iscsid daemon or service running) [of course]
+
+
+-----------------
+Running the tests
+-----------------
+
+  You will also need to know the IQN (name) of an accesable iscsi target,
+  set up with appropriate access controls so that you can log into it,
+  as well as the IP address where you can access this
+  target, and you will need to know which SCSI disk will show in in
+  /dev for this target (e.g. "/dev/sdc", if you already have a "/dev/sda"
+  and a "/dev/sdb"). You will need to pass in this information to the
+  python script to test. For example, to run all tests on my test
+  system (as root, of course):
+
+    # ./test-open-iscsi.py -v -f \
+        -t iqn.2003-01.org.linux-iscsi.linux-o2br.x8664:sn.2296be998e2c \
+       -i 192.168.20.168 \
+       -D /dev/sdc
+
+  This can take quite a while to run -- hours -- unless you limit
+  the tests to a subset of the whole suite.
+
+  The data on your target iSCSI disc will be wiped, so don't use a target
+  that has data you wish to save. As far as the size of the target, I
+  set up a 10G block-based iscsi target. Having a larger target makes
+  the test run take longer, though. I believe 1G or even 100M might work?
+
+  Instead of running all the tests, one can instead run a subtest, since
+  the unittest package supports this. To get a list of the tests, run:
+
+    # ./test-open-iscsi.py -l
+    test_HdrDigest_on_DataDigest_off (harness.tests.TestRegression)
+    test_HdrDigest_on_DataDigest_on (harness.tests.TestRegression)
+    test_InitialR2T_off_ImmediateData_off (harness.tests.TestRegression)
+    test_InitialR2T_off_ImmediateData_on (harness.tests.TestRegression)
+    test_InitialR2T_on_ImmediateData_off (harness.tests.TestRegression)
+    test_InitialR2T_on_ImmediateData_on (harness.tests.TestRegression)
+
+  I believe the names are self-explanitory. (If not, submit a pull
+  request or let me know.)
+
+  There are 6 test groups, all coming from one test script file (in
+  harness/tests.py), and that are in the the TestRegression python class.
+
+  [In the future, one can add more tests to this class, and other
+  classes to test things besides regression (like functionality,
+  bug-fix detection, etc).]
+
+  See below for an exapmle of how you might use this option.
+
+  One can also specify the list of subtests (by number) for each test,
+  further reducing test executing amount and time, if one wishes, using
+  the "-l/--list" option. Each subtest specifies a different
+  combination of FirstBurst, MaxBurstLength, and MaxRecv for the IO test.
+  Here's a list of the subest values:
+
+    Subtest   [FirstBurstLength, MaxBurstLength, MaxRecvDataSegmentLength]
+        1          4096             4096            4096
+        2          8192             4096            4096
+        3         16384             4096            4096
+        4         32768             4096            4096
+        5         65536             4096            4096
+        6        131972             4096            4096
+        7          4096             8192            4096
+        8          4096            16384            4096
+        9          4096            32768            4096
+       10          4096            65536            4096
+       11          4096           131072            4096
+       12          4096             4096            8192
+       13          4096             4096           16384
+       14          4096             4096           32768
+       15          4096             4096           65536
+       16          4096             4096          131072
+
+  So to run subtest 7 through 11 of test_InitialR2T_off_ImmediateData_off:
+
+    # ... (fill in)                                                                    << TODO XXX
+
+  Lastly, one can reduce the number of tests run (and hence the length of
+  time spent testing) by specifying the block size to test with during
+  IO testing. By default the script uses an array of block sizes:
+
+       [512,1k,2k,4k,8k,16k,32k,75536,128k,1000000]
+
+  For example, to run a test for block size 4k, all subtest 12, for
+  the test_HdrDigest_on_DataDigest_on test:
+
+    # ./test-open-iscsi.py -v -f \
+        -t iqn.2003-01.org.linux-iscsi.linux-o2br.x8664:sn.2296be998e2c \
+       -i 192.168.20.168 \
+       -D /dev/sdc \
+       -B 4k \
+       -s 12 \
+       TestRegression.test_HdrDigest_on_DataDigest_on
+
+
+------------------
+Test Descriptsions
+------------------
+
+  The "regression" test sequence was laid out in regression.sh (the
+  previous test script, still around for reference). I am not sure
+  why we still call it a regression test, when it does not in fact
+  check for any regression in performance. Instead, it tests
+  functionality.
+
+  Each iscsi test has the following default values
+  (called "IscsiData()" in the test suite). These correspond to
+  the default values usually found in open-iscsi:
+
+    Immediate Data             = on
+    Initial Request to Transmit        = off
+    Header Digest              = 'None,CRC32C' (i.e. off by default)
+    Data Digest                        = 'None,CRC32C' (i.e. off by default)
+    First Burst Length         = 256k
+    Max Burst Length           = (16 Meg - 1k)
+    Max Receive Data Length    = 128k
+    Max Request to Transmit    = 1
+
+  but one or more of these values can be overwritten for each test.
+
+  The current test suite is laid out like this:
+
+    test_HdrDigest_on_DataDigest_off (harness.tests.TestRegression)
+
+       This tests the Header Digest functionality, by itself.
+
+    test_HdrDigest_on_DataDigest_on (harness.tests.TestRegression)
+
+       This one tests both the Header and Data Digest functionality,
+       together
+
+    test_InitialR2T_off_ImmediateData_off (harness.tests.TestRegression)
+
+       Test both Initial Rquest to Transmit and Imediate data off
+
+    test_InitialR2T_off_ImmediateData_on (harness.tests.TestRegression)
+
+       Test with Initial Request to Transmit off but Imeediate Data
+       on. (This is the default configuration)
+
+    test_InitialR2T_on_ImmediateData_off (harness.tests.TestRegression)
+
+       Test Initial Request to Transmit on but Imediate Data off
+
+    test_InitialR2T_on_ImmediateData_on (harness.tests.TestRegression)
+
+       Test with both Initial Request to Transmit and Immediate Data
+       on.
+
+  For each test run (from this list above), we perform the following tests:
+
+    - Use "iscsiadm" to log into the iscsi target and wait for the
+      device to show up
+    - Run "fio" on the raw disc device
+       This is done 16 times, one for each subtest (see above)
+         Each of these 16 tests has 10 different block sizes used
+         (see above)
+         fio actually does (for each block size):
+         - fio read test (8 threads)
+         - fio write test (8 threads)
+         - fio verify test (1 thread)
+    - Run "parted" to partition
+       This actually first runs "sgdisk" then "dd" to wipe the disc,
+       then runs "parted" make a label then partition it, then
+       waits for the partition to show up.
+    - Run "mkfs" to create a filesystem (EXT3 by default)
+    - Run "bonnie++" on the created filesystem
+
+  For the math-friendly out there, I believe this adds up to about
+  960 tests (10x16x6). By far the slowest part of the tests seems
+  to be wiping the discs clean of a label or partitions. Perhaps this
+  can be sped up?
+
+  The following things can be overridden in the environment, if you
+  wish, by setting the appropriate environment variable before running
+  the test script:
+
+    env. var.          default                 meaning
+    ---------          -------                 -------
+    FSTYPE             "ext3"                  filesystem type to create
+    MOUNTOPTIONS       "-t FSTYPE"             "-t FSTYPE" is added to whatever
+                                               options you pass in, if any
+    MKFSCMD            "mkfs.FSTYPE"           which mkfs command to call
+    MKFSOPTS           <none>                  options too add to mkfs call,
+                                               if any
+    BONNIEPARAMS       "-r0 -n10:0:0 -s16 -uroot -f -q"
+                                               params used when running bonnie++
+
+-----------------------------------
+Suggestions for running these tests
+-----------------------------------
+
+  I suggest the following values for setting up these tests:
+
+  - Set up a smaller target -- maybe 100M -- which makes tests run faster
+  - Ensure that noop_out_* values are 0 (NOPs off) for your target
+  - Use the local system for your target, to avoid network/switch delays
+  - If there are failures, check dmesg for possible error messages
+  - If you use targetcli for your target, disable NOP-INs on the
+    target ACL attributes
+
+---------------------------------------------------------------------------
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/test/TODO b/pkgs/open-iscsi/open-iscsi-2.1.8/test/TODO
new file mode 100644 (file)
index 0000000..37af59f
--- /dev/null
@@ -0,0 +1,64 @@
+#
+# Things to do for testing
+#
+
+* ensure user is root? -- easy to do
+
+* have tests create their own target using targetcli and
+  a file? -- this would be much better, but would pull
+  in a requirement for targetcli-fb and friends, plus we
+  would still need a place for a decent-sized (1G?) file.
+
+* have tests do discovery themselves, instead of requiring
+  that to be done already. Either way, we may still need
+  to know the IQN of our target and the host where it lives.
+
+* Have tests figure out the device path, so it doesn't have
+  to be passed in. Passing it in requires the called to
+  login to the remote iscsi target and look at the path
+  in /dev/disk/by-id (for example). If we created the
+  disk, we might have a better chance of guessing its name?
+
+* Augment tests
+  Right now, the test is a long-ass regression test. Very
+  repetitive and time-consuming. But we also have need of
+  regular unit tests, e.g. for functionality, where a new
+  test could be added each time we find a bug? New tests
+  could include things like:
+    - multipathing
+    - using interface files or not
+    - discovery, with and without authentication
+    - session creation, w/ & w/o auth
+
+* Gather actual regression data!
+  - Since we are testing all of these combinations, why not
+    keep historical data to see if there are any negative
+    trends (i.e. regressions)? Need to understand fio and bonnie++
+    output better to find a way to gather one or two datapoints
+    (max) per test, out of all the info dumped by these
+    programs.
+
+* Add in test cases for Discovery and/or Connection validation,
+  which would require either a separate target set up for that,
+  or control of our own target
+
+* Only allow /dev/disk/by-* paths, as /dev/sd? paths are
+  inherently problematic, since they can change names.
+
+* Add back in the "big warning" from regression.sh?
+
+* Find a faster way to zero the disc than using sgdisk and
+  dd. Running both of these on a 10G disc can take minutes.
+
+* Come up with some common subsets of tests that can be run
+  when needed, since running all the tests takes forever. Maybe
+  a "short", "medium", and "long" option, so the caller doesn't
+  have to remember the arcane command-line options?
+
+* keep track of our session id (when we have one), so that
+  we can log out of just our session more easily
+
+* do a better job of tracking time spent exec-ing other
+  programs -- maybe have the run_cmd() function do it
+  automatically, using a dict, based on the argv[0]
+  command being run?
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/test/harness/.gitignore b/pkgs/open-iscsi/open-iscsi-2.1.8/test/harness/.gitignore
new file mode 100644 (file)
index 0000000..8025bc0
--- /dev/null
@@ -0,0 +1,2 @@
+__pycache__
+*~
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/test/harness/__init__.py b/pkgs/open-iscsi/open-iscsi-2.1.8/test/harness/__init__.py
new file mode 100644 (file)
index 0000000..b93fb7e
--- /dev/null
@@ -0,0 +1,7 @@
+"""
+Harness functions for the open-iscsi test suite.
+"""
+
+__version__ = '1.0'
+
+__all__ = ['util', 'iscsi', 'tests']
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/test/harness/iscsi.py b/pkgs/open-iscsi/open-iscsi-2.1.8/test/harness/iscsi.py
new file mode 100644 (file)
index 0000000..a252d7a
--- /dev/null
@@ -0,0 +1,63 @@
+"""
+ISCSI classes and utilities
+"""
+
+from .util import *
+
+class IscsiData:
+    """
+    Gather all the iscsi data in one place
+    """
+    imm_data_en = 'Yes'
+    initial_r2t_en = 'No'
+    hdrdgst_en = 'None,CRC32C'
+    datdgst_en = 'None,CRC32C'
+    first_burst = 256 * 1024
+    max_burst = 16 * 1024 * 1024 - 1024
+    max_recv_dlength = 128 * 1024
+    max_r2t = 1
+    # the target-name and IP:Port
+    target = None
+    ipnr = None
+
+    def __init__(self,
+            imm_data_en=imm_data_en,
+            initial_r2t_en=initial_r2t_en,
+            hdrdgst_en=hdrdgst_en,
+            datdgst_en=datdgst_en,
+            first_burst=first_burst,
+            max_burst=max_burst,
+            max_recv_dlength=max_recv_dlength,
+            max_r2t=max_r2t):
+        self.imm_data_en = imm_data_en
+        self.initial_r2t_en = initial_r2t_en
+        self.hdrdgst_en = hdrdgst_en
+        self.datdgst_en = datdgst_en
+        self.first_burst = first_burst
+        self.max_burst = max_burst
+        self.max_recv_dlength = max_recv_dlength
+        self.max_r2t = max_r2t
+
+    def update_cfg(self, target, ipnr):
+        """
+        Update the configuration -- we could do this by hacking on the
+        appropriate DB file, but this is safer (and slower) by far
+        """
+        if Global.verbosity > 1:
+            print('* ImmediateData = %s' % self.imm_data_en)
+            print('* InitialR2T = %s' % self.initial_r2t_en)
+            print('* HeaderDigest = %s' % self.hdrdgst_en)
+            print('* DataDigest = %s' % self.datdgst_en)
+            print('* FirstBurstLength = %d' % self.first_burst)
+            print('* MaxBurstLength = %d' % self.max_burst)
+            print('* MaxRecvDataSegmentLength = %d' % self.max_recv_dlength)
+            print('* MaxOutstandingR2T = %d' % self.max_r2t)
+        c = ['iscsiadm', '-m', 'node', '-T', target, '-p', ipnr, '-o', 'update']
+        run_cmd(c + ['-n', 'node.session.iscsi.ImmediateData', '-v', self.imm_data_en])
+        run_cmd(c + ['-n', 'node.session.iscsi.InitialR2T', '-v', self.initial_r2t_en])
+        run_cmd(c + ['-n', 'node.conn[0].iscsi.HeaderDigest', '-v', self.hdrdgst_en])
+        run_cmd(c + ['-n', 'node.conn[0].iscsi.DataDigest', '-v', self.datdgst_en])
+        run_cmd(c + ['-n', 'node.session.iscsi.FirstBurstLength', '-v', str(self.first_burst)])
+        run_cmd(c + ['-n', 'node.session.iscsi.MaxBurstLength', '-v', str(self.max_burst)])
+        run_cmd(c + ['-n', 'node.conn[0].iscsi.MaxRecvDataSegmentLength', '-v', str(self.max_recv_dlength)])
+        run_cmd(c + ['-n', 'node.session.iscsi.MaxOutstandingR2T', '-v', str(self.max_r2t)])
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/test/harness/tests.py b/pkgs/open-iscsi/open-iscsi-2.1.8/test/harness/tests.py
new file mode 100644 (file)
index 0000000..2adad04
--- /dev/null
@@ -0,0 +1,211 @@
+"""
+tests -- the actual TestCase (just one)
+"""
+
+import sys
+import os
+import unittest
+import time
+
+from . import util
+from .util import Global
+from .iscsi import IscsiData
+
+
+def s2dt(s):
+    # seconds to "HH:MM:SS.sss"
+    s_orig = s
+    hrs = s / 3600
+    s -= (int(hrs) * 3600)
+    mins = s / 60
+    s -= (int(mins) * 60)
+    a_str="%02d:%02d:%06.3f" % (hrs, mins, s)
+    dprint("s2dt: %f -> %s" % (s_orig, a_str))
+    return a_str
+
+
+def print_time_values():
+    # print out global exec time values
+    util.vprint('')
+    util.vprint('Times spent running sub-programs:')
+    ttl_time = 0.0
+    for s in Global.timing.keys():
+        v = Global.timing[s]
+        r = s2dt(v)
+        ttl_time += v
+        util.vprint('  %10s = %s' % (s, r))
+    util.vprint('    =======================')
+    util.vprint('  %10s = %s' % ('Total', s2dt(ttl_time)))
+    util.vprint('')
+    util.vprint('Total test-run time: %s' % (s2dt(Global.total_time)))
+
+
+class TestRegression(unittest.TestCase):
+    """
+    Regression testing
+    """
+
+    @classmethod
+    def setUpClass(cls):
+        util.verify_needed_commands_exist(['parted', 'fio', Global.MKFSCMD[0], 'bonnie++', 'sgdisk', 'iscsiadm'])
+        util.vprint('*** Starting %s' % cls.__name__)
+        # XXX validate that target exists?
+        # an array of first burts, max burst, and max recv values, for testing
+        cls.param_values = [[4096, 4096, 4096],
+                            [8192, 4096, 4096],
+                            [16384, 4096, 4096],
+                            [32768, 4096, 4096],
+                            [65536, 4096, 4096],
+                            [131972, 4096, 4096],
+                            [4096, 8192, 4096],
+                            [4096, 16384, 4096],
+                            [4096, 32768, 4096],
+                            [4096, 65536, 4096],
+                            [4096, 131072, 4096],
+                            [4096, 4096, 8192],
+                            [4096, 4096, 16384],
+                            [4096, 4096, 32768],
+                            [4096, 4096, 65536],
+                            [4096, 4096, 131072]]
+        cls.time_start = time.perf_counter()
+
+    def setUp(self):
+        if Global.debug or Global.verbosity > 1:
+            # this makes debug printing a little more clean
+            print('', file=sys.stderr)
+
+    def iscsi_logout(self):
+        res = util.run_cmd(['iscsiadm', '-m', 'node',
+                            '-T', Global.target,
+                            '-p', Global.ipnr,
+                            '--logout'])
+        if res not in [0, 21]:
+            self.fail('logout failed')
+        self.assertFalse(os.path.exists(Global.device), '%s: exists after logout!' % Global.device)
+
+    def test_InitialR2T_on_ImmediateData_off(self):
+        """Test Initial Request to Transmit on, but Immediate Data off"""
+        i = 1
+        for v in self.param_values:
+            with self.subTest('Testing FirstBurst={} MaxBurst={} MaxRecv={}'.format(*v), i=i):
+                if i not in Global.subtest_list:
+                    util.vprint('Skipping subtest %d: FirstBurst={} MaxBurst={} MaxRecv={}'.format(*v) % i)
+                else:
+                    util.vprint('Running subtest %d: FirstBurst={} MaxBurst={} MaxRecv={}'.format(*v) % i)
+                    self.iscsi_logout()
+                    iscsi_data = IscsiData('No', 'Yes', 'None', 'None', v[0], v[1], v[2])
+                    iscsi_data.update_cfg(Global.target, Global.ipnr)
+                    self.run_the_rest()
+            i += 1
+
+    def test_InitialR2T_off_ImmediateData_on(self):
+        """Test Initial Request to Transmit off, Immediate Data on"""
+        i = 1
+        for v in self.param_values:
+            with self.subTest('Testing FirstBurst={} MaxBurst={} MaxRecv={}'.format(*v), i=i):
+                if i not in Global.subtest_list:
+                    util.vprint('Skipping subtest %d: FirstBurst={} MaxBurst={} MaxRecv={}'.format(*v) % i)
+                else:
+                    util.vprint('Running subtest %d: FirstBurst={} MaxBurst={} MaxRecv={}'.format(*v) % i)
+                    self.iscsi_logout()
+                    iscsi_data = IscsiData('Yes', 'No', 'None', 'None', v[0], v[1], v[2])
+                    iscsi_data.update_cfg(Global.target, Global.ipnr)
+                    self.run_the_rest()
+            i += 1
+
+    def test_InitialR2T_on_ImmediateData_on(self):
+        """Test Initial Request to Transmit and Immediate Data on"""
+        i = 1
+        for v in self.param_values:
+            with self.subTest('Testing FirstBurst={} MaxBurst={} MaxRecv={}'.format(*v), i=i):
+                if i not in Global.subtest_list:
+                    util.vprint('Skipping subtest %d: FirstBurst={} MaxBurst={} MaxRecv={}'.format(*v) % i)
+                else:
+                    util.vprint('Running subtest %d: FirstBurst={} MaxBurst={} MaxRecv={}'.format(*v) % i)
+                    self.iscsi_logout()
+                    iscsi_data = IscsiData('Yes', 'Yes', 'None', 'None', v[0], v[1], v[2])
+                    iscsi_data.update_cfg(Global.target, Global.ipnr)
+                    self.run_the_rest()
+            i += 1
+
+    def test_InitialR2T_off_ImmediateData_off(self):
+        """Test Initial Request to Transmit and Immediate Data off"""
+        i = 1
+        for v in self.param_values:
+            with self.subTest('Testing FirstBurst={} MaxBurst={} MaxRecv={}'.format(*v), i=i):
+                if i not in Global.subtest_list:
+                    util.vprint('Skipping subtest %d: FirstBurst={} MaxBurst={} MaxRecv={}'.format(*v) % i)
+                else:
+                    util.vprint('Running subtest %d: FirstBurst={} MaxBurst={} MaxRecv={}'.format(*v) % i)
+                    self.iscsi_logout()
+                    iscsi_data = IscsiData('No', 'No', 'None', 'None', v[0], v[1], v[2])
+                    iscsi_data.update_cfg(Global.target, Global.ipnr)
+                    self.run_the_rest()
+            i += 1
+
+    def test_HdrDigest_on_DataDigest_off(self):
+        """Test With Header Digest"""
+        i = 1
+        for v in self.param_values:
+            with self.subTest('Testing FirstBurst={} MaxBurst={} MaxRecv={}'.format(*v), i=i):
+                if i not in Global.subtest_list:
+                    util.vprint('Skipping subtest %d: FirstBurst={} MaxBurst={} MaxRecv={}'.format(*v) % i)
+                else:
+                    util.vprint('Running subtest %d: FirstBurst={} MaxBurst={} MaxRecv={}'.format(*v) % i)
+                    self.iscsi_logout()
+                    iscsi_data = IscsiData('No', 'Yes', 'CRC32C', 'None', v[0], v[1], v[2])
+                    iscsi_data.update_cfg(Global.target, Global.ipnr)
+                    self.run_the_rest()
+            i += 1
+
+    def test_HdrDigest_on_DataDigest_on(self):
+        """Test With Header Digest"""
+        i = 1
+        for v in self.param_values:
+            with self.subTest('Testing FirstBurst={} MaxBurst={} MaxRecv={}'.format(*v), i=i):
+                if i not in Global.subtest_list:
+                    util.vprint('Skipping subtest %d: FirstBurst={} MaxBurst={} MaxRecv={}'.format(*v) % i)
+                else:
+                    util.vprint('Running subtest %d: FirstBurst={} MaxBurst={} MaxRecv={}'.format(*v) % i)
+                    self.iscsi_logout()
+                    iscsi_data = IscsiData('No', 'Yes', 'CRC32C', 'CRC32C', v[0], v[1], v[2])
+                    iscsi_data.update_cfg(Global.target, Global.ipnr)
+                    self.run_the_rest()
+            i += 1
+
+    def run_the_rest(self):
+        res = util.run_cmd(['iscsiadm', '-m', 'node',
+                            '-T', Global.target,
+                            '-p', Global.ipnr,
+                            '--login'])
+        self.assertEqual(res, 0, 'cannot login to device')
+        # wait a few seconds for the device to show up
+        if not util.wait_for_path(Global.device):
+            self.fail('%s: does not exist after login' % Global.device)
+        # run parted to partition the disc with one whole disk partition
+        (res, reason) = util.run_parted()
+        self.assertEqual(res, 0, reason)
+        # run fio to test file IO
+        (res, reason) = util.run_fio()
+        self.assertEqual(res, 0, reason)
+        # wait a bit for cache to flush
+        util.sleep_some(1)
+        # make a filesystem
+        (res, reason) = util.run_mkfs()
+        self.assertEqual(res, 0, reason)
+        # run bonnie++ to test the filesystem IO
+        (res, reason) = util.run_bonnie()
+        self.assertEqual(res, 0, reason)
+
+    @classmethod
+    def tearDownClass(cls):
+        # restore iscsi config
+        iscsi_data = IscsiData()
+        iscsi_data.update_cfg(Global.target, Global.ipnr)
+        # log out of iscsi connection
+        util.run_cmd(['iscsiadm', '-m', 'node',
+                      '-T', Global.target,
+                      '-p', Global.ipnr,
+                      '--logout'])
+        Global.total_time = time.perf_counter() - cls.time_start
+        print_time_values()
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/test/harness/util.py b/pkgs/open-iscsi/open-iscsi-2.1.8/test/harness/util.py
new file mode 100644 (file)
index 0000000..fd09d67
--- /dev/null
@@ -0,0 +1,418 @@
+"""
+harness stuff (support) -- utility routines
+"""
+
+import os
+import shutil
+import sys
+import unittest
+import time
+import tempfile
+import re
+
+from . import __version__ as lib_version
+
+#
+# globals
+#
+class Global:
+    FSTYPE = os.getenv('FSTYPE', 'ext3')
+    if os.getenv('MOUNTOPTIONS'):
+        MOUNTOPTIONS = os.getenv('MOUNTOPTIONS').split(' ')
+    else:
+        MOUNTOPTIONS = []
+    MOUNTOPTIONS += ['-t', FSTYPE]
+    MKFSCMD = [os.getenv('MKFSCMD', 'mkfs.' + FSTYPE)]
+    if os.getenv('MKFSOPTS'):
+        MKFSCMD += os.getenv('MKFSOPTS').split(' ')
+    BONNIEPARAMS = os.getenv('BONNIEPARAMS', '-r0 -n10:0:0 -s16 -uroot -f -q').split(' ')
+    verbosity = 1
+    debug = False
+    # the target (e.g. "iqn.*")
+    target = None
+    # the IP and optional port (e.g. "linux-system", "192.168.10.1:3260")
+    ipnr = None
+    # the device that will be created when our target is connected
+    device = None
+    # the first and only partition on said device
+    partition = None
+    # optional override for fio disk testing block size(s)
+    blocksize = None
+    # subtests to run -- by default, all of them
+    # XXX we should really look how many subtests there are, but there's
+    # no good way to detect that.
+    subtest_list = [i+1 for i in range(16)]
+    # for timing
+    timing = dict.fromkeys(['fio', 'sgdisk', 'dd', 'bonnie', 'mkfs', 'sleep'], 0.0)
+    total_time = 0.0
+
+
+def dprint(*args):
+    """
+    Print a debug message if in debug mode
+    """
+    if Global.debug:
+        print('DEBUG: ', file=sys.stderr, end='')
+        for arg in args:
+            print(arg, file=sys.stderr, end='')
+        print('', file=sys.stderr)
+
+def vprint(*args):
+    """
+    Print a verbose message
+    """
+    if Global.verbosity > 1 and args:
+        for arg in args:
+            print(arg, end='')
+        print('')
+
+def run_cmd(cmd, output_save_file=None):
+    """
+    run specified command, waiting for and returning result
+    """
+    if Global.debug:
+        cmd_str = ' '.join(cmd)
+        if output_save_file:
+            cmd_str += ' >& %s' % output_save_file
+        dprint(cmd_str)
+    pid = os.fork()
+    if pid < 0:
+        print("Error: cannot fork!", flie=sys.stderr)
+        sys.exit(1)
+    if pid == 0:
+        # the child
+        if output_save_file or not Global.debug:
+            stdout_fileno = sys.stdout.fileno()
+            stderr_fileno = sys.stderr.fileno()
+            if output_save_file:
+                new_stdout = os.open(output_save_file, os.O_WRONLY|os.O_CREAT|os.O_TRUNC,
+                                     mode=0o664)
+            else:
+                new_stdout = os.open('/dev/null', os.O_WRONLY)
+            os.dup2(new_stdout, stdout_fileno)
+            os.dup2(new_stdout, stderr_fileno)
+        os.execvp(cmd[0], cmd)
+        # not reached
+        sys.exit(1)
+
+    # the parent
+    wpid, wstat = os.waitpid(pid, 0)
+    if wstat != 0:
+        dprint("exit status: (%d) %d" % (wstat, os.WEXITSTATUS(wstat)))
+    return os.WEXITSTATUS(wstat)
+
+def new_initArgParsers(self):
+    """
+    Add  some options to the normal unittest main options
+    """
+    global old_initArgParsers
+
+    old_initArgParsers(self)
+    self._main_parser.add_argument('-d', '--debug', dest='debug',
+            action='store_true',
+            help='Enable developer debugging')
+    self._main_parser.add_argument('-t', '--target', dest='target',
+            action='store',
+            help='Required: target name')
+    self._main_parser.add_argument('-i', '--ipnr', dest='ipnr',
+            action='store',
+            help='Required: name-or-ip[:port]')
+    self._main_parser.add_argument('-D', '--device', dest='device',
+            action='store',
+            help='Required: device')
+    self._main_parser.add_argument('-B', '--blocksize', dest='blocksize',
+            action='store',
+            help='block size (defaults to an assortment of sizes)')
+    self._main_parser.add_argument('-V', '--version', dest='version_request',
+            action='store_true',
+            help='Display Version info and exit')
+    self._main_parser.add_argument('-l', '--list', dest='list_tests',
+            action='store_true',
+            help='List test cases and exit')
+    self._main_parser.add_argument('-s', '--subtests', dest='subtest_list',
+            action='store',
+            help='Subtests to execute [default all, i.e. "1-16"]')
+
+def print_suite(suite):
+    """Print a list of tests from a test suite"""
+    dprint("print_suite: entering for", suite)
+    if hasattr(suite, '__iter__'):
+        for x in suite:
+            print_suite(x)
+    else:
+        print(suite)
+
+def new_parseArgs(self, argv):
+    """
+    Gather globals from unittest main for local consumption -- this
+    called to parse then validate the arguments, inside each TestCase
+    instance.
+    """
+    global old_parseArgs, prog_name, parent_version, lib_version
+
+    # actually parse the arguments
+    old_parseArgs(self, argv)
+
+    # now validate stuff
+    if self.version_request:
+        print('%s Version %s, harness version %s' % \
+              (prog_name, parent_version, lib_version))
+        sys.exit(0)
+    Global.verbosity = self.verbosity
+    Global.debug = self.debug
+    if self.list_tests:
+        print_suite(unittest.defaultTestLoader.discover('.'))
+        sys.exit(0)
+    for v in ['target', 'ipnr', 'device']:
+        if getattr(self, v) is None:
+            print('Error: "%s" required' % v.upper())
+            sys.exit(1)
+        setattr(Global, v, getattr(self, v))
+    Global.blocksize = self.blocksize
+    dprint("found: verbosity=%d, target=%s, ipnr=%s, device=%s, bs=%s" % \
+            (Global.verbosity, Global.target, Global.ipnr, Global.device, Global.blocksize))
+    # get partition from path
+    device_dir = os.path.dirname(Global.device)
+    if device_dir == '/dev':
+        Global.partition = '%s1' % Global.device
+    elif device_dir in ['/dev/disk/by-id', '/dev/disk/by-path']:
+        Global.partition = '%s-part1' % Global.device
+    else:
+        print('Error: must start with "/dev" or "/dev/disk/by-{id,path}": %s' % \
+                Global.device, file=sys.stderr)
+        sys.exit(1)
+    if self.subtest_list:
+        if not user_spec_to_list(self.subtest_list):
+            self._print_help()
+            sys.exit(1)
+
+def user_spec_to_list(user_spec):
+    """
+    We have 16 subtests. By default, we run them all, but if
+    the user has specified a subset, like 'N' or 'N-M', then
+    a list of the indicies they requested.
+
+    XXX: expand to handle groups, e.g. 1,3-4,12 ???
+
+    XXX: should we validate that the range will work, or just
+    let an exception happen in that case?
+    """
+    pat_single = re.compile(r'(\d+)$')
+    pat_range = re.compile(r'(\d+)-(\d+)$')
+    found = False
+    start_idx = None
+    end_idx = None
+    res = pat_range.match(user_spec)
+    if res:
+        # user wants just one subtest
+        start_idx = int(res.group(1)) - 1
+        end_idx = int(res.group(2))
+        dprint("Found request for range: %d-%d" % (start_idx, end_idx))
+        found = True
+    else:
+        res = pat_single.match(user_spec)
+        if res:
+            start_idx = int(res.group(1)) - 1
+            end_idx = start_idx + 1
+            dprint("Found request for single: %d-%d" % (start_idx, end_idx))
+            found = True
+    if not found:
+        print('Error: subtest spec does not match N or N-M: %s' % user_spec)
+    else:
+        dprint("subtest_list before:", Global.subtest_list)
+        Global.subtest_list = Global.subtest_list[start_idx:end_idx]
+        dprint("subtest_list after:", Global.subtest_list)
+    return found
+    
+def setup_testProgram_overrides(version_str, name):
+    """
+    Add in special handling for a couple of the methods in TestProgram (main)
+    so that we can add parameters and detect some globals we care about
+    """
+    global old_parseArgs, old_initArgParsers, parent_version, prog_name
+
+    old_initArgParsers = unittest.TestProgram._initArgParsers
+    unittest.TestProgram._initArgParsers = new_initArgParsers
+    old_parseArgs = unittest.TestProgram.parseArgs
+    unittest.TestProgram.parseArgs = new_parseArgs
+    parent_version = version_str
+    prog_name = name
+
+def verify_needed_commands_exist(cmd_list):
+    """
+    Verify that the commands in the supplied list are in our path
+    """
+    path_list = os.getenv('PATH').split(':')
+    any_cmd_not_found = False
+    for cmd in cmd_list:
+        found = False
+        for a_path in path_list:
+            if os.path.exists('%s/%s' % (a_path, cmd)):
+                found = True
+                break
+        if not found:
+            print('Error: %s must be in your PATH' % cmd)
+            any_cmd_not_found = True
+    if any_cmd_not_found:
+        sys.exit(1)
+
+
+def run_fio():
+    """
+    Run the fio benchmark for various block sizes.
+    
+    Return zero for success.
+    Return non-zero for failure and a failure reason.
+
+    Uses Globals: partition, blocksize
+    """
+    if Global.blocksize is not None:
+        dprint('Found a block size passed in: %s' % Global.blocksize)
+        blocksizes = Global.blocksize.split(' ')
+    else:
+        dprint('NO Global block size pass in?')
+        blocksizes = ['512', '1k', '2k', '4k', '8k',
+                '16k', '32k', '75536', '128k', '1000000']
+    # for each block size, do a read test, then a write test
+    for bs in blocksizes:
+        vprint('Running "fio" read/write/verify tests with 8/8/1 threads, bs=%s' % bs)
+        # only support direct IO with aligned reads
+        if bs.endswith('k'):
+            direct=1
+        else:
+            direct=0
+        ts = time.perf_counter()
+        res = run_cmd(['fio', '--name=read-test', '--readwrite=randread',
+            '--runtime=2s', '--numjobs=8', '--blocksize=%s' % bs, 
+            '--offset=256k',
+            '--direct=%d' % direct, '--filename=%s' % Global.partition])
+        if res != 0:
+            return (res, 'fio failed')
+        res = run_cmd(['fio', '--name=write-test', '--readwrite=randwrite',
+            '--runtime=2s', '--numjobs=8', '--blocksize=%s' % bs, 
+            '--offset=256k',
+            '--direct=%d' % direct, '--filename=%s' % Global.partition])
+        if res != 0:
+            return (res, 'fio failed')
+        res = run_cmd(['fio', '--name=verify-test', '--readwrite=randwrite',
+            '--runtime=2s', '--numjobs=1', '--blocksize=%s' % bs, 
+            '--direct=%d' % direct, '--filename=%s' % Global.partition,
+            '--offset=256k',
+            '--verify=md5', '--verify_state_save=0'])
+        if res != 0:
+            return (res, 'fio failed')
+        te = time.perf_counter()
+        Global.timing['fio'] += te - ts
+    return (0, 'Success')
+
+def wait_for_path(path, present=True, amt=10):
+    """Wait until a path exists or is gone"""
+    dprint("Looking for path=%s, present=%s" % (path, present))
+    for i in range(amt):
+        sleep_some(1)
+        if os.path.exists(path) == present:
+            dprint("We are Happy :) present=%s, cnt=%d" % (present, i))
+            return True
+    dprint("We are not happy :( present=%s actual=%s after %d seconds" % \
+           (present, os.path.exists(path), amt))
+    return False
+
+def wipe_disc():
+    """
+    Wipe the label and partition table from the disc drive -- the sleep-s
+    are needed to give the async OS and udev a chance to notice the partition
+    table has been erased
+    """
+    # zero out the label and parition table
+    vprint('Running "sgdisk" and "dd" to wipe disc label, partitions, and filesystem')
+    sleep_some(1)
+    ts = time.perf_counter()
+    res = run_cmd(['sgdisk', '--clear', Global.device])
+    te = time.perf_counter()
+    Global.timing['sgdisk'] += te -ts
+    if res != 0:
+        if res == 4:
+            dprint("Oh oh -- 'clear' failed! trying one more time ...")
+        ts = time.perf_counter()
+        res = run_cmd(['sgdisk', '--clear', Global.device])
+        te = time.perf_counter()
+        if res != 0:
+            return (res, '%s: could not zero out label after two tries: %d' % \
+                    (Global.device, res))
+        Global.timing['sgdisk'] += te - ts
+    ts = time.perf_counter()
+    res = run_cmd(['dd', 'if=/dev/zero', 'of=%s' % Global.device, 'bs=256k', 'count=20', 'oflag=direct'])
+    te = time.perf_counter()
+    if res != 0:
+        return (res, '%s: could not zero out filesystem: %d' % (Global.device, res))
+    Global.timing['dd'] += te - ts
+    return (0, 'Success')
+    
+def run_parted():
+    """
+    Run the parted program to ensure there is one partition,
+    and that it covers the whole disk
+
+    Return zero for success and the device pathname.
+    Return non-zero for failure and a failure reason.
+
+    Uses Globals: device, partition
+    """
+    (res, reason) = wipe_disc()
+    if res != 0:
+        return (res, reason)
+    # ensure our partition file is not there, to be safe
+    if not wait_for_path(Global.partition, present=False, amt=30):
+        return (1, '%s: Partition already exists?' % Global.partition)
+    # make a label, then a partition table with one partition
+    vprint('Running "parted" to create a label and partition table')
+    res = run_cmd(['parted', Global.device, 'mklabel', 'gpt'])
+    if res != 0:
+        return (res, '%s: Could not create a GPT label' % Global.device)
+    res = run_cmd(['parted', '-a', 'none', Global.device, 'mkpart', 'primary', '0', '100%'])
+    if res != 0:
+        return (res, '%s: Could not create a primary partition' % Global.device)
+    # wait for the partition to show up
+    if not wait_for_path(Global.partition):
+        return (1, '%s: Partition never showed up?' % Global.partition)
+    # success
+    return (0, 'Success')
+
+def run_mkfs():
+    vprint('Running "mkfs" to to create filesystem')
+    ts = time.perf_counter()
+    res = run_cmd(Global.MKFSCMD + [ Global.partition ] )
+    te = time.perf_counter()
+    if res != 0:
+        return (res, '%s: mkfs failed (%d)' % (Global.partition, res))
+    Global.timing['mkfs'] += te - ts
+    return (0, 'Success')
+
+def run_bonnie():
+    # make a temp dir and mount the device there
+    with tempfile.TemporaryDirectory() as tmp_dir:
+        vprint('Running "mount" to mount the filesystem')
+        res = run_cmd(['mount'] + Global.MOUNTOPTIONS + [Global.partition, tmp_dir])
+        if res != 0:
+            return (res, '%s: mount failed (%d)' % (Global.partition, res))
+        # run bonnie++ on the new directory
+        vprint('Running "bonnie++" on the filesystem')
+        ts = time.perf_counter()
+        res = run_cmd(['bonnie++'] + Global.BONNIEPARAMS + ['-d', tmp_dir])
+        te = time.perf_counter()
+        if res != 0:
+            return (res, '%s: umount failed (%d)' % (tmp_dir, res))
+        Global.timing['bonnie'] += te - ts
+        # unmount the device and remove the temp dir
+        vprint('Running "umount" to unmount the filesystem')
+        res = run_cmd(['umount', tmp_dir])
+        if res != 0:
+            return (res, '%s: umount failed (%d)' % (tmp_dir, res))
+    return (0, 'Success')
+
+def sleep_some(s):
+    # sleep s seconds
+    ts = time.perf_counter()
+    time.sleep(s)
+    te = time.perf_counter()
+    Global.timing['sleep'] += te - ts
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/test/regression.dat b/pkgs/open-iscsi/open-iscsi-2.1.8/test/regression.dat
new file mode 100644 (file)
index 0000000..c96cd9d
--- /dev/null
@@ -0,0 +1,108 @@
+#imdata        inir2t  hdrdgst datdgst frstbst mxbrst  mxrecv  mxr2t
+# 0 - 16
+No     Yes     None    None    4096    4096    4096    1
+No     Yes     None    None    8192    4096    4096    1
+No     Yes     None    None    16384   4096    4096    1
+No     Yes     None    None    32768   4096    4096    1
+No     Yes     None    None    65536   4096    4096    1
+No     Yes     None    None    131972  4096    4096    1
+No     Yes     None    None    4096    8192    4096    1
+No     Yes     None    None    4096    16384   4096    1
+No     Yes     None    None    4096    32768   4096    1
+No     Yes     None    None    4096    65536   4096    1
+No     Yes     None    None    4096    131072  4096    1
+No     Yes     None    None    4096    4096    8192    1
+No     Yes     None    None    4096    4096    16384   1
+No     Yes     None    None    4096    4096    32768   1
+No     Yes     None    None    4096    4096    65536   1
+No     Yes     None    None    4096    4096    131072  1
+
+# 15 - 31
+No     No      None    None    4096    4096    4096    1
+No     No      None    None    8192    4096    4096    1
+No     No      None    None    16384   4096    4096    1
+No     No      None    None    32768   4096    4096    1
+No     No      None    None    65536   4096    4096    1
+No     No      None    None    131972  4096    4096    1
+No     No      None    None    4096    8192    4096    1
+No     No      None    None    4096    16384   4096    1
+No     No      None    None    4096    32768   4096    1
+No     No      None    None    4096    65536   4096    1
+No     No      None    None    4096    131072  4096    1
+No     No      None    None    4096    4096    8192    1
+No     No      None    None    4096    4096    16384   1
+No     No      None    None    4096    4096    32768   1
+No     No      None    None    4096    4096    65536   1
+No     No      None    None    4096    4096    131072  1
+
+# 32 - 47
+Yes    No      None    None    4096    4096    4096    1
+Yes    No      None    None    8192    4096    4096    1
+Yes    No      None    None    16384   4096    4096    1
+Yes    No      None    None    32768   4096    4096    1
+Yes    No      None    None    65536   4096    4096    1
+Yes    No      None    None    131972  4096    4096    1
+Yes    No      None    None    4096    8192    4096    1
+Yes    No      None    None    4096    16384   4096    1
+Yes    No      None    None    4096    32768   4096    1
+Yes    No      None    None    4096    65536   4096    1
+Yes    No      None    None    4096    131072  4096    1
+Yes    No      None    None    4096    4096    8192    1
+Yes    No      None    None    4096    4096    16384   1
+Yes    No      None    None    4096    4096    32768   1
+Yes    No      None    None    4096    4096    65536   1
+Yes    No      None    None    4096    4096    131072  1
+
+# 48 - 63
+Yes    Yes     None    None    4096    4096    4096    1
+Yes    Yes     None    None    8192    4096    4096    1
+Yes    Yes     None    None    16384   4096    4096    1
+Yes    Yes     None    None    32768   4096    4096    1
+Yes    Yes     None    None    65536   4096    4096    1
+Yes    Yes     None    None    131972  4096    4096    1
+Yes    Yes     None    None    4096    8192    4096    1
+Yes    Yes     None    None    4096    16384   4096    1
+Yes    Yes     None    None    4096    32768   4096    1
+Yes    Yes     None    None    4096    65536   4096    1
+Yes    Yes     None    None    4096    131072  4096    1
+Yes    Yes     None    None    4096    4096    8192    1
+Yes    Yes     None    None    4096    4096    16384   1
+Yes    Yes     None    None    4096    4096    32768   1
+Yes    Yes     None    None    4096    4096    65536   1
+Yes    Yes     None    None    4096    4096    131072  1
+
+# 64 - 79
+No     Yes     CRC32C  None    4096    4096    4096    1
+No     Yes     CRC32C  None    8192    4096    4096    1
+No     Yes     CRC32C  None    16384   4096    4096    1
+No     Yes     CRC32C  None    32768   4096    4096    1
+No     Yes     CRC32C  None    65536   4096    4096    1
+No     Yes     CRC32C  None    131972  4096    4096    1
+No     Yes     CRC32C  None    4096    8192    4096    1
+No     Yes     CRC32C  None    4096    16384   4096    1
+No     Yes     CRC32C  None    4096    32768   4096    1
+No     Yes     CRC32C  None    4096    65536   4096    1
+No     Yes     CRC32C  None    4096    131072  4096    1
+No     Yes     CRC32C  None    4096    4096    8192    1
+No     Yes     CRC32C  None    4096    4096    16384   1
+No     Yes     CRC32C  None    4096    4096    32768   1
+No     Yes     CRC32C  None    4096    4096    65536   1
+No     Yes     CRC32C  None    4096    4096    131072  1
+
+# 80 - 95
+No     Yes     CRC32C  CRC32C  4096    4096    4096    1
+No     Yes     CRC32C  CRC32C  8192    4096    4096    1
+No     Yes     CRC32C  CRC32C  16384   4096    4096    1
+No     Yes     CRC32C  CRC32C  32768   4096    4096    1
+No     Yes     CRC32C  CRC32C  65536   4096    4096    1
+No     Yes     CRC32C  CRC32C  131972  4096    4096    1
+No     Yes     CRC32C  CRC32C  4096    8192    4096    1
+No     Yes     CRC32C  CRC32C  4096    16384   4096    1
+No     Yes     CRC32C  CRC32C  4096    32768   4096    1
+No     Yes     CRC32C  CRC32C  4096    65536   4096    1
+No     Yes     CRC32C  CRC32C  4096    131072  4096    1
+No     Yes     CRC32C  CRC32C  4096    4096    8192    1
+No     Yes     CRC32C  CRC32C  4096    4096    16384   1
+No     Yes     CRC32C  CRC32C  4096    4096    32768   1
+No     Yes     CRC32C  CRC32C  4096    4096    65536   1
+No     Yes     CRC32C  CRC32C  4096    4096    131072  1
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/test/regression.sh b/pkgs/open-iscsi/open-iscsi-2.1.8/test/regression.sh
new file mode 100755 (executable)
index 0000000..aeef74d
--- /dev/null
@@ -0,0 +1,266 @@
+#!/bin/bash
+#
+# Open-iSCSI Regression Test Utility
+# Copyright (C) 2004 Dmitry Yusupov
+# 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.
+#
+
+PATH=".:${PATH}"
+FSTYPE="${FSTYPE:-ext3}"
+DEFAULTMOUNTOPTS='-o _netdev'
+[ -z "${MOUNTOPTS}" ] && MOUNTOPTS="${DEFAULTMOUNTOPTS}"
+# to avoid mount looking for fstype
+MOUNTOPTIONS="${MOUNTOPTIONS} -t ${FSTYPE}"
+MKFSCMD="${MKFSCMD:-mkfs.${FSTYPE}} ${MKFSOPTS}"
+PARTITIONSUFFIX="1"
+BONNIEPARAMS="${BONNIEPARAMS:--r0 -n10:0:0 -s16 -uroot -f -q}"
+
+trap regress_signal INT QUIT TERM
+regress_signal() {
+    printf "\nterminating, restore defaults: "
+       # use the other function to clean up
+       imm_data_en="Yes"
+       initial_r2t_en="No"
+       hdrdgst_en="None,CRC32C"
+       datdgst_en="None,CRC32C"
+       c="${iscsiadm} -m node -T $target -p $ipnr -o update"
+       first_burst="$((256*1024))"
+       max_burst="$((16*1024*1024-1024))"
+       max_recv_dlength="$((128*1024))"
+       max_r2t="1"
+       update_cfg
+       ${iscsiadm} -m node -T $target -p $ipnr --logout 2>/dev/null >/dev/null
+    printf "done\n"
+    exit 0
+}
+
+function update_cfg() {
+       c="${iscsiadm} -m node -T $target -p $ipnr -o update"
+       $c -n node.session.iscsi.ImmediateData -v $imm_data_en
+       $c -n node.session.iscsi.InitialR2T -v $initial_r2t_en
+       $c -n node.conn[0].iscsi.HeaderDigest -v $hdrdgst_en
+       $c -n node.conn[0].iscsi.DataDigest -v $datdgst_en
+       $c -n node.session.iscsi.FirstBurstLength -v $first_burst
+       $c -n node.session.iscsi.MaxBurstLength -v $max_burst
+       $c -n node.conn[0].iscsi.MaxRecvDataSegmentLength -v $max_recv_dlength
+       $c -n node.session.iscsi.MaxOutstandingR2T -v $max_r2t
+}
+
+function disktest_run() {
+       bsizes="512 1024 2048 4096 8192 16384 32768 65536 131072 1000000"
+       test "x$bsize" != x && bsizes=$bsize
+       test "x$bsize" = xbonnie && return 0;
+       for bs in $bsizes; do
+               echo -n "disktest -T2 -K8 -B$bs -r -ID $device: "
+               #if ! ${disktest} -T2 -K8 -B$bs -r -ID $device >/dev/null; then
+               if ! ${disktest} -T2 -K8 -B$bs -r -ID $device; then
+                       echo "FAILED"
+                       return 1;
+               fi
+               echo "PASSED"
+               #echo -n "disktest -T2 -K8 -B$bs -E16 -w -ID $device: "
+               #if ! ${disktest} -T2 -K8 -B$bs -E16 -w -ID $device >/dev/null;then
+               echo -n "disktest -T2 -K8 -B$bs -E16 -ID $device: "
+               if ! ${disktest} -T2 -K8 -B$bs -E16 -ID $device; then
+                       echo "FAILED"
+                       return 1;
+               fi
+               echo "PASSED"
+       done
+       return 0;
+}
+
+function fdisk_run() {
+       echo -n "sfdisk -qf $device: "
+       #sfdisk -Lqf $device >/dev/null 2>/dev/null <<-EOF
+       sfdisk -Lqf $device <<-EOF
+       ,
+       quit
+       EOF
+       rc=$?
+       if [ $rc -ne 0 ]; then
+               echo "FAILED"
+               return 1;
+       fi
+       echo "PASSED"
+       return 0;
+}
+
+function mkfs_run() {
+       echo -n "${MKFSCMD} $device_partition: "
+       #if ! ${MKFSCMD} $device_partition 2>/dev/null >/dev/null; then
+       if ! ${MKFSCMD} $device_partition ; then
+               echo "FAILED"
+               return 1;
+       fi
+       echo "PASSED"
+       return 0;
+}
+
+function bonnie_run() {
+       dir="/tmp/iscsi.bonnie.regression.$record.$RANDOM"
+       umount $dir 2>/dev/null >/dev/null
+       rm -rf $dir; mkdir $dir
+       echo -n "mount $dir: "
+       if ! mount ${MOUNTOPTIONS} $device_partition $dir; then
+               echo "FAILED"
+               return 1;
+       fi
+       echo "PASSED"
+       echo -n "bonnie++ ${BONNIEPARAMS}: "
+       pushd $dir >/dev/null
+       ${bonnie} ${BONNIEPARAMS} 2>/dev/null >/dev/null
+       rc=$?
+       popd >/dev/null
+       umount $dir 2>/dev/null >/dev/null
+       rmdir ${dir}
+       if [ $rc -ne 0 ]; then
+               echo "FAILED"
+               return 1;
+       fi
+       echo "PASSED"
+       return 0;
+}
+
+function fatal() {
+       echo "regression.sh: $1"
+       echo "Usage: regression.sh [-f | <targetname> <ipnumber#> ] <device> [test#[:#]] [bsize]"
+       exit 1
+}
+
+############################ main ###################################
+
+disktest=`which disktest`
+iscsiadm=`which iscsiadm`
+bonnie=`which bonnie++`
+datfile=`dirname $0`"/regression.dat"
+test ! -e ${datfile} && fatal "can not find regression.dat"
+test ! -e ${disktest} && fatal "can not find disktest"
+test ! -e ${iscsiadm} && fatal "can not find iscsiadm"
+test ! -e ${bonnie} && fatal "can not find bonnie++"
+
+if test x$1 = "x-f" -o x$1 = "x--format"; then
+       test x$2 = x && fatal "SCSI device parameter error"
+       device=$2
+else
+       test x$1 = x && fatal "target name parameter error"
+       test x$2 = x && fatal "ipnumber parameter error"
+       test x$3 = x && fatal "SCSI device parameter error"
+
+       target="$1"
+       ipnr="$2"
+       device=$3
+fi
+
+device_dir="$(dirname ${device})"
+device_partition=''
+case "${device_dir}" in
+       # /dev/sdaX
+       /dev) device_partition="${device}1" ;;
+       # /dev/disk/by-id/scsi-${ID_SERIAL}-part1
+       # where ID_SERIAL is SCSI disk SERIAL from scsi_id
+       /dev/disk/by-id|/dev/disk/by-path) device_partition="${device}-part1" ;;
+       # upcoming stuff
+       /dev/iscsi/*) device_partition="${device}-part1" ;;
+esac
+
+if test x$1 = "x-f" -o x$1 = "x--format"; then
+       mkfs_run
+       exit
+fi
+
+if [ -z "${device_partition}" ]; then
+       echo 'Unable to find device name for first partition.' >&2
+       exit 1
+fi
+
+test "x$4" != x && begin="$4"
+test "x$5" != x && bsize="$5"
+
+if test "x$begin" != "x"; then
+       end="${begin/*:}"
+       begin="${begin/:*}"
+fi
+
+# don't say we didn't warn you
+if [ -z "${SKIP_WARNING}" ]; then
+       cat <<-EOF
+       BIG FAT WARNING!
+       
+       Open-iSCSI Regression Test Suite is about to start. It is going
+       to use "$device" for its testing. iSCSI session could be re-opened
+       during the tests several times and as the result device name could
+       not match provided device name if some other SCSI activity happened
+       during the test.
+       
+       Are you sure you want to continue? [y/n]:
+       EOF
+       read line
+       if test x$line = xn -o x$line = xN -o x$line = xno -o x$line = xNO; then
+               echo "aborting..."
+               exit
+       fi
+fi
+
+i=0
+cat ${datfile} | while read line; do
+       if echo $line | grep "^#" >/dev/null; then continue; fi
+       if echo $line | grep "^$" >/dev/null; then continue; fi
+       if test x$begin != x; then
+               if test x$begin != x$i -a x$end = x; then
+                       let i=i+1
+                       continue
+               elif test x$begin != x -a x$end != x; then
+                       if test $i -lt $begin -o $i -gt $end; then
+                               let i=i+1
+                               continue
+                       fi
+               fi
+       fi
+       imm_data_en=`echo $line | awk '/^[YesNo]+/ {print $1}'`
+       if test x$imm_data_en = x; then continue; fi
+       initial_r2t_en=`echo $line | awk '{print $2}'`
+       hdrdgst_en=`echo $line | awk '{print $3}'`
+       datdgst_en=`echo $line | awk '{print $4}'`
+       first_burst=`echo $line | awk '{print $5}'`
+       max_burst=`echo $line | awk '{print $6}'`
+       max_recv_dlength=`echo $line | awk '{print $7}'`
+       max_r2t=`echo $line | awk '{print $8}'`
+       # ensure we are logged out
+       ${iscsiadm} -m node -T $target -p $ipnr --logout 2>/dev/null >/dev/null
+       # set parameters for next run
+       update_cfg
+       echo "================== TEST #$i BEGIN ===================="
+       echo "ImmediateData = $imm_data_en"
+       echo "InitialR2T = $initial_r2t_en"
+       echo "HeaderDigest = $hdrdgst_en"
+       echo "DataDigest = $datdgst_en"
+       echo "FirstBurstLength = $first_burst"
+       echo "MaxBurstLength = $max_burst"
+       echo "MaxRecvDataSegmentLength = $max_recv_dlength"
+       echo "MaxOutstandingR2T = $max_r2t"
+       # login for new test
+       # catch errors on this
+       if ! ${iscsiadm} -m node -T $target -p $ipnr --login; then break; fi
+       while [ ! -e $device ] ; do sleep 1 ; done
+       if ! disktest_run; then break; fi
+       if ! fdisk_run; then break; fi
+       if ! mkfs_run; then break; fi
+       if ! bonnie_run; then break; fi
+       let i=i+1
+done
+regress_signal
+echo
+echo "===================== THE END ========================"
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/test/test-open-iscsi.py b/pkgs/open-iscsi/open-iscsi-2.1.8/test/test-open-iscsi.py
new file mode 100755 (executable)
index 0000000..2b8f2b9
--- /dev/null
@@ -0,0 +1,22 @@
+#!/usr/bin/env python3
+"""
+Unit tests for open-iscsi, using the unittest built-in package
+"""
+
+import sys
+import unittest
+import os
+import time
+from harness import util
+#from harness import tests
+#from tests import TestRegression
+
+__version__ = '1.0'
+
+
+if __name__ == '__main__':
+    # do our own hackery first, to get access to verbosity, debug, etc,
+    # as well as add our own command-line options
+    util.setup_testProgram_overrides(__version__, 'test-open-iscsi.py')
+    # now run the tests
+    unittest.main(module = 'harness.tests')
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/.gitignore b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/.gitignore
new file mode 100644 (file)
index 0000000..a672448
--- /dev/null
@@ -0,0 +1,4 @@
+iscsiadm
+iscsid
+iscsistart
+.depend
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/Makefile b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/Makefile
new file mode 100644 (file)
index 0000000..84f33bc
--- /dev/null
@@ -0,0 +1,132 @@
+# This Makefile will work only with GNU make.
+
+ifeq ($(TOPDIR),)
+       TOPDIR = ..
+endif
+
+INSTALL = install
+
+DESTDR ?=
+SBINDIR ?= /sbin
+etcdir = /etc
+
+OSNAME=$(shell uname -s)
+
+# allow users to override these
+# eg to compile for a kernel that you aren't currently running
+KERNELRELEASE ?= $(shell uname -r)
+KSRC ?= /lib/modules/$(KERNELRELEASE)/build
+
+KSUBLEVEL=$(shell cat $(KSRC)/Makefile | awk -F= '/^SUBLEVEL =/ {print $$2}' | \
+                       sed 's/^[ \t]*//;s/[ \t]*$$//')
+
+ifeq ($(OSNAME),Linux)
+       ifeq ($(KSUBLEVEL),11)
+               IPC_CFLAGS=-DNETLINK_ISCSI=12 -D_GNU_SOURCE
+       else
+       ifeq ($(KSUBLEVEL),12)
+               IPC_CFLAGS=-DNETLINK_ISCSI=12 -D_GNU_SOURCE
+       else
+               IPC_CFLAGS=-DNETLINK_ISCSI=8 -D_GNU_SOURCE
+       endif
+       endif
+IPC_OBJ=netlink.o
+else
+ifeq ($(OSNAME),FreeBSD)
+IPC_CFLAGS=
+IPC_OBJ=ioctl.o
+endif
+endif
+
+DBROOT ?= $(etcdir)/iscsi
+HOMEDIR ?= $(etcdir)/iscsi
+
+PKG_CONFIG ?= /usr/bin/pkg-config
+
+CFLAGS ?= -O2 -g
+WARNFLAGS ?= -Wall -Wextra -Werror -Wstrict-prototypes -fno-common
+CFLAGS += $(WARNFLAGS) -I../include -I. -D_GNU_SOURCE \
+         -I$(TOPDIR)/libopeniscsiusr \
+         -DISCSI_VERSION_STR=\"$(ISCSI_VERSION_STR)\"
+CFLAGS += $(shell $(PKG_CONFIG) --cflags libkmod)
+CFLAGS += $(shell $(PKG_CONFIG) --cflags libsystemd)
+ISCSI_LIB = -L$(TOPDIR)/libopeniscsiusr -lopeniscsiusr
+LDFLAGS += $(shell $(PKG_CONFIG) --libs libkmod)
+ifeq ($(NO_SYSTEMD),)
+LDFLAGS += $(shell $(PKG_CONFIG) --libs libsystemd)
+else
+CFLAGS += -DNO_SYSTEMD
+endif
+CFLAGS += -DISCSI_DB_ROOT=\"$(DBROOT)\"
+CFLAGS += -DISCSI_CONFIG_ROOT=\"$(HOMEDIR)\"
+
+PROGRAMS       = iscsid iscsiadm iscsistart
+PROGRAMS_DEST  = $(addprefix $(DESTDIR)$(SBINDIR)/,$(PROGRAMS))
+
+ISCSID_OBJS    = iscsid.o session_mgmt.o discoveryd.o mntcheck.o
+ISCSIADM_OBJS  = iscsiadm.o session_mgmt.o mntcheck.o
+ISCSISTART_OBJS        = iscsistart.o
+
+# libc compat files
+SYSDEPS_DIR = $(TOPDIR)/sysdeps
+SYSDEPS_OBJS = $(SYSDEPS_DIR)/sysdeps.o
+# sources shared between iscsid, iscsiadm and iscsistart
+ISCSI_LIB_OBJS = iscsi_util.o io.o auth.o iscsi_timer.o login.o log.o \
+       iface.o idbm.o sysfs.o host.o session_info.o iscsi_sysfs.o \
+       iscsi_net_util.o iscsid_req.o transport.o iser.o cxgbi.o be2iscsi.o \
+       initiator_common.o iscsi_err.o flashnode.o uip_mgmt_ipc.o \
+       netlink.o
+# core initiator files
+INITIATOR_OBJS = initiator.o scsi.o actor.o event_poll.o mgmt_ipc.o kern_err_table.o
+
+# fw boot files
+FW_BOOT_DIR = fwparam_ibft
+FW_BOOT_OBJ_FILES = fw_entry.o fwparam_sysfs.o prom_lex.o prom_parse.tab.o fwparam_ppc.o
+FW_BOOT_OBJS = $(addprefix $(FW_BOOT_DIR)/,$(FW_BOOT_OBJ_FILES))
+
+# core discovery files
+DISCOVERY_OBJS = local_strings.o discovery.o
+
+all: $(PROGRAMS)
+
+iscsid: $(ISCSI_LIB_OBJS) $(SYSDEPS_OBJS) $(INITIATOR_OBJS) $(DISCOVERY_OBJS) $(FW_BOOT_OBJS) \
+       $(ISCSID_OBJS)
+       $(CC) $(CFLAGS) $^ -o $@  -lisns -lcrypto -lrt -lmount $(LDFLAGS) $(ISCSI_LIB)
+
+iscsiadm: $(ISCSI_LIB_OBJS) $(SYSDEPS_OBJS) $(DISCOVERY_OBJS) $(FW_BOOT_OBJS) \
+       $(ISCSIADM_OBJS)
+       $(CC) $(CFLAGS) $^ -o $@ -lisns -lcrypto -lmount $(LDFLAGS) $(ISCSI_LIB)
+
+iscsistart: $(ISCSI_LIB_OBJS) $(SYSDEPS_OBJS) $(INITIATOR_OBJS) $(FW_BOOT_OBJS) \
+       $(ISCSISTART_OBJS)
+       $(CC) $(CFLAGS) $^ -o $@ -lcrypto -lrt $(LDFLAGS) $(ISCSI_LIB)
+
+install: $(DESTDIR)$(SBINDIR) $(PROGRAMS_DEST)
+
+$(DESTDIR)$(SBINDIR):
+       [ -d $@ ] || $(INSTALL) -d $@
+
+$(PROGRAMS_DEST): $(DESTDIR)$(SBINDIR)/%: %
+       $(INSTALL) -m 755 $? $@
+
+$(SYSDEPS_OBJS):
+       $(MAKE) $(MFLAGS) -C $(SYSDEPS_DIR)
+
+$(FW_BOOT_OBJS):
+       $(MAKE) $(MFLAGS) -C $(FW_BOOT_DIR)
+
+clean:
+       $(RM) $(ISCSI_LIB_OBJS) $(INITIATOR_OBJS) $(DISCOVERY_OBJS) \
+               $(ISCSISTART_OBJS) $(ISCSID_OBJS) $(ISCSIADM_OBJS) \
+               $(PROGRAMS) .depend
+       $(MAKE) $(MFLAGS) -C $(FW_BOOT_DIR) clean
+
+distclean: ;
+
+.PHONY: all install clean distclean depend
+
+depend:
+       $(CC) $(CFLAGS) -M `ls *.c` > .depend
+       $(MAKE) $(MFLAGS) -C $(FW_BOOT_DIR) depend
+
+-include .depend
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/actor.c b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/actor.c
new file mode 100644 (file)
index 0000000..a6bb02f
--- /dev/null
@@ -0,0 +1,296 @@
+/*
+ * 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
+ * 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 <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(ready_list);
+static volatile int poll_in_progress;
+
+static uint64_t
+actor_time_left(actor_t *thread, time_t current_time)
+{
+       if (current_time > thread->ttschedule)
+               return 0;
+       else
+               return (thread->ttschedule - current_time);
+}
+
+#define time_after(a,b) \
+       ((int64_t)(b) - (int64_t)(a) < 0)
+
+void
+__actor_init(actor_t *thread, void (*callback)(void *), void *data)
+{
+       if (thread->state != ACTOR_INVALID)
+               log_error("bug:thread %p:%s has already been initialized",
+                         thread, thread->name);
+
+       INIT_LIST_HEAD(&thread->list);
+       thread->state = ACTOR_NOTSCHEDULED;
+       thread->callback = callback;
+       thread->data = data;
+}
+
+void
+actor_delete(actor_t *thread)
+{
+       log_debug(7, "thread %p:%s delete: state %d",
+                       thread, thread->name,
+                       thread->state);
+       switch(thread->state) {
+       case ACTOR_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 %p:%s!",
+                        thread, thread->name);
+               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;
+       }
+       thread->state = ACTOR_NOTSCHEDULED;
+}
+
+/*
+ * Inserts actor on pend list and sets alarm if new item is
+ * sooner than previous entries.
+ */
+static void
+actor_insert_on_pend_list(actor_t *thread, uint32_t delay_secs)
+{
+       struct actor *orig_head;
+       struct actor *new_head;
+       struct actor *next_thread;
+
+       orig_head = list_first_entry_or_null(&pend_list,
+                                            struct actor, list);
+
+       /* 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:%s due %lld", next_thread,
+                         next_thread->name, (long long)next_thread->ttschedule);
+                       log_debug(7, "new thread %p:%s is before (%lld), inserting",
+                         thread, next_thread->name, (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:%s due %lld", next_thread,
+                         next_thread->name, (long long)next_thread->ttschedule);
+               log_debug(7, "new thread %p:%s is after (%lld), inserting at tail",
+                         thread, thread->name, (long long)thread->ttschedule);
+       }
+       else
+               log_debug(7, "new thread %p:%s due %lld is first item on pend_list",
+                         thread, thread->name, (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:%s schedule: delay %u state %d",
+               thread, thread->name, delay_secs, thread->state);
+
+       switch(thread->state) {
+       case ACTOR_WAITING:
+               log_error("rescheduling a waiting thread %p:%s !",
+                         thread, thread->name);
+               list_del(&thread->list);
+               /* fall-through */
+       case ACTOR_NOTSCHEDULED:
+               INIT_LIST_HEAD(&thread->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 = current_time + delay_secs;
+
+                       actor_insert_on_pend_list(thread, delay_secs);
+               }
+               break;
+       case ACTOR_SCHEDULED:
+               // don't do anything
+               break;
+       case ACTOR_INVALID:
+               log_error("BUG: Trying to schedule a thread %p"
+                         "that has not been setup. Ignoring sched.",
+                         thread);
+               break;
+       }
+
+}
+
+void
+actor_schedule_head(actor_t *thread)
+{
+       actor_schedule_private(thread, 0, 1);
+}
+
+void
+actor_schedule(actor_t *thread)
+{
+       actor_schedule_private(thread, 0, 0);
+}
+
+void
+__actor_timer(actor_t *thread, uint32_t timeout_secs, void (*callback)(void *),
+           void *data)
+{
+       __actor_init(thread, callback, data);
+       actor_schedule_private(thread, timeout_secs, 0);
+}
+
+void
+actor_timer_mod(actor_t *thread, uint32_t new_timeout_secs, void *data)
+{
+       actor_delete(thread);
+       thread->data = data;
+       actor_schedule_private(thread, new_timeout_secs, 0);
+}
+
+/*
+ * Execute all items that have expired.
+ *
+ * Set an alarm if items remain. Caller must catch SIGALRM and
+ * then re-invoke this function.
+ */
+void
+actor_poll(void)
+{
+       struct actor *thread, *tmp;
+       uint64_t current_time;
+       struct timespec tv;
+
+       if (poll_in_progress) {
+               log_error("recursive actor_poll() is not allowed");
+               return;
+       }
+
+       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 %p:%s due %" PRIu64 ", wait %" PRIu64 " more",
+                                 thread, thread->name,
+                                 (uint64_t)thread->ttschedule, time_left);
+
+                       alarm(time_left);
+                       break;
+               }
+
+               /* This entry can be run now */
+               list_del_init(&thread->list);
+
+               log_debug(2, "thread %p:%s was scheduled for "
+                         "%" PRIu64 ", curtime %" PRIu64 " q_forw %p "
+                         "&pend_list %p",
+                         thread, thread->name, (uint64_t)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 %p:%s now in ready_list",
+                         thread, thread->name);
+       }
+
+       /* Disable alarm if nothing else pending */
+       if (list_empty(&pend_list)) {
+               log_debug(7, "nothing on pend_list, deactivating alarm");
+               alarm(0);
+       }
+
+       poll_in_progress = 1;
+       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("ready_list: thread %p:%s state corrupted! "
+                                 "Thread with state %d in actor list.",
+                                 thread, thread->name,
+                                 thread->state);
+               thread->state = ACTOR_NOTSCHEDULED;
+               log_debug(7, "exec thread %p:%s",
+                         thread, thread->name);
+               thread->callback(thread->data);
+               log_debug(7, "thread %p:%s done", thread, thread->name);
+       }
+       poll_in_progress = 0;
+}
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/actor.h b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/actor.h
new file mode 100644 (file)
index 0000000..a67eb36
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * iSCSI usermode single-threaded scheduler
+ *
+ * Copyright (C) 2004 Dmitry Yusupov, Alex Aizman
+ * 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 ACTOR_H
+#define ACTOR_H
+
+#include <stdio.h>
+#include "types.h"
+#include "list.h"
+
+#define ACTOR_NAME_LEN 128
+
+typedef enum actor_state_e {
+    ACTOR_INVALID,
+    ACTOR_WAITING,
+    ACTOR_SCHEDULED,
+    ACTOR_NOTSCHEDULED,
+} actor_state_e;
+
+typedef struct actor {
+       char name[ACTOR_NAME_LEN];
+       struct list_head list;
+       actor_state_e state;
+       void *data;
+       void (*callback)(void * );
+       time_t ttschedule;
+} actor_t;
+
+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 delay_secs,
+                       void (*callback)(void *), void *data);
+extern void actor_timer_mod(actor_t *thread, uint32_t new_delay_secs,
+                           void *data);
+extern void actor_poll(void);
+
+#define actor_init(thread, callback, data) \
+do { \
+       snprintf((thread)->name, ACTOR_NAME_LEN, #callback); \
+       __actor_init(thread, callback, data); \
+} while (0)
+
+#define actor_timer(thread, timeout_secs, callback, data) \
+do { \
+       snprintf((thread)->name, ACTOR_NAME_LEN, #callback); \
+       __actor_timer(thread, timeout_secs, callback, data); \
+} while (0)
+
+#endif /* ACTOR_H */
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/auth.c b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/auth.c
new file mode 100644 (file)
index 0000000..46c328e
--- /dev/null
@@ -0,0 +1,2112 @@
+/*
+ * iSCSI Authorization Library
+ *
+ * maintained by open-iscsi@@googlegroups.com
+ *
+ * Originally based on:
+ * Copyright (C) 2001 Cisco Systems, Inc.
+ *
+ * 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.
+ *
+ * This file implements the iSCSI CHAP authentication method based on
+ * RFC 3720.  The code in this file is meant to be common for both kernel and
+ * user level and makes use of only limited  library  functions, presently only
+ * string.h. Routines specific to kernel, user level are implemented in
+ * separate files under the appropriate directories.
+ * This code in this files assumes a single thread of execution
+ * for each iscsi_acl structure, and does no locking.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "sysdeps.h"
+#include "auth.h"
+#include "initiator.h"
+#include "log.h"
+
+static const char acl_hexstring[] = "0123456789abcdefABCDEF";
+static const char acl_base64_string[] =
+    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+static const char acl_authmethod_set_chap_alg_list[] = "CHAP";
+static const char acl_reject_option_name[] = "Reject";
+
+#include <openssl/evp.h>
+#include <openssl/rand.h>
+static int auth_hash_init(EVP_MD_CTX **context, int chap_alg);
+static void auth_hash_update(EVP_MD_CTX *context, unsigned char *md, unsigned int);
+static unsigned int auth_hash_final(unsigned char *, EVP_MD_CTX *context);
+
+size_t strlcpy(char *, const char *, size_t);
+size_t strlcat(char *, const char *, size_t);
+
+enum auth_dbg_status
+acl_chap_compute_rsp(struct iscsi_acl *client, int rmt_auth, unsigned int id,
+                    unsigned char *challenge_data,
+                    unsigned int challenge_length,
+                    unsigned char *response_data)
+{
+       unsigned char id_data[1];
+       EVP_MD_CTX *context = NULL;
+       unsigned char out_data[AUTH_STR_MAX_LEN];
+       unsigned int out_length = AUTH_STR_MAX_LEN;
+
+       if (!client->passwd_present)
+               return AUTH_DBG_STATUS_LOCAL_PASSWD_NOT_SET;
+
+       if (auth_hash_init(&context, client->negotiated_chap_alg) != 0)
+               return AUTH_DBG_STATUS_AUTH_FAIL;
+
+       /* id byte */
+       id_data[0] = id;
+       auth_hash_update(context, id_data, 1);
+
+       /* decrypt password */
+       if (acl_data(out_data, &out_length, client->passwd_data,
+                    client->passwd_length))
+               return AUTH_DBG_STATUS_PASSWD_DECRYPT_FAILED;
+
+       if (!rmt_auth && !client->ip_sec && out_length < 12)
+               return AUTH_DBG_STATUS_PASSWD_TOO_SHORT_WITH_NO_IPSEC;
+
+       /* shared secret */
+       auth_hash_update(context, out_data, out_length);
+
+       /* clear decrypted password */
+       memset(out_data, 0, AUTH_STR_MAX_LEN);
+
+       /* challenge value */
+       auth_hash_update(context, challenge_data, challenge_length);
+
+       auth_hash_final(response_data, context);
+
+       return AUTH_DBG_STATUS_NOT_SET; /* no error */
+}
+
+/*
+ * Authenticate a target's CHAP response.
+ */
+int
+acl_chap_auth_request(struct iscsi_acl *client, char *username, unsigned int id,
+                     unsigned char *challenge_data,
+                     unsigned int challenge_length,
+                     unsigned char *response_data,
+                     unsigned int rsp_length)
+{
+       iscsi_session_t *session = client->session_handle;
+       EVP_MD_CTX *context = NULL;
+       unsigned char verify_data[client->chap_challenge_len];
+
+       /* the expected credentials are in the session */
+       if (session->username_in[0] == '\0') {
+               log_error("failing authentication, no incoming username "
+                         "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", session->target_name);
+               return AUTH_STATUS_FAIL;
+       }
+
+       if ((session->password_in_length < 1) ||
+           (session->password_in[0] == '\0')) {
+               log_error("failing authentication, no incoming password "
+                      "configured to authenticate target %s",
+                      session->target_name);
+               return AUTH_STATUS_FAIL;
+       }
+
+       /* challenge length is I->T, and shouldn't need to be checked */
+
+       if (rsp_length != sizeof(verify_data)) {
+               log_error("failing authentication, received incorrect "
+                         "CHAP response length %u from target %s",
+                         rsp_length, session->target_name);
+               return AUTH_STATUS_FAIL;
+       }
+
+       if (auth_hash_init(&context, client->negotiated_chap_alg) != 0)
+               return AUTH_STATUS_FAIL;
+
+       /* id byte */
+       verify_data[0] = id;
+       auth_hash_update(context, verify_data, 1);
+
+       /* shared secret */
+       auth_hash_update(context, (unsigned char *)session->password_in,
+                       session->password_in_length);
+
+       /* challenge value */
+       auth_hash_update(context, (unsigned char *)challenge_data,
+                       challenge_length);
+
+       auth_hash_final(verify_data, context);
+
+       if (memcmp(response_data, verify_data, sizeof(verify_data)) == 0) {
+               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", session->target_name);
+       return AUTH_STATUS_FAIL;
+}
+
+static int auth_hash_init(EVP_MD_CTX **context, int chap_alg) {
+       const EVP_MD *digest = NULL;
+       *context = EVP_MD_CTX_new();
+       int rc;
+
+       switch (chap_alg) {
+       case AUTH_CHAP_ALG_MD5:
+               digest = EVP_md5();
+               break;
+       case AUTH_CHAP_ALG_SHA1:
+               digest = EVP_sha1();
+               break;
+       case AUTH_CHAP_ALG_SHA256:
+               digest = EVP_sha256();
+               break;
+       case AUTH_CHAP_ALG_SHA3_256:
+               digest = EVP_sha3_256();
+               break;
+       }
+
+       if (*context == NULL)
+               goto fail_context;
+       if (digest == NULL)
+               goto fail_digest;
+       rc = EVP_DigestInit_ex(*context, digest, NULL);
+       if (!rc)
+               goto fail_init;
+
+       return 0;
+
+fail_init:
+fail_digest:
+       EVP_MD_CTX_free(*context);
+       *context = NULL;
+fail_context:
+       return -1;
+}
+
+static void auth_hash_update(EVP_MD_CTX *context, unsigned char *data, unsigned int length) {
+       EVP_DigestUpdate(context, data, length);
+}
+
+static unsigned int auth_hash_final(unsigned char *hash, EVP_MD_CTX *context) {
+       unsigned int md_len;
+       EVP_DigestFinal_ex(context, hash, &md_len);
+       EVP_MD_CTX_free(context);
+       context = NULL;
+       return md_len;
+}
+
+static const char acl_none_option_name[] = "None";
+
+static int
+acl_text_to_number(const char *text, unsigned long *num)
+{
+       char *end;
+       unsigned long number;
+
+       if (text[0] == '0' && (text[1] == 'x' || text[1] == 'X'))
+               number = strtoul(text + 2, &end, 16);
+       else
+               number = strtoul(text, &end, 10);
+
+       if (*text != '\0' && *end == '\0') {
+               *num = number;
+               return 0;       /* No error */
+       } else
+               return 1;       /* Error */
+}
+
+static int
+acl_chk_string(const char *s, unsigned int max_len, unsigned int *out_len)
+{
+       unsigned int len;
+
+       if (!s)
+               return 1;
+
+       for (len = 0; len < max_len; len++)
+               if (*s++ == '\0') {
+                       if (out_len)
+                               *out_len = len;
+                       return 0;
+               }
+
+       return 1;
+}
+
+static int
+acl_str_index(const char *s, int c)
+{
+       char *str = strchr(s, c);
+
+       if (str)
+               return (str - s);
+       else
+               return -1;
+}
+
+static int
+acl_chk_auth_mthd_optn(int val)
+{
+       if (val == AUTH_OPTION_NONE || val == AUTH_METHOD_CHAP)
+               return 0;
+
+       return 1;
+}
+
+static const char *
+acl_authmethod_optn_to_text(int value)
+{
+       const char *s;
+       switch (value) {
+       case AUTH_OPTION_REJECT:
+               s = acl_reject_option_name;
+               break;
+       case AUTH_OPTION_NONE:
+               s = acl_none_option_name;
+               break;
+       case AUTH_METHOD_CHAP:
+               s = acl_authmethod_set_chap_alg_list;
+               break;
+       default:
+               s = NULL;
+       }
+       return s;
+}
+
+static int
+acl_chk_chap_alg_optn(int chap_algorithm)
+{
+       if (chap_algorithm == AUTH_OPTION_NONE ||
+           chap_algorithm == AUTH_CHAP_ALG_SHA3_256 ||
+           chap_algorithm == AUTH_CHAP_ALG_SHA256 ||
+           chap_algorithm == AUTH_CHAP_ALG_SHA1 ||
+           chap_algorithm == AUTH_CHAP_ALG_MD5)
+               return 0;
+
+       return 1;
+}
+
+static int
+acl_data_to_text(unsigned char *data, unsigned int data_length, char *text,
+                unsigned int text_length)
+{
+       unsigned long n;
+
+       if (!text || text_length == 0)
+               return 1;
+
+       if (!data || data_length == 0) {
+               *text = '\0';
+               return 1;
+       }
+
+       if (text_length < 3) {
+               *text = '\0';
+               return 1;
+       }
+
+       *text++ = '0';
+       *text++ = 'x';
+
+       text_length -= 2;
+
+       while (data_length > 0) {
+
+               if (text_length < 3) {
+                       *text = '\0';
+                       return 1;
+               }
+
+               n = *data++;
+               data_length--;
+
+               *text++ = acl_hexstring[(n >> 4) & 0xf];
+               *text++ = acl_hexstring[n & 0xf];
+
+               text_length -= 2;
+       }
+
+       *text = '\0';
+
+       return 0;
+}
+
+static int
+acl_hex_to_data(const char *text, unsigned int text_length, unsigned char *data,
+               unsigned int *data_lenp)
+{
+       int i;
+       unsigned int n1;
+       unsigned int n2;
+       unsigned int data_length = *data_lenp;
+
+       if ((text_length % 2) == 1) {
+
+               i = acl_str_index(acl_hexstring, *text++);
+               if (i < 0)
+                       return 1;       /* error, bad character */
+
+               if (i > 15)
+                       i -= 6;
+               n2 = i;
+
+               if (data_length < 1)
+                       return 1;       /* error, too much data */
+
+               *data++ = n2;
+               data_length--;
+       }
+
+       while (*text != '\0') {
+               i = acl_str_index(acl_hexstring, *text++);
+               if (i < 0)
+                       return 1;       /* error, bad character */
+
+               if (i > 15)
+                       i -= 6;
+               n1 = i;
+
+               if (*text == '\0')
+                       return 1;       /* error, odd string length */
+
+               i = acl_str_index(acl_hexstring, *text++);
+               if (i < 0)
+                       return 1;       /* error, bad character */
+
+               if (i > 15)
+                       i -= 6;
+               n2 = i;
+
+               if (data_length < 1)
+                       return 1;       /* error, too much data */
+
+               *data++ = (n1 << 4) | n2;
+               data_length--;
+       }
+
+       if (data_length >= *data_lenp)
+               return 1;       /* error, no data */
+
+       *data_lenp = *data_lenp - data_length;
+
+       return 0;               /* no error */
+}
+
+static int
+acl_base64_to_data(const char *text, unsigned char *data,
+                  unsigned int *data_lenp)
+{
+       int i;
+       unsigned int n;
+       unsigned int count;
+       unsigned int data_length = *data_lenp;
+
+       n = 0;
+       count = 0;
+
+       while (*text != '\0' && *text != '=') {
+
+               i = acl_str_index(acl_base64_string, *text++);
+               if (i < 0)
+                       return 1;       /* error, bad character */
+
+               n = (n << 6 | (unsigned int)i);
+               count++;
+
+               if (count >= 4) {
+                       if (data_length < 3)
+                               return 1;       /* error, too much data */
+                       *data++ = n >> 16;
+                       *data++ = n >> 8;
+                       *data++ = n;
+                       data_length -= 3;
+                       n = 0;
+                       count = 0;
+               }
+       }
+
+       while (*text != '\0')
+               if (*text++ != '=')
+                       return 1;       /* error, bad pad */
+
+       if (count == 0) {
+               /* do nothing */
+       } else if (count == 2) {
+               if (data_length < 1)
+                       return 1;       /* error, too much data */
+               n = n >> 4;
+               *data++ = n;
+               data_length--;
+       } else if (count == 3) {
+               if (data_length < 2)
+                       return 1;       /* error, too much data */
+               n = n >> 2;
+               *data++ = n >> 8;
+               *data++ = n;
+               data_length -= 2;
+       } else
+               return 1;       /* bad encoding */
+
+       if (data_length >= *data_lenp)
+               return 1;       /* error, no data */
+
+       *data_lenp = *data_lenp - data_length;
+
+       return 0;               /* no error */
+}
+
+static int
+acl_text_to_data(const char *text, unsigned char *data,
+                unsigned int *data_length)
+{
+       int status;
+       unsigned int text_length;
+
+       status = acl_chk_string(text, 2 + 2 * AUTH_LARGE_BINARY_MAX_LEN + 1,
+                               &text_length);
+       if (status)
+               return status;
+
+       if (text[0] == '0' && (text[1] == 'x' || text[1] == 'X')) {
+               /* skip prefix */
+               text += 2;
+               text_length -= 2;
+               status = acl_hex_to_data(text, text_length, data, data_length);
+       } else if (text[0] == '0' && (text[1] == 'b' || text[1] == 'B')) {
+               /* skip prefix */
+               text += 2;
+               text_length -= 2;
+               status = acl_base64_to_data(text, data, data_length);
+       } else
+               status = 1;     /* prefix not recognized. */
+
+       return status;
+}
+
+static void
+acl_init_key_blk(struct auth_key_block *key_blk)
+{
+       char *str_block = key_blk->str_block;
+
+       memset(key_blk, 0, sizeof(*key_blk));
+       key_blk->str_block = str_block;
+}
+
+static void
+acl_set_key_value(struct auth_key_block *key_blk, int key_type,
+                 const char *key_val)
+{
+       unsigned int length;
+       char *string;
+
+       if (key_blk->key[key_type].value_set) {
+               key_blk->dup_set = 1;
+               return;
+       }
+
+       key_blk->key[key_type].value_set = 1;
+
+       if (!key_val)
+               return;
+
+       if (acl_chk_string(key_val, AUTH_STR_MAX_LEN, &length)) {
+               key_blk->str_too_long = 1;
+               return;
+       }
+
+       length += 1;
+
+       if ((key_blk->blk_length + length) > AUTH_STR_BLOCK_MAX_LEN) {
+               key_blk->too_much_data = 1;
+               return;
+       }
+
+       string = &key_blk->str_block[key_blk->blk_length];
+
+       if (strlcpy(string, key_val, length) >= length) {
+               key_blk->too_much_data = 1;
+               return;
+       }
+       key_blk->blk_length += length;
+
+       key_blk->key[key_type].string = string;
+       key_blk->key[key_type].present = 1;
+}
+
+static const char *
+acl_get_key_val(struct auth_key_block *key_blk, int key_type)
+{
+       key_blk->key[key_type].processed = 1;
+
+       if (!key_blk->key[key_type].present)
+               return NULL;
+
+       return key_blk->key[key_type].string;
+}
+
+static void
+acl_chk_key(struct iscsi_acl *client, int key_type, int *negotiated_option,
+           unsigned int option_count, int *option_list,
+           const char *(*value_to_text) (int))
+{
+       const char *key_val;
+       int length;
+       unsigned int i;
+
+       key_val = acl_get_key_val(&client->recv_key_block, key_type);
+       if (!key_val) {
+               *negotiated_option = AUTH_OPTION_NOT_PRESENT;
+               return;
+       }
+
+       while (*key_val != '\0') {
+
+               length = 0;
+
+               while (*key_val != '\0' && *key_val != ',')
+                       client->scratch_key_value[length++] = *key_val++;
+
+               if (*key_val == ',')
+                       key_val++;
+               client->scratch_key_value[length++] = '\0';
+
+               for (i = 0; i < option_count; i++) {
+                       const char *s = (*value_to_text)(option_list[i]);
+
+                       if (!s)
+                               continue;
+
+                       if (strcmp(client->scratch_key_value, s) == 0) {
+                               *negotiated_option = option_list[i];
+                               return;
+                       }
+               }
+       }
+
+       *negotiated_option = AUTH_OPTION_REJECT;
+}
+
+static void
+acl_set_key(struct iscsi_acl *client, int key_type, unsigned int option_count,
+           int *option_list, const char *(*value_to_text)(int))
+{
+       unsigned int i;
+
+       if (option_count == 0) {
+               /*
+                * No valid options to send, but we always want to
+                * send something.
+                */
+               acl_set_key_value(&client->send_key_block, key_type,
+                                 acl_none_option_name);
+               return;
+       }
+
+       if (option_count == 1 && option_list[0] == AUTH_OPTION_NOT_PRESENT) {
+               acl_set_key_value(&client->send_key_block, key_type, NULL);
+               return;
+       }
+
+       for (i = 0; i < option_count; i++) {
+               const char *s = (*value_to_text)(option_list[i]);
+
+               if (!s)
+                       continue;
+
+               if (i == 0)
+                       strlcpy(client->scratch_key_value, s,
+                                  AUTH_STR_MAX_LEN);
+               else {
+                       strlcat(client->scratch_key_value, ",",
+                                  AUTH_STR_MAX_LEN);
+                       strlcat(client->scratch_key_value, s,
+                                  AUTH_STR_MAX_LEN);
+               }
+       }
+
+       acl_set_key_value(&client->send_key_block, key_type,
+                         client->scratch_key_value);
+}
+
+static void
+acl_chk_auth_method_key(struct iscsi_acl *client)
+{
+       acl_chk_key(client, AUTH_KEY_TYPE_AUTH_METHOD,
+                   &client->negotiated_auth_method,
+                   client->auth_method_valid_count,
+                   client->auth_method_valid_list,
+                   acl_authmethod_optn_to_text);
+}
+
+static void
+acl_set_auth_method_key(struct iscsi_acl *client,
+                       unsigned int auth_method_count, int *auth_method_list)
+{
+       acl_set_key(client, AUTH_KEY_TYPE_AUTH_METHOD, auth_method_count,
+                   auth_method_list, acl_authmethod_optn_to_text);
+}
+
+static void
+acl_chk_chap_alg_key(struct iscsi_acl *client)
+{
+       const char *key_val;
+       int length;
+       unsigned long number;
+       unsigned int i;
+
+       key_val = acl_get_key_val(&client->recv_key_block,
+                                 AUTH_KEY_TYPE_CHAP_ALG);
+       if (!key_val) {
+               client->negotiated_chap_alg = AUTH_OPTION_NOT_PRESENT;
+               return;
+       }
+
+       while (*key_val != '\0') {
+
+               length = 0;
+
+               while (*key_val != '\0' && *key_val != ',')
+                       client->scratch_key_value[length++] = *key_val++;
+
+               if (*key_val == ',')
+                       key_val++;
+               client->scratch_key_value[length++] = '\0';
+
+               if (acl_text_to_number(client->scratch_key_value, &number))
+                       continue;
+
+
+               for (i = 0; i < client->chap_alg_count; i++)
+                       if (number == (unsigned long)client->chap_alg_list[i])
+                       {
+                               client->negotiated_chap_alg = number;
+                               switch (number) {
+                               case AUTH_CHAP_ALG_MD5:
+                                       client->chap_challenge_len = AUTH_CHAP_MD5_RSP_LEN;
+                                       break;
+                               case AUTH_CHAP_ALG_SHA1:
+                                       client->chap_challenge_len = AUTH_CHAP_SHA1_RSP_LEN;
+                                       break;
+                               case AUTH_CHAP_ALG_SHA256:
+                                       client->chap_challenge_len = AUTH_CHAP_SHA256_RSP_LEN;
+                                       break;
+                               case AUTH_CHAP_ALG_SHA3_256:
+                                       client->chap_challenge_len = AUTH_CHAP_SHA3_256_RSP_LEN;
+                                       break;
+                               }
+                               return;
+                       }
+       }
+
+       client->negotiated_chap_alg = AUTH_OPTION_REJECT;
+}
+
+static void
+acl_set_chap_alg_key(struct iscsi_acl *client, unsigned int chap_alg_count,
+                    int *chap_alg_list)
+{
+       unsigned int i;
+
+       if (chap_alg_count == 0) {
+               acl_set_key_value(&client->send_key_block,
+                                 AUTH_KEY_TYPE_CHAP_ALG, NULL);
+               return;
+       }
+
+       if (chap_alg_count == 1 &&
+           chap_alg_list[0] == AUTH_OPTION_NOT_PRESENT) {
+               acl_set_key_value(&client->send_key_block,
+                                 AUTH_KEY_TYPE_CHAP_ALG, NULL);
+               return;
+       }
+
+       if (chap_alg_count == 1 && chap_alg_list[0] == AUTH_OPTION_REJECT) {
+               acl_set_key_value(&client->send_key_block,
+                                 AUTH_KEY_TYPE_CHAP_ALG,
+                                 acl_reject_option_name);
+               return;
+       }
+
+       for (i = 0; i < chap_alg_count; i++) {
+               char s[20];
+
+               snprintf(s, sizeof(s), "%lu",(unsigned long)chap_alg_list[i]);
+
+               if (i == 0)
+                       strlcpy(client->scratch_key_value, s,
+                                  AUTH_STR_MAX_LEN);
+                else {
+                       strlcat(client->scratch_key_value, ",",
+                                  AUTH_STR_MAX_LEN);
+                       strlcat(client->scratch_key_value, s,
+                                  AUTH_STR_MAX_LEN);
+               }
+       }
+
+       acl_set_key_value(&client->send_key_block, AUTH_KEY_TYPE_CHAP_ALG,
+                         client->scratch_key_value);
+}
+
+static void
+acl_next_phase(struct iscsi_acl *client)
+{
+       switch (client->phase) {
+       case AUTH_PHASE_CONFIGURE:
+               client->phase = AUTH_PHASE_NEGOTIATE;
+               break;
+       case AUTH_PHASE_NEGOTIATE:
+               client->phase = AUTH_PHASE_AUTHENTICATE;
+
+               if (client->negotiated_auth_method == AUTH_OPTION_REJECT ||
+                   client->negotiated_auth_method == AUTH_OPTION_NOT_PRESENT ||
+                   client->negotiated_auth_method == AUTH_OPTION_NONE) {
+
+                       client->local_state = AUTH_LOCAL_STATE_DONE;
+                       client->rmt_state = AUTH_RMT_STATE_DONE;
+
+                       if (client->auth_rmt) {
+                               client->rmt_auth_status = AUTH_STATUS_FAIL;
+                               client->phase = AUTH_PHASE_DONE;
+                       } else
+                               client->rmt_auth_status = AUTH_STATUS_PASS;
+
+                       switch (client->negotiated_auth_method) {
+                       case AUTH_OPTION_REJECT:
+                               client->dbg_status =
+                                   AUTH_DBG_STATUS_AUTH_METHOD_REJECT;
+                               break;
+                       case AUTH_OPTION_NOT_PRESENT:
+                               client->dbg_status =
+                                   AUTH_DBG_STATUS_AUTH_METHOD_NOT_PRESENT;
+                               break;
+                       case AUTH_OPTION_NONE:
+                               client->dbg_status =
+                                   AUTH_DBG_STATUS_AUTH_METHOD_NONE;
+                       }
+
+               } else if (client->negotiated_auth_method == AUTH_METHOD_CHAP) {
+                       client->local_state = AUTH_LOCAL_STATE_SEND_ALG;
+                       client->rmt_state = AUTH_RMT_STATE_SEND_ALG;
+               } else {
+
+                       client->local_state = AUTH_LOCAL_STATE_DONE;
+                       client->rmt_state = AUTH_RMT_STATE_DONE;
+                       client->rmt_auth_status = AUTH_STATUS_FAIL;
+                       client->dbg_status = AUTH_DBG_STATUS_AUTH_METHOD_BAD;
+               }
+               break;
+       case AUTH_PHASE_AUTHENTICATE:
+               client->phase = AUTH_PHASE_DONE;
+               break;
+       case AUTH_PHASE_DONE:
+       case AUTH_PHASE_ERROR:
+       default:
+               client->phase = AUTH_PHASE_ERROR;
+       }
+}
+
+static void
+acl_local_auth(struct iscsi_acl *client)
+{
+       unsigned int chap_identifier;
+       unsigned char response_data[AUTH_CHAP_RSP_MAX];
+       unsigned long number;
+       int status;
+       enum auth_dbg_status dbg_status;
+       const char *chap_identifier_key_val;
+       const char *chap_challenge_key_val;
+
+       switch (client->local_state) {
+       case AUTH_LOCAL_STATE_SEND_ALG:
+               if (client->node_type == TYPE_INITIATOR) {
+                       acl_set_chap_alg_key(client, client->chap_alg_count,
+                                            client->chap_alg_list);
+                       client->local_state = AUTH_LOCAL_STATE_RECV_ALG;
+                       break;
+               }
+               /* Fall through */
+       case AUTH_LOCAL_STATE_RECV_ALG:
+               acl_chk_chap_alg_key(client);
+
+               if (client->node_type == TYPE_TARGET)
+                       acl_set_chap_alg_key(client, 1,
+                                            &client->negotiated_chap_alg);
+
+               /* Make sure only supported CHAP algorithm is used. */
+               if (client->negotiated_chap_alg == AUTH_OPTION_NOT_PRESENT) {
+                       client->local_state = AUTH_LOCAL_STATE_ERROR;
+                       client->dbg_status = AUTH_DBG_STATUS_CHAP_ALG_EXPECTED;
+                       break;
+               } else if (client->negotiated_chap_alg == AUTH_OPTION_REJECT) {
+                       client->local_state = AUTH_LOCAL_STATE_ERROR;
+                       client->dbg_status = AUTH_DBG_STATUS_CHAP_ALG_REJECT;
+                       break;
+               } else if ((client->negotiated_chap_alg != AUTH_CHAP_ALG_SHA3_256) &&
+                          (client->negotiated_chap_alg != AUTH_CHAP_ALG_SHA256) &&
+                          (client->negotiated_chap_alg != AUTH_CHAP_ALG_SHA1) &&
+                          (client->negotiated_chap_alg != AUTH_CHAP_ALG_MD5)) {
+                       client->local_state = AUTH_LOCAL_STATE_ERROR;
+                       client->dbg_status = AUTH_DBG_STATUS_CHAP_ALG_BAD;
+                       break;
+               }
+               if (client->node_type == TYPE_TARGET) {
+                       client->local_state = AUTH_LOCAL_STATE_RECV_CHALLENGE;
+                       break;
+               }
+               /* Fall through */
+       case AUTH_LOCAL_STATE_RECV_CHALLENGE:
+               chap_identifier_key_val = acl_get_key_val(&client->recv_key_block,
+                                                         AUTH_KEY_TYPE_CHAP_IDENTIFIER);
+               chap_challenge_key_val = acl_get_key_val(&client->recv_key_block,
+                                                        AUTH_KEY_TYPE_CHAP_CHALLENGE);
+               if (client->node_type == TYPE_TARGET) {
+                       if (!chap_identifier_key_val &&
+                           !chap_challenge_key_val) {
+                               client->local_state = AUTH_LOCAL_STATE_DONE;
+                               break;
+                       }
+               }
+
+               if (!chap_identifier_key_val) {
+                       client->local_state = AUTH_LOCAL_STATE_ERROR;
+                       client->dbg_status =
+                           AUTH_DBG_STATUS_CHAP_IDENTIFIER_EXPECTED;
+                       break;
+               }
+
+               if (!chap_challenge_key_val) {
+                       client->local_state = AUTH_LOCAL_STATE_ERROR;
+                       client->dbg_status =
+                           AUTH_DBG_STATUS_CHAP_CHALLENGE_EXPECTED;
+                       break;
+               }
+
+               status = acl_text_to_number(chap_identifier_key_val, &number);
+               if (status || (255 < number)) {
+                       client->local_state = AUTH_LOCAL_STATE_ERROR;
+                       client->dbg_status = AUTH_DBG_STATUS_CHAP_IDENTIFIER_BAD;
+                       break;
+               }
+               chap_identifier = number;
+
+               if (client->recv_chap_challenge_status) {
+                       client->local_state = AUTH_LOCAL_STATE_ERROR;
+                       client->dbg_status = AUTH_DBG_STATUS_CHALLENGE_BAD;
+                       break;
+               }
+
+               if (client->node_type == TYPE_TARGET &&
+                   client->recv_chap_challenge.length ==
+                   client->send_chap_challenge.length &&
+                   memcmp(client->recv_chap_challenge.large_binary,
+                          client->send_chap_challenge.large_binary,
+                          client->send_chap_challenge.length) == 0) {
+                       client->local_state = AUTH_LOCAL_STATE_ERROR;
+                       client->dbg_status =
+                           AUTH_DBG_STATUS_CHAP_CHALLENGE_REFLECTED;
+                       break;
+               }
+
+               dbg_status = acl_chap_compute_rsp(client, 0,
+                                                 chap_identifier,
+                                                 client->recv_chap_challenge.large_binary,
+                                                 client->recv_chap_challenge.length,
+                                                 response_data);
+
+               if (dbg_status != AUTH_DBG_STATUS_NOT_SET) {
+                       client->local_state = AUTH_LOCAL_STATE_ERROR;
+                       client->dbg_status = dbg_status;
+                       break;
+               }
+
+               acl_data_to_text(response_data, client->chap_challenge_len,
+                                client->scratch_key_value,
+                                AUTH_STR_MAX_LEN);
+               acl_set_key_value(&client->send_key_block,
+                                 AUTH_KEY_TYPE_CHAP_RSP,
+                                 client->scratch_key_value);
+               acl_set_key_value(&client->send_key_block,
+                                 AUTH_KEY_TYPE_CHAP_USERNAME,
+                                 client->username);
+
+               client->local_state = AUTH_LOCAL_STATE_DONE;
+               break;
+       case AUTH_LOCAL_STATE_DONE:
+               break;
+       case AUTH_LOCAL_STATE_ERROR:
+       default:
+               client->phase = AUTH_PHASE_ERROR;
+       }
+}
+
+static void
+acl_rmt_auth(struct iscsi_acl *client)
+{
+       unsigned char id_data[1];
+       unsigned char response_data[AUTH_STR_MAX_LEN];
+       unsigned int rsp_len = AUTH_STR_MAX_LEN;
+       unsigned char my_rsp_data[AUTH_CHAP_RSP_MAX];
+       int status;
+       enum auth_dbg_status dbg_status;
+       const char *chap_rsp_key_val;
+       const char *chap_username_key_val;
+       int ssl_ret = 0;
+
+       switch (client->rmt_state) {
+       case AUTH_RMT_STATE_SEND_ALG:
+               if (client->node_type == TYPE_INITIATOR) {
+                       client->rmt_state = AUTH_RMT_STATE_SEND_CHALLENGE;
+                       break;
+               }
+               /* Fall through */
+       case AUTH_RMT_STATE_SEND_CHALLENGE:
+               if (!client->auth_rmt) {
+                       client->rmt_auth_status = AUTH_STATUS_PASS;
+                       client->dbg_status = AUTH_DBG_STATUS_AUTH_RMT_FALSE;
+                       client->rmt_state = AUTH_RMT_STATE_DONE;
+                       break;
+               }
+
+               ssl_ret = RAND_bytes(id_data, sizeof(id_data));
+               if (ssl_ret != 1) {
+                       client->rmt_state = AUTH_RMT_STATE_ERROR;
+                       client->dbg_status = AUTH_DBG_STATUS_AUTH_FAIL;
+                       break;
+               }
+               client->send_chap_identifier = id_data[0];
+               snprintf(client->scratch_key_value, AUTH_STR_MAX_LEN, "%lu",
+                        (unsigned long)client->send_chap_identifier);
+               acl_set_key_value(&client->send_key_block,
+                                 AUTH_KEY_TYPE_CHAP_IDENTIFIER,
+                                 client->scratch_key_value);
+
+               client->send_chap_challenge.length = client->chap_challenge_len;
+               ssl_ret = RAND_bytes(client->send_chap_challenge.large_binary,
+                                    client->send_chap_challenge.length);
+               if (ssl_ret != 1) {
+                       client->rmt_state = AUTH_RMT_STATE_ERROR;
+                       client->dbg_status = AUTH_DBG_STATUS_AUTH_FAIL;
+                       break;
+               }
+               acl_set_key_value(&client->send_key_block,
+                                 AUTH_KEY_TYPE_CHAP_CHALLENGE, "");
+
+               client->rmt_state = AUTH_RMT_STATE_RECV_RSP;
+               break;
+       case AUTH_RMT_STATE_RECV_RSP:
+               chap_rsp_key_val = acl_get_key_val(&client->recv_key_block,
+                                                  AUTH_KEY_TYPE_CHAP_RSP);
+               chap_username_key_val = acl_get_key_val(&client->recv_key_block,
+                                                        AUTH_KEY_TYPE_CHAP_USERNAME);
+
+               if (!chap_rsp_key_val) {
+                       client->rmt_state = AUTH_RMT_STATE_ERROR;
+                       client->dbg_status = AUTH_DBG_STATUS_CHAP_RSP_EXPECTED;
+                       break;
+               }
+
+               if (!chap_username_key_val) {
+                       client->rmt_state = AUTH_RMT_STATE_ERROR;
+                       client->dbg_status = AUTH_DBG_STATUS_CHAP_USERNAME_EXPECTED;
+                       break;
+               }
+
+               status = acl_text_to_data(chap_rsp_key_val, response_data,
+                                         &rsp_len);
+
+               if (status) {
+                       client->rmt_state = AUTH_RMT_STATE_ERROR;
+                       client->dbg_status = AUTH_DBG_STATUS_CHAP_RSP_BAD;
+                       break;
+               }
+
+               if (rsp_len == client->chap_challenge_len) {
+                       dbg_status = acl_chap_compute_rsp(client, 1,
+                                                         client->send_chap_identifier,
+                                                         client->send_chap_challenge.large_binary,
+                                                         client->send_chap_challenge.length,
+                                                         my_rsp_data);
+
+                       if (dbg_status == AUTH_DBG_STATUS_NOT_SET &&
+                           memcmp(my_rsp_data, response_data,
+                                  client->chap_challenge_len) == 0) {
+                               client->rmt_state = AUTH_RMT_STATE_ERROR;
+                               client->dbg_status = AUTH_DBG_STATUS_PASSWD_IDENTICAL;
+                               break;
+                       }
+               }
+
+               strlcpy(client->chap_username, chap_username_key_val,
+                       AUTH_STR_MAX_LEN);
+
+               status = acl_chap_auth_request(client, client->chap_username,
+                                              client->send_chap_identifier,
+                                              client->send_chap_challenge.
+                                              large_binary,
+                                              client->send_chap_challenge.
+                                              length, response_data,
+                                              rsp_len);
+
+               client->rmt_auth_status = (enum auth_status) status;
+               client->auth_rsp_flag = 1;
+
+               if (client->auth_server_error_flag) {
+                       client->rmt_auth_status = AUTH_STATUS_FAIL;
+                       client->dbg_status = AUTH_DBG_STATUS_AUTH_SERVER_ERROR;
+               } else if (client->rmt_auth_status == AUTH_STATUS_PASS)
+                       client->dbg_status = AUTH_DBG_STATUS_AUTH_PASS;
+               else if (client->rmt_auth_status == AUTH_STATUS_FAIL)
+                       client->dbg_status = AUTH_DBG_STATUS_AUTH_FAIL;
+               else {
+                       client->rmt_auth_status = AUTH_STATUS_FAIL;
+                       client->dbg_status = AUTH_DBG_STATUS_AUTH_STATUS_BAD;
+               }
+               client->rmt_state = AUTH_RMT_STATE_DONE;
+
+               /* Fall through */
+       case AUTH_RMT_STATE_DONE:
+               break;
+       case AUTH_RMT_STATE_ERROR:
+       default:
+               client->phase = AUTH_PHASE_ERROR;
+       }
+}
+
+static void
+acl_hand_shake(struct iscsi_acl *client)
+{
+       if (client->phase == AUTH_PHASE_DONE)
+
+               /*
+                * Should only happen if authentication
+                * protocol error occurred.
+                */
+               return;
+
+       if (client->node_type == TYPE_INITIATOR)
+
+               /*
+                * Target should only have set T bit on response if
+                * initiator set it on previous message.
+                */
+               if (client->recv_key_block.transit_bit &&
+                   !client->transit_bit_sent_flag) {
+                       client->rmt_auth_status = AUTH_STATUS_FAIL;
+                       client->phase = AUTH_PHASE_DONE;
+                       client->dbg_status =
+                           AUTH_DBG_STATUS_T_BIT_SET_ILLEGAL;
+                       return;
+               }
+
+       if (client->phase == AUTH_PHASE_NEGOTIATE) {
+               /*
+                * Should only happen if waiting for peer
+                * to send AuthMethod key or set Transit Bit.
+                */
+               if (client->node_type == TYPE_INITIATOR)
+                       client->send_key_block.transit_bit = 1;
+               return;
+       }
+
+       if (client->rmt_state == AUTH_RMT_STATE_RECV_RSP ||
+           client->rmt_state == AUTH_RMT_STATE_DONE) {
+               if (client->node_type == TYPE_INITIATOR) {
+                       if (client->recv_key_block.transit_bit) {
+                               if (client->rmt_state !=
+                                   AUTH_RMT_STATE_DONE)
+                                       goto recv_transit_bit_err;
+                               acl_next_phase(client);
+                       } else
+                               client->send_key_block.transit_bit = 1;
+               } else {
+                       if (client->rmt_state == AUTH_RMT_STATE_DONE &&
+                           client->rmt_auth_status != AUTH_STATUS_PASS)
+                               /*
+                                * Authentication failed, don't do T bit
+                                * handshake.
+                                */
+                               acl_next_phase(client);
+                       else {
+                               /*
+                                * Target can only set T bit on response if
+                                * initiator set it on current message.
+                                */
+                               if (client->recv_key_block.transit_bit) {
+                                       client->send_key_block.transit_bit = 1;
+                                       acl_next_phase(client);
+                               }
+                       }
+               }
+       } else
+               if (client->node_type == TYPE_INITIATOR)
+                       if (client->recv_key_block.transit_bit)
+                               goto recv_transit_bit_err;
+       return;
+
+ recv_transit_bit_err:
+       /*
+        * Target set T bit on response but
+        * initiator was not done with authentication.
+        */
+       client->rmt_auth_status = AUTH_STATUS_FAIL;
+       client->phase = AUTH_PHASE_DONE;
+       client->dbg_status = AUTH_DBG_STATUS_T_BIT_SET_PREMATURE;
+}
+
+static int
+acl_rcv_end_status(struct iscsi_acl *client)
+{
+       int auth_status;
+       int key_type;
+
+       if (client->phase == AUTH_PHASE_ERROR)
+               return AUTH_STATUS_ERROR;
+
+       if (client->phase == AUTH_PHASE_DONE) {
+
+               /* Perform sanity check against configured parameters. */
+               if (client->auth_rmt && !client->auth_rsp_flag &&
+                   client->rmt_auth_status == AUTH_STATUS_PASS) {
+                       client->rmt_auth_status = AUTH_STATUS_FAIL;
+                       client->dbg_status = AUTH_DBG_STATUS_AUTHPASS_NOT_VALID;
+               }
+
+               auth_status = client->rmt_auth_status;
+
+       } else
+               auth_status = AUTH_STATUS_CONTINUE;
+
+       if (auth_status == AUTH_STATUS_CONTINUE ||
+           auth_status == AUTH_STATUS_PASS) {
+               if (client->send_key_block.dup_set) {
+                       client->rmt_auth_status = AUTH_STATUS_FAIL;
+                       client->phase = AUTH_PHASE_DONE;
+                       client->dbg_status =
+                           AUTH_DBG_STATUS_SEND_DUP_SET_KEY_VALUE;
+                       auth_status = AUTH_STATUS_FAIL;
+               } else if (client->send_key_block.str_too_long) {
+                       client->rmt_auth_status = AUTH_STATUS_FAIL;
+                       client->phase = AUTH_PHASE_DONE;
+                       client->dbg_status =
+                           AUTH_DBG_STATUS_SEND_STR_TOO_LONG;
+                       auth_status = AUTH_STATUS_FAIL;
+               } else if (client->send_key_block.too_much_data) {
+                       client->rmt_auth_status = AUTH_STATUS_FAIL;
+                       client->phase = AUTH_PHASE_DONE;
+                       client->dbg_status =
+                           AUTH_DBG_STATUS_SEND_TOO_MUCH_DATA;
+                       auth_status = AUTH_STATUS_FAIL;
+               } else {
+                       /* Check that all incoming keys have been processed. */
+
+                       for (key_type = AUTH_KEY_TYPE_FIRST;
+                            key_type < AUTH_KEY_TYPE_MAX_COUNT; key_type++)
+                               if (client->recv_key_block.key[key_type].present &&
+                                   !client->recv_key_block.key[key_type].
+                                   processed)
+                                       break;
+
+                       if (key_type < AUTH_KEY_TYPE_MAX_COUNT) {
+                               client->rmt_auth_status = AUTH_STATUS_FAIL;
+                               client->phase = AUTH_PHASE_DONE;
+                               client->dbg_status =
+                                   AUTH_DBG_STATUS_UNEXPECTED_KEY_PRESENT;
+                               auth_status = AUTH_STATUS_FAIL;
+                       }
+               }
+       }
+
+       if (auth_status != AUTH_STATUS_PASS &&
+           auth_status != AUTH_STATUS_CONTINUE) {
+               int auth_method_key_present = 0;
+               int chap_alg_key_present = 0;
+
+               /*
+                * Suppress send keys on error,
+                * except for AuthMethod and CHAP_A.
+                */
+               if (client->node_type == TYPE_TARGET) {
+                       if (acl_get_key_val(&client->send_key_block,
+                                           AUTH_KEY_TYPE_AUTH_METHOD))
+                               auth_method_key_present = 1;
+                       else if (acl_get_key_val(&client->send_key_block,
+                                                AUTH_KEY_TYPE_CHAP_ALG))
+                               chap_alg_key_present = 1;
+               }
+
+               acl_init_key_blk(&client->send_key_block);
+
+               if (client->node_type == TYPE_TARGET) {
+                       if (auth_method_key_present &&
+                           client->negotiated_auth_method ==
+                           AUTH_OPTION_REJECT)
+                               acl_set_key_value(&client->send_key_block,
+                                                 AUTH_KEY_TYPE_AUTH_METHOD,
+                                                 acl_reject_option_name);
+                       else if (chap_alg_key_present &&
+                                client->negotiated_chap_alg ==
+                                AUTH_OPTION_REJECT)
+                               acl_set_key_value(&client->send_key_block,
+                                                 AUTH_KEY_TYPE_CHAP_ALG,
+                                                 acl_reject_option_name);
+               }
+       }
+       client->recv_in_progress_flag = 0;
+
+       return auth_status;
+}
+
+int
+acl_recv_begin(struct iscsi_acl *client)
+{
+       if (!client || client->signature != ACL_SIGNATURE)
+               return AUTH_STATUS_ERROR;
+
+       if (client->phase == AUTH_PHASE_ERROR)
+               return AUTH_STATUS_ERROR;
+
+       if (client->phase == AUTH_PHASE_DONE) {
+               client->phase = AUTH_PHASE_ERROR;
+               return AUTH_STATUS_ERROR;
+       }
+
+       if (client->recv_in_progress_flag) {
+               client->phase = AUTH_PHASE_ERROR;
+               return AUTH_STATUS_ERROR;
+       }
+
+       client->recv_in_progress_flag = 1;
+
+       if (client->phase == AUTH_PHASE_CONFIGURE)
+               acl_next_phase(client);
+
+       client->transit_bit_sent_flag = client->send_key_block.transit_bit;
+
+       acl_init_key_blk(&client->recv_key_block);
+       acl_init_key_blk(&client->send_key_block);
+
+       return AUTH_STATUS_NO_ERROR;
+}
+
+int
+acl_recv_end(struct iscsi_acl *client, iscsi_session_t *session_handle)
+{
+       int next_phase_flag = 0;
+
+       if (!client || client->signature != ACL_SIGNATURE)
+               return AUTH_STATUS_ERROR;
+
+       if (client->phase == AUTH_PHASE_ERROR)
+               return AUTH_STATUS_ERROR;
+
+       if (!client->recv_in_progress_flag)  {
+               client->phase = AUTH_PHASE_ERROR;
+               return AUTH_STATUS_ERROR;
+       }
+
+       if (client->recv_end_count > AUTH_RECV_END_MAX_COUNT) {
+               client->rmt_auth_status = AUTH_STATUS_FAIL;
+               client->phase = AUTH_PHASE_DONE;
+               client->dbg_status = AUTH_DBG_STATUS_RECV_MSG_COUNT_LIMIT;
+       } else if (client->recv_key_block.dup_set) {
+               client->rmt_auth_status = AUTH_STATUS_FAIL;
+               client->phase = AUTH_PHASE_DONE;
+               client->dbg_status = AUTH_DBG_STATUS_RECV_DUP_SET_KEY_VALUE;
+       } else if (client->recv_key_block.str_too_long) {
+               client->rmt_auth_status = AUTH_STATUS_FAIL;
+               client->phase = AUTH_PHASE_DONE;
+               client->dbg_status = AUTH_DBG_STATUS_RECV_STR_TOO_LONG;
+       } else if (client->recv_key_block.too_much_data) {
+               client->rmt_auth_status = AUTH_STATUS_FAIL;
+               client->phase = AUTH_PHASE_DONE;
+               client->dbg_status = AUTH_DBG_STATUS_RECV_TOO_MUCH_DATA;
+       }
+
+       client->recv_end_count++;
+       client->session_handle = session_handle;
+
+       switch (client->phase) {
+       case AUTH_PHASE_NEGOTIATE:
+               acl_chk_auth_method_key(client);
+               if (client->auth_method_valid_neg_role ==
+                   AUTH_NEG_ROLE_RESPONDER) {
+                       if (client->negotiated_auth_method ==
+                           AUTH_OPTION_NOT_PRESENT) {
+                               if (client->auth_rmt ||
+                                   !client->recv_key_block.transit_bit) {
+                                       /*
+                                        * No AuthMethod key from peer on
+                                        * first message, try moving the
+                                        * process along by sending the
+                                        * AuthMethod key.
+                                        */
+
+                                       client->auth_method_valid_neg_role =
+                                           AUTH_NEG_ROLE_ORIGINATOR;
+                                       acl_set_auth_method_key(client,
+                                                               client->auth_method_valid_count,
+                                                               client->auth_method_valid_list);
+                                       break;
+                               }
+
+                               /*
+                                * Special case if peer sent no AuthMethod key,
+                                * but did set Transit Bit, allowing this side
+                                * to do a null authentication, and compelete
+                                * the iSCSI security phase without either side
+                                * sending the AuthMethod key.
+                                */
+                       } else
+                               /* Send response to AuthMethod key. */
+                               acl_set_auth_method_key(client, 1,
+                                                       &client->negotiated_auth_method);
+
+                       if (client->node_type == TYPE_INITIATOR)
+                               acl_next_phase(client);
+                       else
+                               next_phase_flag = 1;
+               } else {
+
+                       if (client->negotiated_auth_method ==
+                           AUTH_OPTION_NOT_PRESENT) {
+                               client->rmt_auth_status = AUTH_STATUS_FAIL;
+                               client->phase = AUTH_PHASE_DONE;
+                               client->dbg_status =
+                                   AUTH_DBG_STATUS_AUTH_METHOD_EXPECTED;
+                               break;
+                       }
+
+                       acl_next_phase(client);
+               }
+               break;
+       case AUTH_PHASE_AUTHENTICATE:
+       case AUTH_PHASE_DONE:
+               break;
+       default:
+               client->phase = AUTH_PHASE_ERROR;
+               return AUTH_STATUS_ERROR;
+       }
+
+       switch (client->phase) {
+       case AUTH_PHASE_NEGOTIATE:
+               if (next_phase_flag)
+                       acl_next_phase(client);
+               break;
+       case AUTH_PHASE_AUTHENTICATE:
+               /*
+                * Must call acl_local_auth()
+                * before acl_rmt_auth()
+                * to insure processing of the CHAP algorithm key,
+                * and to avoid leaving an in progress request to the
+                * authentication service.
+                */
+               acl_local_auth(client);
+
+               if (client->local_state != AUTH_LOCAL_STATE_ERROR)
+                       acl_rmt_auth(client);
+
+               if (client->local_state == AUTH_LOCAL_STATE_ERROR ||
+                   client->rmt_state == AUTH_RMT_STATE_ERROR) {
+
+                       client->rmt_auth_status = AUTH_STATUS_FAIL;
+                       client->phase = AUTH_PHASE_DONE;
+                       /* client->dbg_status should already be set. */
+               }
+               break;
+       case AUTH_PHASE_DONE:
+               break;
+       default:
+               client->phase = AUTH_PHASE_ERROR;
+               return AUTH_STATUS_ERROR;
+       }
+
+       acl_hand_shake(client);
+
+       return acl_rcv_end_status(client);
+}
+
+const char *
+acl_get_key_name(int key_type)
+{
+       /*
+        * Note: The ordering of this table must match the order
+        *       defined by enum auth_key_type in iscsi-auth-client.h.
+        */
+       static char *const key_names[AUTH_KEY_TYPE_MAX_COUNT] = {
+               "AuthMethod",
+               "CHAP_A",
+               "CHAP_N",
+               "CHAP_R",
+               "CHAP_I",
+               "CHAP_C"
+       };
+
+       if (key_type < AUTH_KEY_TYPE_FIRST || key_type > AUTH_KEY_TYPE_LAST)
+               return NULL;
+
+       return key_names[key_type];
+}
+
+int
+acl_get_next_key_type(int *key_type)
+{
+       if (*key_type >= AUTH_KEY_TYPE_LAST)
+               return AUTH_STATUS_ERROR;
+
+       if (*key_type < AUTH_KEY_TYPE_FIRST)
+               *key_type = AUTH_KEY_TYPE_FIRST;
+       else
+               (*key_type)++;
+
+       return AUTH_STATUS_NO_ERROR;
+}
+
+int
+acl_recv_key_value(struct iscsi_acl *client, int key_type,
+                  const char *user_key_val)
+{
+       if (!client || client->signature != ACL_SIGNATURE)
+               return AUTH_STATUS_ERROR;
+
+       if (client->phase != AUTH_PHASE_NEGOTIATE &&
+           client->phase != AUTH_PHASE_AUTHENTICATE) {
+               client->phase = AUTH_PHASE_ERROR;
+               return AUTH_STATUS_ERROR;
+       }
+
+       if (key_type < AUTH_KEY_TYPE_FIRST || key_type > AUTH_KEY_TYPE_LAST) {
+               client->phase = AUTH_PHASE_ERROR;
+               return AUTH_STATUS_ERROR;
+       }
+
+       if (key_type == AUTH_KEY_TYPE_CHAP_CHALLENGE) {
+               client->recv_chap_challenge.length =
+                   AUTH_LARGE_BINARY_MAX_LEN;
+               client->recv_chap_challenge_status =
+                   acl_text_to_data(user_key_val,
+                                    client->recv_chap_challenge.large_binary,
+                                    &client->recv_chap_challenge.length);
+               user_key_val = "";
+       }
+
+       acl_set_key_value(&client->recv_key_block, key_type, user_key_val);
+
+       return AUTH_STATUS_NO_ERROR;
+}
+
+int
+acl_send_key_val(struct iscsi_acl *client, int key_type, int *key_present,
+                char *user_key_val, unsigned int max_length)
+{
+       const char *key_val;
+
+       if (!client || client->signature != ACL_SIGNATURE)
+               return AUTH_STATUS_ERROR;
+
+       if (client->phase != AUTH_PHASE_CONFIGURE &&
+           client->phase != AUTH_PHASE_NEGOTIATE &&
+           client->phase != AUTH_PHASE_AUTHENTICATE &&
+           client->phase != AUTH_PHASE_DONE) {
+               client->phase = AUTH_PHASE_ERROR;
+               return AUTH_STATUS_ERROR;
+       }
+
+       if (key_type < AUTH_KEY_TYPE_FIRST || key_type > AUTH_KEY_TYPE_LAST) {
+               client->phase = AUTH_PHASE_ERROR;
+               return AUTH_STATUS_ERROR;
+       }
+
+       key_val = acl_get_key_val(&client->send_key_block, key_type);
+       if (key_val) {
+               if (key_type == AUTH_KEY_TYPE_CHAP_CHALLENGE) {
+                       if (acl_data_to_text(client->send_chap_challenge.large_binary,
+                                            client->send_chap_challenge.length, user_key_val,
+                                            max_length)) {
+                               client->phase = AUTH_PHASE_ERROR;
+                               return AUTH_STATUS_ERROR;
+                       }
+               } else if (strlcpy(user_key_val, key_val, max_length) >=
+                          max_length) {
+                               client->phase = AUTH_PHASE_ERROR;
+                               return AUTH_STATUS_ERROR;
+                       }
+               *key_present = 1;
+       } else
+               *key_present = 0;
+
+       return AUTH_STATUS_NO_ERROR;
+}
+
+int
+acl_recv_transit_bit(struct iscsi_acl *client, int value)
+{
+       if (!client || client->signature != ACL_SIGNATURE)
+               return AUTH_STATUS_ERROR;
+
+       if (client->phase != AUTH_PHASE_NEGOTIATE &&
+           client->phase != AUTH_PHASE_AUTHENTICATE) {
+
+               client->phase = AUTH_PHASE_ERROR;
+               return AUTH_STATUS_ERROR;
+       }
+
+       if (value)
+               client->recv_key_block.transit_bit = 1;
+       else
+               client->recv_key_block.transit_bit = 0;
+
+       return AUTH_STATUS_NO_ERROR;
+}
+
+int
+acl_send_transit_bit(struct iscsi_acl *client, int *value)
+{
+       if (!client || client->signature != ACL_SIGNATURE)
+               return AUTH_STATUS_ERROR;
+
+       if (client->phase != AUTH_PHASE_CONFIGURE &&
+           client->phase != AUTH_PHASE_NEGOTIATE &&
+           client->phase != AUTH_PHASE_AUTHENTICATE &&
+           client->phase != AUTH_PHASE_DONE) {
+
+               client->phase = AUTH_PHASE_ERROR;
+               return AUTH_STATUS_ERROR;
+       }
+
+       *value = client->send_key_block.transit_bit;
+
+       return AUTH_STATUS_NO_ERROR;
+}
+
+static int
+acl_set_option_list(struct iscsi_acl *client, unsigned int opt_count,
+                   const int *opt_list, unsigned int *clnt_optn_count,
+                   int *clnt_optn_list, unsigned int optn_max_count,
+                   int (*chk_option)(int),
+                   int (*chk_list)(unsigned int opt_count, const int *opt_list))
+{
+       unsigned int i, j;
+
+       if (!client || client->signature != ACL_SIGNATURE)
+               return AUTH_STATUS_ERROR;
+
+       if (client->phase != AUTH_PHASE_CONFIGURE ||
+           opt_count > optn_max_count) {
+               client->phase = AUTH_PHASE_ERROR;
+               return AUTH_STATUS_ERROR;
+       }
+
+       for (i = 0; i < opt_count; i++)
+               if (chk_option(opt_list[i])) {
+                       client->phase = AUTH_PHASE_ERROR;
+                       return AUTH_STATUS_ERROR;
+               }
+
+       /* Check for duplicate entries. */
+       for (i = 0; i < opt_count; i++)
+               for (j = 0; j < opt_count; j++) {
+                       if (j == i)
+                               continue;
+                       if (opt_list[i] == opt_list[j]) {
+                               client->phase = AUTH_PHASE_ERROR;
+                               return AUTH_STATUS_ERROR;
+                       }
+               }
+
+       /* Check for key specific constraints. */
+       if (chk_list)
+               if (chk_list(opt_count, opt_list)) {
+                       client->phase = AUTH_PHASE_ERROR;
+                       return AUTH_STATUS_ERROR;
+               }
+
+       for (i = 0; i < opt_count; i++)
+               clnt_optn_list[i] = opt_list[i];
+
+       *clnt_optn_count = opt_count;
+
+       return AUTH_STATUS_NO_ERROR;
+}
+
+static int
+acl_chk_auth_method_list(unsigned int option_count, const int *option_list)
+{
+       unsigned int i;
+
+       if (!option_list || option_count < 2)
+               return 1;
+
+       if (option_list[option_count - 1] != AUTH_OPTION_NONE)
+               return 1;
+
+       for (i = 0; i < (option_count - 1); i++)
+               if (option_list[i] != AUTH_OPTION_NONE)
+                       return 0;
+
+       return 0;
+}
+
+static void
+acl_set_auth_method_valid(struct iscsi_acl *client)
+{
+       unsigned int i, j = 0;
+       int option = 0;
+
+       /*
+        * Following checks may need to be revised if
+        * authentication options other than CHAP and none
+        * are supported.
+        */
+       if (client->node_type == TYPE_INITIATOR) {
+               if (client->auth_rmt)
+                       /*
+                        * If initiator doing authentication,
+                        * don't offer authentication option none.
+                        */
+                       option = 1;
+               else if (!client->passwd_present)
+                       /*
+                        * If initiator password not set,
+                        * only offer authentication option none.
+                        */
+                       option = 2;
+       }
+
+       if (client->node_type == TYPE_TARGET) {
+               if (client->auth_rmt)
+                       /*
+                        * If target doing authentication,
+                        * don't accept authentication option none.
+                        */
+                       option = 1;
+               else
+                       /*
+                        * If target not doing authentication,
+                        * only accept authentication option none.
+                        */
+                       option = 2;
+       }
+
+       for (i = 0; i < client->auth_method_count; i++) {
+               if (option == 1) {
+                       if (client->auth_method_list[i] == AUTH_OPTION_NONE)
+                               continue;
+               } else if (option == 2)
+                       if (client->auth_method_list[i] != AUTH_OPTION_NONE)
+                               continue;
+               client->auth_method_valid_list[j++] = client->auth_method_list[i];
+       }
+
+       client->auth_method_valid_count = j;
+
+       acl_init_key_blk(&client->send_key_block);
+
+       if (client->node_type == TYPE_INITIATOR) {
+               if (client->auth_rmt) {
+                       /*
+                        * Initiator wants to authenticate target,
+                        * always send AuthMethod key.
+                        */
+                       client->send_key_block.transit_bit = 0;
+                       client->auth_method_valid_neg_role =
+                           AUTH_NEG_ROLE_ORIGINATOR;
+               } else {
+                       client->send_key_block.transit_bit = 1;
+                       client->auth_method_valid_neg_role =
+                           client->auth_method_neg_role;
+               }
+       } else {
+               client->send_key_block.transit_bit = 0;
+               client->auth_method_valid_neg_role = AUTH_NEG_ROLE_RESPONDER;
+       }
+
+       if (client->auth_method_valid_neg_role == AUTH_NEG_ROLE_ORIGINATOR)
+               acl_set_auth_method_key(client, client->auth_method_valid_count,
+                                       client->auth_method_valid_list);
+       else {
+               int value = AUTH_OPTION_NOT_PRESENT;
+               acl_set_auth_method_key(client, 1, &value);
+       }
+}
+
+static int
+acl_set_auth_method_list(struct iscsi_acl *client, unsigned int option_count,
+                        const int *option_list)
+{
+       int status;
+
+       status = acl_set_option_list(client, option_count, option_list,
+                                    &client->auth_method_count,
+                                    client->auth_method_list,
+                                    AUTH_METHOD_MAX_COUNT,
+                                    acl_chk_auth_mthd_optn,
+                                    acl_chk_auth_method_list);
+
+       if (status != AUTH_STATUS_NO_ERROR)
+               return status;
+
+       /* Setting authMethod affects auth_method_valid. */
+       acl_set_auth_method_valid(client);
+
+       return AUTH_STATUS_NO_ERROR;
+}
+
+static int
+acl_chk_chap_alg_list(unsigned int option_count, const int *option_list)
+{
+       if (!option_list || option_count < 1)
+               return 1;
+
+       return 0;
+}
+
+int
+acl_set_chap_alg_list(struct iscsi_acl *client, unsigned int option_count,
+                     const int *option_list)
+{
+       return acl_set_option_list(client, option_count, option_list,
+                                  &client->chap_alg_count,
+                                  client->chap_alg_list,
+                                  AUTH_CHAP_ALG_MAX_COUNT,
+                                  acl_chk_chap_alg_optn,
+                                  acl_chk_chap_alg_list);
+}
+
+int
+acl_init_chap_digests(int *value_list, unsigned *chap_algs, int conf_count) {
+       EVP_MD_CTX *context = EVP_MD_CTX_new();
+       int i = 0;
+
+       for (int j = 0; j < conf_count; j++) {
+               switch (chap_algs[j]) {
+               case AUTH_CHAP_ALG_MD5:
+                       if (EVP_DigestInit_ex(context, EVP_md5(), NULL)) {
+                               value_list[i++] = AUTH_CHAP_ALG_MD5;
+                       } else {
+                               log_warning("Ignoring CHAP algorthm request for "
+                                           "MD5 due to crypto lib configuration");
+                       }
+                       break;
+               case AUTH_CHAP_ALG_SHA1:
+                       if (EVP_DigestInit_ex(context, EVP_sha1(), NULL)) {
+                               value_list[i++] = AUTH_CHAP_ALG_SHA1;
+                       } else {
+                               log_warning("Ignoring CHAP algorthm request for "
+                                           "SHA1 due to crypto lib configuration");
+                       }
+                       break;
+               case AUTH_CHAP_ALG_SHA256:
+                       if (EVP_DigestInit_ex(context, EVP_sha256(), NULL)) {
+                               value_list[i++] = AUTH_CHAP_ALG_SHA256;
+                       } else {
+                               log_warning("Ignoring CHAP algorthm request for "
+                                           "SHA256 due to crypto lib configuration");
+                       }
+                       break;
+               case AUTH_CHAP_ALG_SHA3_256:
+                       if (EVP_DigestInit_ex(context, EVP_sha3_256(), NULL)) {
+                               value_list[i++] = AUTH_CHAP_ALG_SHA3_256;
+                       } else {
+                               log_warning("Ignoring CHAP algorthm request for "
+                                           "SHA3-256 due to crypto lib configuration");
+                       }
+                       break;
+               case ~0:
+                       /* unset value in array, just ignore */
+                       break;
+               default:
+                       log_warning("Ignoring unknown CHAP algorithm request "
+                                   "'%d'", chap_algs[j]);
+                       break;
+               }
+       }
+
+       return i;
+}
+
+#define MAX(a,b) ((a) > (b) ? (a) : (b))
+
+int
+acl_init(int node_type, int buf_desc_count, struct auth_buffer_desc *buff_desc)
+{
+       struct iscsi_acl *client;
+       struct auth_str_block *recv_str_blk;
+       struct auth_str_block *send_str_blk;
+       struct auth_large_binary *recv_chap_challenge;
+       struct auth_large_binary *send_chap_challenge;
+       int value_list[MAX(AUTH_METHOD_MAX_COUNT, AUTH_CHAP_ALG_MAX_COUNT)];
+
+       if (buf_desc_count != 5 || !buff_desc)
+               return AUTH_STATUS_ERROR;
+
+       if (!buff_desc[0].address ||
+           buff_desc[0].length != sizeof(*client))
+               return AUTH_STATUS_ERROR;
+       client = (struct iscsi_acl *)buff_desc[0].address;
+
+       if (!buff_desc[1].address ||
+           buff_desc[1].length != sizeof(*recv_str_blk))
+               return AUTH_STATUS_ERROR;
+       recv_str_blk = (struct auth_str_block *)buff_desc[1].address;
+
+       if (!buff_desc[2].address ||
+           buff_desc[2].length != sizeof(*send_str_blk))
+               return AUTH_STATUS_ERROR;
+
+       send_str_blk = (struct auth_str_block *)buff_desc[2].address;
+
+       if (!buff_desc[3].address ||
+           buff_desc[3].length != sizeof(*recv_chap_challenge))
+               return AUTH_STATUS_ERROR;
+
+       recv_chap_challenge = (struct auth_large_binary *)
+                            buff_desc[3].address;
+
+       if (!buff_desc[4].address ||
+           buff_desc[4].length != sizeof(*send_chap_challenge))
+               return AUTH_STATUS_ERROR;
+       send_chap_challenge = (struct auth_large_binary *)
+                           buff_desc[4].address;
+       memset(client, 0, sizeof(*client));
+       memset(recv_str_blk, 0, sizeof(*recv_str_blk));
+       memset(send_str_blk, 0, sizeof(*send_str_blk));
+       memset(recv_chap_challenge, 0, sizeof(*recv_chap_challenge));
+       memset(send_chap_challenge, 0, sizeof(*send_chap_challenge));
+
+       client->recv_key_block.str_block = recv_str_blk->str_block;
+       client->send_key_block.str_block = send_str_blk->str_block;
+       client->recv_chap_challenge.large_binary = recv_chap_challenge->large_binary;
+       client->send_chap_challenge.large_binary = send_chap_challenge->large_binary;
+
+       if (node_type != TYPE_INITIATOR  && node_type != TYPE_TARGET) {
+               client->phase = AUTH_PHASE_ERROR;
+               return AUTH_STATUS_ERROR;
+       }
+
+       client->signature = ACL_SIGNATURE;
+       client->node_type = (enum auth_node_type) node_type;
+       client->auth_rmt = 1;
+       client->passwd_present = 0;
+       client->ip_sec = 0;
+
+       client->phase = AUTH_PHASE_CONFIGURE;
+       client->negotiated_auth_method = AUTH_OPTION_NOT_PRESENT;
+       client->negotiated_chap_alg = AUTH_OPTION_NOT_PRESENT;
+
+       if (client->node_type == TYPE_INITIATOR)
+               client->auth_method_neg_role = AUTH_NEG_ROLE_ORIGINATOR;
+       else
+               /* Initial value ignored for Target. */
+               client->auth_method_neg_role = AUTH_NEG_ROLE_RESPONDER;
+
+       value_list[0] = AUTH_METHOD_CHAP;
+       value_list[1] = AUTH_OPTION_NONE;
+
+       /*
+        * Must call after setting auth_rmt, password,
+        * and auth_method_neg_role
+        */
+       if (acl_set_auth_method_list(client, 2, value_list) !=
+           AUTH_STATUS_NO_ERROR) {
+               client->phase = AUTH_PHASE_ERROR;
+               return AUTH_STATUS_ERROR;
+       }
+
+       return AUTH_STATUS_NO_ERROR;
+}
+
+int
+acl_finish(struct iscsi_acl *client)
+{
+       if (!client || client->signature != ACL_SIGNATURE)
+               return AUTH_STATUS_ERROR;
+
+       memset(client, 0, sizeof(*client));
+
+       return AUTH_STATUS_NO_ERROR;
+}
+
+int
+acl_set_user_name(struct iscsi_acl *client, const char *username)
+{
+       if (!client || client->signature != ACL_SIGNATURE)
+               return AUTH_STATUS_ERROR;
+
+       if (client->phase != AUTH_PHASE_CONFIGURE ||
+           acl_chk_string(username, AUTH_STR_MAX_LEN, NULL)) {
+               client->phase = AUTH_PHASE_ERROR;
+               return AUTH_STATUS_ERROR;
+       }
+
+       if (!username)
+               client->username[0] = '\0';
+       else if (strlcpy(client->username, username, AUTH_STR_MAX_LEN) >=
+                AUTH_STR_MAX_LEN) {
+               client->phase = AUTH_PHASE_ERROR;
+               return AUTH_STATUS_ERROR;
+       }
+
+       return AUTH_STATUS_NO_ERROR;
+}
+
+int
+acl_set_passwd(struct iscsi_acl *client, const unsigned char *passwd_data,
+              unsigned int passwd_length)
+{
+       if (!client || client->signature != ACL_SIGNATURE)
+               return AUTH_STATUS_ERROR;
+
+       if (client->phase != AUTH_PHASE_CONFIGURE ||
+           passwd_length > AUTH_STR_MAX_LEN) {
+               client->phase = AUTH_PHASE_ERROR;
+               return AUTH_STATUS_ERROR;
+       }
+
+       memcpy(client->passwd_data, passwd_data, passwd_length);
+       client->passwd_length = passwd_length;
+       client->passwd_present = 1;
+
+       /* Setting password may affect auth_method_valid. */
+       acl_set_auth_method_valid(client);
+
+       return AUTH_STATUS_NO_ERROR;
+}
+
+int
+acl_set_auth_rmt(struct iscsi_acl *client, int auth_rmt)
+{
+       if (!client || client->signature != ACL_SIGNATURE)
+               return AUTH_STATUS_ERROR;
+
+       if (client->phase != AUTH_PHASE_CONFIGURE) {
+               client->phase = AUTH_PHASE_ERROR;
+               return AUTH_STATUS_ERROR;
+       }
+
+       client->auth_rmt = auth_rmt;
+
+       /* Setting auth_rmt may affect auth_method_valid. */
+       acl_set_auth_method_valid(client);
+
+       return AUTH_STATUS_NO_ERROR;
+}
+
+int
+acl_set_ip_sec(struct iscsi_acl *client, int ip_sec)
+{
+       if (!client || client->signature != ACL_SIGNATURE)
+               return AUTH_STATUS_ERROR;
+
+       if (client->phase != AUTH_PHASE_CONFIGURE) {
+               client->phase = AUTH_PHASE_ERROR;
+               return AUTH_STATUS_ERROR;
+       }
+
+       client->ip_sec = ip_sec;
+
+       return AUTH_STATUS_NO_ERROR;
+}
+
+int
+acl_get_dbg_status(struct iscsi_acl *client, int *value)
+{
+       if (!client || client->signature != ACL_SIGNATURE)
+               return AUTH_STATUS_ERROR;
+
+       if (client->phase != AUTH_PHASE_DONE) {
+               client->phase = AUTH_PHASE_ERROR;
+               return AUTH_STATUS_ERROR;
+       }
+
+       *value = client->dbg_status;
+
+       return AUTH_STATUS_NO_ERROR;
+}
+
+const char *
+acl_dbg_status_to_text(int dbg_status)
+{
+       /*
+        * Note: The ordering of this table must match the order
+        *       defined by enum auth_dbg_status in iscsi-auth-client.h.
+        */
+       static char *const dbg_text[AUTH_DBG_STATUS_MAX_COUNT] = {
+               "Debug status not set",
+               "Authentication request passed",
+               "Authentication not enabled",
+               "Authentication request failed",
+               "AuthMethod bad",
+               "CHAP algorithm bad",
+               "Decrypt password failed",
+               "Local password too short with no IPSec",
+               "Unexpected error from authentication server",
+               "Authentication request status bad",
+               "Authentication pass status not valid",
+               "Same key set more than once on send",
+               "Key value too long on send",
+               "Too much data on send",
+               "AuthMethod key expected",
+               "CHAP algorithm key expected",
+               "CHAP identifier expected",
+               "CHAP challenge expected",
+               "CHAP response expected",
+               "CHAP username expected",
+               "AuthMethod key not present",
+               "AuthMethod negotiation failed",
+               "AuthMethod negotiated to none",
+               "CHAP algorithm negotiation failed",
+               "CHAP challenge reflected",
+               "Local password same as remote",
+               "Local password not set",
+               "CHAP identifier bad",
+               "CHAP challenge bad",
+               "CHAP response bad",
+               "Unexpected key present",
+               "T bit set on response, but not on previous message",
+               "T bit set on response, but authenticaton not complete",
+               "Message count limit reached on receive",
+               "Same key set more than once on receive",
+               "Key value too long on receive",
+               "Too much data on receive"
+       };
+
+       if (dbg_status < 0 || dbg_status >= AUTH_DBG_STATUS_MAX_COUNT)
+               return "Unknown error";
+
+       return dbg_text[dbg_status];
+}
+
+int
+acl_data(unsigned char *out_data, unsigned int *out_length,
+         unsigned char *in_data, unsigned int in_length)
+{
+       if (*out_length < in_length)
+               return 1;       /* error */
+
+       memcpy(out_data, in_data, in_length);
+       *out_length = in_length;
+
+       return 0;               /* no error */
+}
+
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/auth.h b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/auth.h
new file mode 100644 (file)
index 0000000..16cdb24
--- /dev/null
@@ -0,0 +1,295 @@
+/*
+ * iSCSI Authorization Library
+ *
+ * maintained by open-iscsi@@googlegroups.com
+ *
+ * Originally based on:
+ * Copyright (C) 2001 Cisco Systems, Inc.
+ *
+ * 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 AUTH_CLIENT_H
+#define AUTH_CLIENT_H
+
+struct iscsi_session;
+
+enum {
+       AUTH_STR_MAX_LEN = 256,
+       AUTH_STR_BLOCK_MAX_LEN = 1024,
+       AUTH_LARGE_BINARY_MAX_LEN = 1024,
+       AUTH_RECV_END_MAX_COUNT = 10,
+       ACL_SIGNATURE = 0x5984B2E3,
+       AUTH_CHAP_MD5_RSP_LEN = 16,
+       AUTH_CHAP_SHA1_RSP_LEN = 20,
+       AUTH_CHAP_SHA256_RSP_LEN = 32,
+       AUTH_CHAP_SHA3_256_RSP_LEN = 32,
+       AUTH_CHAP_RSP_MAX = 32,
+};
+
+/*
+ * Note: The ordering of these values are chosen to match
+ *       the ordering of the keys as shown in the iSCSI spec.
+ *       The order of table key_names in acl_get_key_name()
+ *       must match the order defined by enum auth_key_type.
+ */
+enum auth_key_type {
+       AUTH_KEY_TYPE_NONE = -1,
+       AUTH_KEY_TYPE_FIRST = 0,
+       AUTH_KEY_TYPE_AUTH_METHOD = AUTH_KEY_TYPE_FIRST,
+       AUTH_KEY_TYPE_CHAP_ALG,
+       AUTH_KEY_TYPE_CHAP_USERNAME,
+       AUTH_KEY_TYPE_CHAP_RSP,
+       AUTH_KEY_TYPE_CHAP_IDENTIFIER,
+       AUTH_KEY_TYPE_CHAP_CHALLENGE,
+       AUTH_KEY_TYPE_MAX_COUNT,
+       AUTH_KEY_TYPE_LAST = AUTH_KEY_TYPE_MAX_COUNT - 1
+};
+
+enum {
+       /* Common options for all keys. */
+       AUTH_OPTION_REJECT = -2,
+       AUTH_OPTION_NOT_PRESENT = -1,
+       AUTH_OPTION_NONE = 1,
+
+       AUTH_METHOD_CHAP = 2,
+       AUTH_METHOD_MAX_COUNT = 2,
+
+       AUTH_CHAP_ALG_MD5 = 5,
+       AUTH_CHAP_ALG_SHA1 = 6,
+       AUTH_CHAP_ALG_SHA256 = 7,
+       AUTH_CHAP_ALG_SHA3_256 = 8,
+       AUTH_CHAP_ALG_MAX_COUNT = 5
+};
+
+enum auth_neg_role {
+       AUTH_NEG_ROLE_ORIGINATOR = 1,
+       AUTH_NEG_ROLE_RESPONDER = 2
+};
+
+enum auth_status {
+       AUTH_STATUS_NO_ERROR = 0,
+       AUTH_STATUS_ERROR,
+       AUTH_STATUS_PASS,
+       AUTH_STATUS_FAIL,
+       AUTH_STATUS_CONTINUE,
+};
+
+/*
+ * Note: The order of table dbg_text in acl_dbg_status_to_text()
+ *       must match the ordered defined by enum auth_dbg_status.
+ */
+enum auth_dbg_status {
+       AUTH_DBG_STATUS_NOT_SET = 0,
+
+       AUTH_DBG_STATUS_AUTH_PASS,
+       AUTH_DBG_STATUS_AUTH_RMT_FALSE,
+
+       AUTH_DBG_STATUS_AUTH_FAIL,
+
+       AUTH_DBG_STATUS_AUTH_METHOD_BAD,
+       AUTH_DBG_STATUS_CHAP_ALG_BAD,
+       AUTH_DBG_STATUS_PASSWD_DECRYPT_FAILED,
+       AUTH_DBG_STATUS_PASSWD_TOO_SHORT_WITH_NO_IPSEC,
+       AUTH_DBG_STATUS_AUTH_SERVER_ERROR,
+       AUTH_DBG_STATUS_AUTH_STATUS_BAD,
+       AUTH_DBG_STATUS_AUTHPASS_NOT_VALID,
+       AUTH_DBG_STATUS_SEND_DUP_SET_KEY_VALUE,
+       AUTH_DBG_STATUS_SEND_STR_TOO_LONG,
+       AUTH_DBG_STATUS_SEND_TOO_MUCH_DATA,
+
+       AUTH_DBG_STATUS_AUTH_METHOD_EXPECTED,
+       AUTH_DBG_STATUS_CHAP_ALG_EXPECTED,
+       AUTH_DBG_STATUS_CHAP_IDENTIFIER_EXPECTED,
+       AUTH_DBG_STATUS_CHAP_CHALLENGE_EXPECTED,
+       AUTH_DBG_STATUS_CHAP_RSP_EXPECTED,
+       AUTH_DBG_STATUS_CHAP_USERNAME_EXPECTED,
+
+       AUTH_DBG_STATUS_AUTH_METHOD_NOT_PRESENT,
+       AUTH_DBG_STATUS_AUTH_METHOD_REJECT,
+       AUTH_DBG_STATUS_AUTH_METHOD_NONE,
+       AUTH_DBG_STATUS_CHAP_ALG_REJECT,
+       AUTH_DBG_STATUS_CHAP_CHALLENGE_REFLECTED,
+       AUTH_DBG_STATUS_PASSWD_IDENTICAL,
+
+       AUTH_DBG_STATUS_LOCAL_PASSWD_NOT_SET,
+
+       AUTH_DBG_STATUS_CHAP_IDENTIFIER_BAD,
+       AUTH_DBG_STATUS_CHALLENGE_BAD,
+       AUTH_DBG_STATUS_CHAP_RSP_BAD,
+       AUTH_DBG_STATUS_UNEXPECTED_KEY_PRESENT,
+       AUTH_DBG_STATUS_T_BIT_SET_ILLEGAL,
+       AUTH_DBG_STATUS_T_BIT_SET_PREMATURE,
+
+       AUTH_DBG_STATUS_RECV_MSG_COUNT_LIMIT,
+       AUTH_DBG_STATUS_RECV_DUP_SET_KEY_VALUE,
+       AUTH_DBG_STATUS_RECV_STR_TOO_LONG,
+       AUTH_DBG_STATUS_RECV_TOO_MUCH_DATA,
+       AUTH_DBG_STATUS_MAX_COUNT
+};
+
+enum auth_node_type {
+       TYPE_INITIATOR = 1,
+       TYPE_TARGET = 2
+};
+
+enum auth_phase {
+       AUTH_PHASE_CONFIGURE = 1,
+       AUTH_PHASE_NEGOTIATE,
+       AUTH_PHASE_AUTHENTICATE,
+       AUTH_PHASE_DONE,
+       AUTH_PHASE_ERROR
+};
+
+enum auth_local_state {
+       AUTH_LOCAL_STATE_SEND_ALG = 1,
+       AUTH_LOCAL_STATE_RECV_ALG,
+       AUTH_LOCAL_STATE_RECV_CHALLENGE,
+       AUTH_LOCAL_STATE_DONE,
+       AUTH_LOCAL_STATE_ERROR
+};
+
+enum auth_rmt_state {
+       AUTH_RMT_STATE_SEND_ALG = 1,
+       AUTH_RMT_STATE_SEND_CHALLENGE,
+       AUTH_RMT_STATE_RECV_RSP,
+       AUTH_RMT_STATE_DONE,
+       AUTH_RMT_STATE_ERROR
+};
+
+struct auth_buffer_desc {
+       unsigned int length;
+       void *address;
+};
+
+struct auth_key {
+       unsigned int present:1;
+       unsigned int processed:1;
+       unsigned int value_set:1;
+       char *string;
+};
+
+struct auth_large_binary_key {
+       unsigned int length;
+       unsigned char *large_binary;
+};
+
+struct auth_key_block {
+       unsigned int transit_bit:1;
+       unsigned int dup_set:1;
+       unsigned int str_too_long:1;
+       unsigned int too_much_data:1;
+       unsigned int blk_length:16;
+       char *str_block;
+       struct auth_key key[AUTH_KEY_TYPE_MAX_COUNT];
+};
+
+struct auth_str_block {
+       char str_block[AUTH_STR_BLOCK_MAX_LEN];
+};
+
+struct auth_large_binary {
+       unsigned char large_binary[AUTH_LARGE_BINARY_MAX_LEN];
+};
+
+struct iscsi_acl {
+       unsigned long signature;
+
+       enum auth_node_type node_type;
+       unsigned int auth_method_count;
+       int auth_method_list[AUTH_METHOD_MAX_COUNT];
+       enum auth_neg_role auth_method_neg_role;
+       unsigned int chap_alg_count;
+       int chap_alg_list[AUTH_CHAP_ALG_MAX_COUNT];
+       int auth_rmt;
+       char username[AUTH_STR_MAX_LEN];
+       int passwd_present;
+       unsigned int passwd_length;
+       unsigned char passwd_data[AUTH_STR_MAX_LEN];
+       unsigned int chap_challenge_len;
+       int ip_sec;
+
+       unsigned int auth_method_valid_count;
+       int auth_method_valid_list[AUTH_METHOD_MAX_COUNT];
+       int auth_method_valid_neg_role;
+
+       int recv_in_progress_flag;
+       int recv_end_count;
+       struct iscsi_session *session_handle;   /*
+                                                * session_handle can only be
+                                                * used by acl_chap_auth_request
+                                                */
+       enum auth_phase phase;
+       enum auth_local_state local_state;
+       enum auth_rmt_state rmt_state;
+       enum auth_status rmt_auth_status;
+       enum auth_dbg_status dbg_status;
+       int negotiated_auth_method;
+       int negotiated_chap_alg;
+       int auth_rsp_flag;
+       int auth_server_error_flag;
+       int transit_bit_sent_flag;
+
+       unsigned int send_chap_identifier;
+       struct auth_large_binary_key send_chap_challenge;
+       char chap_username[AUTH_STR_MAX_LEN];
+
+       int recv_chap_challenge_status;
+       struct auth_large_binary_key recv_chap_challenge;
+
+       char scratch_key_value[AUTH_STR_MAX_LEN];
+
+       struct auth_key_block recv_key_block;
+       struct auth_key_block send_key_block;
+};
+
+extern int acl_init(int node_type, int buf_desc_count,
+                   struct auth_buffer_desc *buff_desc);
+extern int acl_finish(struct iscsi_acl *client);
+
+extern int acl_recv_begin(struct iscsi_acl *client);
+extern int acl_recv_end(struct iscsi_acl *client,
+                       struct iscsi_session *session_handle);
+extern const char *acl_get_key_name(int key_type);
+extern int acl_get_next_key_type(int *key_type);
+extern int acl_recv_key_value(struct iscsi_acl *client, int key_type,
+                             const char *user_key_val);
+extern int acl_send_key_val(struct iscsi_acl *client, int key_type,
+                           int *key_present, char *user_key_val,
+                           unsigned int max_length);
+extern int acl_recv_transit_bit(struct iscsi_acl *client, int value);
+extern int acl_send_transit_bit(struct iscsi_acl *client, int *value);
+extern int acl_set_user_name(struct iscsi_acl *client, const char *username);
+extern int acl_set_passwd(struct iscsi_acl *client,
+                         const unsigned char *pw_data, unsigned int pw_len);
+extern int acl_set_chap_alg_list(struct iscsi_acl *client, unsigned int option_count,
+                     const int *option_list);
+extern int acl_init_chap_digests(int *value_list, unsigned int *chap_algs, int count);
+extern int acl_set_auth_rmt(struct iscsi_acl *client, int auth_rmt);
+extern int acl_set_ip_sec(struct iscsi_acl *client, int ip_sec);
+extern int acl_get_dbg_status(struct iscsi_acl *client, int *value);
+extern const char *acl_dbg_status_to_text(int dbg_status);
+extern enum auth_dbg_status acl_chap_compute_rsp(struct iscsi_acl *client,
+                                                int rmt_auth,
+                                                unsigned int id,
+                                                unsigned char *challenge_data,
+                                                unsigned int challenge_len,
+                                                unsigned char *response_data);
+extern int acl_chap_auth_request(struct iscsi_acl *client, char *username,
+                                unsigned int id,
+                                unsigned char *challenge_data,
+                                unsigned int challenge_length,
+                                unsigned char *response_data,
+                                unsigned int rsp_length);
+extern int acl_data(unsigned char *out_data, unsigned int *out_length,
+                   unsigned char *in_data, unsigned int in_length);
+#endif                         /* #ifndef ISCSIAUTHCLIENT_H */
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/be2iscsi.c b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/be2iscsi.c
new file mode 100644 (file)
index 0000000..8a346a5
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * be2iscsi helpers
+ *
+ * Copyright (C) 2006 Mike Christie
+ * Copyright (C) 2006 Red Hat, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+#include "initiator.h"
+
+void be2iscsi_create_conn(struct iscsi_conn *conn)
+{
+       struct iscsi_session *session = conn->session;
+
+       if (conn->max_recv_dlength > 65536)
+               conn->max_recv_dlength = 65536;
+
+       if (session->first_burst > 8192)
+               session->first_burst = 8192;
+
+       if (session->max_burst > 262144)
+               session->max_burst = 262144;
+
+       if (conn->max_xmit_dlength > 65536)
+               conn->max_xmit_dlength = 65536;
+
+       session->erl = 0;
+       session->initial_r2t_en = 1;
+}
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/be2iscsi.h b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/be2iscsi.h
new file mode 100644 (file)
index 0000000..9e5c727
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef BE2ISCSI_TRANSPORT
+#define BE2ISCSI_TRANSPORT
+
+struct iscsi_conn;
+
+extern void be2iscsi_create_conn(struct iscsi_conn *conn);
+
+#endif
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/config.h b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/config.h
new file mode 100644 (file)
index 0000000..79059ec
--- /dev/null
@@ -0,0 +1,329 @@
+/*
+ * iSCSI Configuration
+ *
+ * Copyright (C) 2002 Cisco Systems, Inc.
+ * maintained by linux-iscsi-devel@lists.sourceforge.net
+ *
+ * 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 CONFIG_H
+#define CONFIG_H
+
+#include <netdb.h>
+#include <net/if.h>
+
+#include "types.h"
+#include "auth.h"      /* for the username and password sizes */
+#include "list.h"
+#include "iscsi_proto.h"
+#include "iscsi_net_util.h"
+
+/* ISIDs now have a typed naming authority in them.  We use an OUI */
+#define DRIVER_ISID_0  0x00
+#define DRIVER_ISID_1  0x02
+#define DRIVER_ISID_2  0x3D
+
+/* number of possible connections per session */
+#define ISCSI_CONN_MAX         1
+/* max len of interface */
+#define ISCSI_MAX_IFACE_LEN    65
+
+/* the following structures store the options set in the config file.
+ * a structure is defined for each logically-related group of options.
+ * if you are adding a new option, first check if it should belong
+ * to one of the existing groups.  If it does, add it.  If not, define
+ * a new structure.
+ */
+
+/* all authentication-related options should be added to this structure.
+ * this structure is per-session, and can be configured
+ * by TargetName but not Subnet.
+ */
+struct iscsi_auth_config {
+       unsigned int authmethod;
+       char username[AUTH_STR_MAX_LEN];
+       unsigned char password[AUTH_STR_MAX_LEN];
+       unsigned int password_length;
+       char username_in[AUTH_STR_MAX_LEN];
+       unsigned char password_in[AUTH_STR_MAX_LEN];
+       unsigned int password_in_length;
+       unsigned int chap_algs[AUTH_CHAP_ALG_MAX_COUNT];
+};
+
+/* all per-connection timeouts go in this structure.
+ * this structure is per-portal, and can be configured
+ * both by TargetName and Subnet.
+ */
+struct iscsi_connection_timeout_config {
+       int login_timeout;
+       int logout_timeout;
+       int auth_timeout;
+       int active_timeout;
+       int noop_out_interval;
+       int noop_out_timeout;
+};
+
+/* all per-session timeouts go in this structure.
+ * this structure is per-session, and can be configured
+ * by TargetName but not by Subnet.
+ */
+struct iscsi_session_timeout_config {
+       int replacement_timeout;
+};
+
+/* all error handling timeouts go in this structure.
+ * this structure is per-portal, and can be configured
+ * both by TargetName and Subnet.
+ */
+struct iscsi_error_timeout_config {
+       int abort_timeout;
+       int host_reset_timeout;
+       int lu_reset_timeout;
+       int tgt_reset_timeout;
+};
+
+/* all TCP options go in this structure.
+ * this structure is per-portal, and can be configured
+ * both by TargetName and Subnet.
+ */
+struct iscsi_tcp_config {
+       int window_size;
+       int type_of_service;    /* try to set IP TOS bits */
+};
+
+struct iscsi_conn_operational_config {
+       int MaxRecvDataSegmentLength;
+       int MaxXmitDataSegmentLength;
+       int HeaderDigest;
+       int DataDigest;
+       int IFMarker;
+       int OFMarker;
+};
+
+/* all iSCSI operational params go in this structure.
+ * this structure is per-portal, and can be configured
+ * both by TargetName and Subnet.
+ */
+struct iscsi_session_operational_config {
+       int DataPDUInOrder;
+       int DataSequenceInOrder;
+       int protocol;
+       int InitialR2T;
+       int ImmediateData;
+       int FirstBurstLength;
+       int MaxBurstLength;
+       int DefaultTime2Wait;
+       int DefaultTime2Retain;
+       int MaxConnections;
+       int MaxOutstandingR2T;
+       int ERL;
+       int FastAbort;
+};
+
+#define CONFIG_DIGEST_NEVER  0
+#define CONFIG_DIGEST_ALWAYS 1
+#define CONFIG_DIGEST_PREFER_ON 2
+#define CONFIG_DIGEST_PREFER_OFF 3
+
+struct iscsi_sendtargets_config {
+       int reopen_max;
+       int use_discoveryd;
+       int discoveryd_poll_inval;
+       struct iscsi_auth_config auth;
+       struct iscsi_connection_timeout_config conn_timeo;
+       struct iscsi_conn_operational_config conn_conf;
+       struct iscsi_session_operational_config session_conf;
+};
+
+struct iscsi_isns_config {
+       int use_discoveryd;
+       int discoveryd_poll_inval;
+};
+
+struct iscsi_slp_config {
+       char *scopes;
+       char *interfaces;       /* for multicast, list of interfaces names,
+                                * "all", or "none" */
+       int poll_interval;
+       struct iscsi_auth_config auth;
+};
+
+typedef enum iscsi_startup {
+       ISCSI_STARTUP_MANUAL,
+       ISCSI_STARTUP_AUTOMATIC,
+       ISCSI_STARTUP_ONBOOT,
+} iscsi_startup_e;
+
+typedef enum discovery_type {
+       DISCOVERY_TYPE_SENDTARGETS,
+       DISCOVERY_TYPE_ISNS,
+       DISCOVERY_TYPE_OFFLOAD_SENDTARGETS,
+       DISCOVERY_TYPE_SLP,
+       DISCOVERY_TYPE_STATIC,
+       DISCOVERY_TYPE_FW,
+} discovery_type_e;
+
+typedef struct conn_rec {
+       iscsi_startup_e                         startup;
+       char                                    address[NI_MAXHOST];
+       int                                     port;
+       struct iscsi_tcp_config                 tcp;
+       struct iscsi_connection_timeout_config  timeo;
+       struct iscsi_conn_operational_config    iscsi;
+} conn_rec_t;
+
+typedef struct session_rec {
+       int                                     initial_cmdsn;
+       int                                     reopen_max;
+       int                                     xmit_thread_priority;
+       int                                     cmds_max;
+       int                                     queue_depth;
+       int                                     initial_login_retry_max;
+       int                                     nr_sessions;
+       int                                     scan;
+       struct iscsi_auth_config                auth;
+       struct iscsi_session_timeout_config     timeo;
+       struct iscsi_error_timeout_config       err_timeo;
+       struct iscsi_session_operational_config iscsi;
+       struct session_info                     *info;
+       unsigned                                sid;
+       /*
+        * This is a flag passed to iscsid.  If set, multiple sessions are
+        * 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
+#define ISCSI_MAX_STR_LEN 80
+
+typedef struct iface_rec {
+       struct list_head        list;
+       /* iscsi iface record name */
+       char                    name[ISCSI_MAX_IFACE_LEN];
+       uint32_t                iface_num;
+       /* network layer iface name (eth0) */
+       char                    netdev[IFNAMSIZ];
+       char                    ipaddress[NI_MAXHOST];
+       char                    subnet_mask[NI_MAXHOST];
+       char                    gateway[NI_MAXHOST];
+       char                    bootproto[ISCSI_MAX_STR_LEN];
+       char                    ipv6_linklocal[NI_MAXHOST];
+       char                    ipv6_router[NI_MAXHOST];
+       char                    ipv6_autocfg[NI_MAXHOST];
+       char                    linklocal_autocfg[NI_MAXHOST];
+       char                    router_autocfg[NI_MAXHOST];
+       uint8_t                 prefix_len;
+       uint16_t                vlan_id;
+       uint8_t                 vlan_priority;
+       char                    vlan_state[ISCSI_MAX_STR_LEN];
+       char                    state[ISCSI_MAX_STR_LEN]; /* 0 = disable,
+                                                          * 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 infiniband
+        */
+       char                    hwaddress[ISCSI_HWADDRESS_BUF_SIZE];
+       char                    transport_name[ISCSI_TRANSPORT_NAME_MAXLEN];
+       /*
+        * This is only used for boot now, but the iser guys
+        * can use this for their virtualization idea.
+        */
+       char                    alias[TARGET_NAME_MAXLEN + 1];
+       char                    iname[TARGET_NAME_MAXLEN + 1];
+} iface_rec_t;
+
+typedef struct node_rec {
+       struct list_head        list;
+       char                    name[TARGET_NAME_MAXLEN];
+       int                     tpgt;
+       iscsi_startup_e         startup;
+       int                     leading_login;
+       session_rec_t           session;
+       conn_rec_t              conn[ISCSI_CONN_MAX];
+       iface_rec_t             iface;
+       discovery_type_e        disc_type;
+       char                    disc_address[NI_MAXHOST];
+       int                     disc_port;
+} node_rec_t;
+
+typedef struct discovery_rec {
+       iscsi_startup_e         startup;
+       discovery_type_e        type;
+       char                    address[NI_MAXHOST];
+       int                     port;
+       int                     iscsid_req_tmo;
+       union {
+               struct iscsi_sendtargets_config sendtargets;
+               struct iscsi_slp_config         slp;
+               struct iscsi_isns_config        isns;
+       } u;
+} discovery_rec_t;
+
+#endif /* CONFIG_H */
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/cxgbi.c b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/cxgbi.c
new file mode 100644 (file)
index 0000000..4f3d1db
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * cxgb3i/cxgb4i helpers
+ *
+ * Copyright (C) 2006 Mike Christie
+ * Copyright (C) 2006 Red Hat, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+#include "initiator.h"
+
+void cxgbi_create_conn(struct iscsi_conn *conn)
+{
+       /* card can handle up to 15360 bytes */
+       if (conn->max_recv_dlength > 8192)
+               conn->max_recv_dlength = 8192;
+}
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/cxgbi.h b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/cxgbi.h
new file mode 100644 (file)
index 0000000..bd46603
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef CXGBI_TRANSPORT
+#define CXGBI_TRANSPORT
+
+struct iscsi_conn;
+
+extern void cxgbi_create_conn(struct iscsi_conn *conn);
+
+#endif
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/discovery.c b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/discovery.c
new file mode 100644 (file)
index 0000000..587af6d
--- /dev/null
@@ -0,0 +1,1790 @@
+/*
+ * iSCSI Discovery
+ *
+ * Copyright (C) 2002 Cisco Systems, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * See the file COPYING included with this distribution for more details.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <errno.h>
+#include <netdb.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <poll.h>
+#include <sys/time.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "local_strings.h"
+#include "types.h"
+#include "iscsi_proto.h"
+#include "initiator.h"
+#include "log.h"
+#include "idbm.h"
+#include "iscsi_settings.h"
+#include "sysdeps.h"
+#include "fw_context.h"
+#include "iscsid_req.h"
+#include "iscsi_util.h"
+#include "transport.h"
+#include "iscsi_sysfs.h"
+#include "iscsi_ipc.h"
+#include "iface.h"
+#include "iscsi_timer.h"
+#include "iscsi_err.h"
+/* libisns includes */
+#include <libisns/isns.h>
+#include <libisns/paths.h>
+#include <libisns/message.h>
+
+#ifdef SLP_ENABLE
+#include "iscsi-slp-discovery.h"
+#endif
+
+#define DISCOVERY_NEED_RECONNECT 0xdead0001
+
+static char initiator_name[TARGET_NAME_MAXLEN + 1];
+static char initiator_alias[TARGET_NAME_MAXLEN + 1];
+static struct iscsi_ev_context ipc_ev_context;
+
+static int request_initiator_name(int tmo)
+{
+       int rc;
+       iscsiadm_req_t req;
+       iscsiadm_rsp_t rsp;
+
+       memset(initiator_name, 0, sizeof(initiator_name));
+       initiator_name[0] = '\0';
+       memset(initiator_alias, 0, sizeof(initiator_alias));
+       initiator_alias[0] = '\0';
+
+       memset(&req, 0, sizeof(req));
+       req.command = MGMT_IPC_CONFIG_INAME;
+
+       rc = iscsid_exec_req(&req, &rsp, 1, tmo);
+       if (rc)
+               return rc;
+
+       if (rsp.u.config.var[0] != '\0')
+               strcpy(initiator_name, rsp.u.config.var);
+
+       memset(&req, 0, sizeof(req));
+       req.command = MGMT_IPC_CONFIG_IALIAS;
+
+       rc = iscsid_exec_req(&req, &rsp, 0, tmo);
+       if (rc)
+               /* alias is optional so return ok */
+               return 0;
+
+       if (rsp.u.config.var[0] != '\0')
+               strcpy(initiator_alias, rsp.u.config.var);
+       return 0;
+}
+
+void discovery_isns_free_servername(void)
+{
+       if (isns_config.ic_server_name)
+               free(isns_config.ic_server_name);
+       isns_config.ic_server_name = NULL;
+}
+
+int discovery_isns_set_servername(char *address, int port)
+{
+       char *server;
+       int len;
+
+       if (port > USHRT_MAX) {
+               log_error("Invalid port %d", port);
+               return ISCSI_ERR_INVAL;
+       }
+
+       /* 5 for port and 1 for colon and 1 for null */
+       len = strlen(address) + 7;
+       server = calloc(1, len);
+       if (!server)
+               return ISCSI_ERR_NOMEM;
+
+       snprintf(server, len, "%s:%d", address, port);
+       isns_assign_string(&isns_config.ic_server_name, server);
+       free(server);
+       return 0;
+}
+
+int discovery_isns_query(struct discovery_rec *drec, const char *iname,
+                        const char *targetname, struct list_head *rec_list)
+{
+       isns_attr_list_t key_attrs = ISNS_ATTR_LIST_INIT;
+       isns_object_list_t objects = ISNS_OBJECT_LIST_INIT;
+       isns_source_t *source;
+       isns_simple_t *qry;
+       isns_client_t *clnt;
+       uint32_t status;
+       int rc;
+
+       isns_config.ic_security = 0;
+       source = isns_source_create_iscsi(iname);
+       if (!source)
+               return ISCSI_ERR_NOMEM;
+
+       clnt = isns_create_client(NULL, iname); 
+       if (!clnt) {
+               rc = ISCSI_ERR_NOMEM;
+               goto free_src;
+       }
+
+       /* do not retry forever */
+       isns_socket_set_disconnect_fatal(clnt->ic_socket);
+
+       if (targetname)
+               isns_attr_list_append_string(&key_attrs, ISNS_TAG_ISCSI_NAME,
+                                            targetname);
+       else
+               /* Query for all visible targets */
+               isns_attr_list_append_uint32(&key_attrs,
+                                            ISNS_TAG_ISCSI_NODE_TYPE,
+                                            ISNS_ISCSI_TARGET_MASK);
+
+       qry = isns_create_query2(clnt, &key_attrs, source);
+       if (!qry) {
+               rc = ISCSI_ERR_NOMEM;
+               goto free_clnt;
+       }
+
+       isns_query_request_attr_tag(qry, ISNS_TAG_ISCSI_NAME);
+       isns_query_request_attr_tag(qry, ISNS_TAG_ISCSI_NODE_TYPE);
+       isns_query_request_attr_tag(qry, ISNS_TAG_PORTAL_IP_ADDRESS);
+       isns_query_request_attr_tag(qry, ISNS_TAG_PORTAL_TCP_UDP_PORT);
+       isns_query_request_attr_tag(qry, ISNS_TAG_PG_ISCSI_NAME);
+       isns_query_request_attr_tag(qry, ISNS_TAG_PG_PORTAL_IP_ADDR);
+       isns_query_request_attr_tag(qry, ISNS_TAG_PG_PORTAL_TCP_UDP_PORT);
+       isns_query_request_attr_tag(qry, ISNS_TAG_PG_TAG);
+
+       status = isns_client_call(clnt, &qry);
+       switch (status) {
+       case ISNS_SUCCESS:
+               break;
+       case ISNS_SOURCE_UNKNOWN:
+               /* server requires that we are registered but we are not */
+               rc = ISCSI_ERR_ISNS_REG_FAILED;
+               goto free_query;
+       default:
+               log_error("iSNS discovery failed: %s", isns_strerror(status));
+               rc = ISCSI_ERR_ISNS_QUERY;
+               goto free_query;
+       }
+
+       status = isns_query_response_get_objects(qry, &objects);
+       if (status) {
+               log_error("Unable to extract object list from query "
+                         "response: %s", isns_strerror(status));
+               rc = ISCSI_ERR;
+               goto free_query;
+       }
+
+       for (unsigned int i = 0; i < objects.iol_count; ++i) {
+               isns_object_t *obj = objects.iol_data[i];
+               const char *pg_tgt = NULL;
+               struct in6_addr in_addr;
+               uint32_t pg_port = ISCSI_LISTEN_PORT;
+               uint32_t pg_tag = PORTAL_GROUP_TAG_UNKNOWN;
+               char pg_addr[INET6_ADDRSTRLEN + 1];
+               struct node_rec *rec;
+
+               if (!isns_object_is_pg(obj))
+                       continue;
+
+               if (!isns_object_get_string(obj, ISNS_TAG_PG_ISCSI_NAME,
+                                           &pg_tgt)) {
+                       log_debug(1, "Missing target name");
+                       continue;
+               }
+
+               if (!isns_object_get_ipaddr(obj, ISNS_TAG_PG_PORTAL_IP_ADDR,
+                                           &in_addr)) {
+                       log_debug(1, "Missing addr");
+                       continue;
+               }
+               if (IN6_IS_ADDR_V4MAPPED(&in_addr) ||
+                   IN6_IS_ADDR_V4COMPAT(&in_addr)) {
+                       struct in_addr ipv4;
+
+                       ipv4.s_addr = in_addr.s6_addr32[3];
+                       inet_ntop(AF_INET, &ipv4, pg_addr, sizeof(pg_addr));
+               } else
+                       inet_ntop(AF_INET6, &in_addr, pg_addr, sizeof(pg_addr));
+
+               if (!isns_object_get_uint32(obj,
+                                           ISNS_TAG_PG_PORTAL_TCP_UDP_PORT,
+                                           &pg_port)) {
+                       log_debug(1, "Missing port");
+                       continue;
+               }
+
+               if (!isns_object_get_uint32(obj, ISNS_TAG_PG_TAG, &pg_tag)) {
+                       log_debug(1, "Missing tag");
+                       continue;
+               }
+
+               rec = calloc(1, sizeof(*rec));
+               if (!rec) {
+                       rc = ISCSI_ERR_NOMEM;
+                       goto destroy_list;
+               }
+
+               idbm_node_setup_from_conf(rec);
+               if (drec) {
+                       rec->disc_type = drec->type;
+                       rec->disc_port = drec->port;
+                       strcpy(rec->disc_address, drec->address);
+               }
+
+               strlcpy(rec->name, pg_tgt, TARGET_NAME_MAXLEN);
+               rec->tpgt = pg_tag;
+               rec->conn[0].port = pg_port;
+               strlcpy(rec->conn[0].address, pg_addr, NI_MAXHOST);
+               list_add_tail(&rec->list, rec_list);
+       }
+       rc = 0;
+
+       isns_flush_events();
+destroy_list:
+       isns_object_list_destroy(&objects);
+free_query:
+       isns_simple_free(qry);
+free_clnt:
+       isns_client_destroy(clnt);
+free_src:
+       isns_source_release(source);
+       return rc;
+}
+
+/*
+ * discovery_isns_reg_node - register/deregister node
+ * @iname: initiator name
+ * @reg: bool indicating if we are supposed to register or deregister node.
+ *
+ * We do a very simple registration just so we can query.
+ */
+static int discovery_isns_reg_node(const char *iname, int op_reg)
+{
+       isns_simple_t *reg;
+       isns_client_t *clnt;
+       isns_source_t *source;
+       int rc = 0, status;
+
+       isns_config.ic_security = 0;
+
+       log_debug(1, "trying to %s %s with iSNS server.",
+                 op_reg ? "register" : "deregister", iname);
+
+       source = isns_source_create_iscsi(iname);
+       if (!source)
+               return ISCSI_ERR_NOMEM;
+
+       clnt = isns_create_client(NULL, iname); 
+       if (!clnt) {
+               rc = ISCSI_ERR_NOMEM;
+               goto free_src;
+       }
+
+       reg = isns_simple_create(op_reg ? ISNS_DEVICE_ATTRIBUTE_REGISTER :
+                                ISNS_DEVICE_DEREGISTER,
+                                source, NULL);
+       if (!reg) {
+               rc = ISCSI_ERR_NOMEM;
+               goto free_clnt;
+       }
+
+       isns_attr_list_append_string(&reg->is_operating_attrs,
+                                    ISNS_TAG_ISCSI_NAME, iname);
+       if (op_reg)
+               isns_attr_list_append_uint32(&reg->is_operating_attrs,
+                                            ISNS_TAG_ISCSI_NODE_TYPE,
+                                            ISNS_ISCSI_INITIATOR_MASK);
+       status = isns_client_call(clnt, &reg);
+       if (status != ISNS_SUCCESS) {
+               log_error("Could not %s %s with iSNS server: %s.",
+                         reg ? "register" : "deregister", iname,
+                         isns_strerror(status));
+               rc = ISCSI_ERR_ISNS_REG_FAILED;
+       } else
+               log_debug(1, "%s %s with iSNS server successful.",
+                         op_reg ? "register" : "deregister", iname);
+free_clnt:
+       isns_client_destroy(clnt);
+free_src:
+       isns_source_release(source);
+       return rc;
+}
+
+int discovery_isns(void *data, struct iface_rec *iface,
+                  struct list_head *rec_list)
+{
+       struct discovery_rec *drec = data;
+       char *iname;
+       int rc, registered = 0;
+
+       if (iface && strlen(iface->iname))
+               iname = iface->iname;
+       else {
+               rc = request_initiator_name(drec->iscsid_req_tmo);
+               if (rc) {
+                       log_error("Cannot perform discovery. Initiatorname "
+                                 "required.");
+                       return rc;
+               } else if (initiator_name[0] == '\0') {
+                       log_error("Cannot perform discovery. Invalid "
+                                 "Initiatorname.");
+                       return ISCSI_ERR_INVAL;
+               }
+
+               iname = initiator_name;
+       }
+
+       rc = discovery_isns_set_servername(drec->address, drec->port);
+       if (rc)
+               return rc;
+retry:
+       rc = discovery_isns_query(drec, iname, NULL, rec_list);
+       if (!registered && rc == ISCSI_ERR_ISNS_REG_FAILED) {
+               rc = discovery_isns_reg_node(iname, 1);
+               if (!rc) {
+                       registered = 1;
+                       goto retry;
+               }
+       }
+
+       if (registered)
+               discovery_isns_reg_node(iname, 0);
+
+       discovery_isns_free_servername();
+       return rc;
+}
+
+int discovery_fw(void *data,
+                __attribute__((unused))struct iface_rec *iface,
+                struct list_head *rec_list)
+{
+       struct discovery_rec *drec = data;
+       struct boot_context *bcontext;
+       struct list_head targets;
+       struct node_rec *rec;
+       int rc;
+
+       INIT_LIST_HEAD(&targets);
+       rc = fw_get_targets(&targets);
+       if (rc) {
+               log_error("Could not get list of targets from firmware. "
+                         "(err %d)", rc);
+               return rc;
+       }
+       if (list_empty(&targets))
+               return 0;
+       /*
+        * TODO: Do we want to match the iface MAC/netdev with what is in
+        * the firmware or could the user want to bind based on what is
+        * in passed in or in the default ifaces?
+        */
+
+       list_for_each_entry(bcontext, &targets, list) {
+               rec = idbm_create_rec_from_boot_context(bcontext);
+               if (!rec) {
+                       log_error("Could not convert firmware info to "
+                                 "node record.");
+                       rc = ISCSI_ERR_NOMEM;
+                       goto free_targets;
+               }
+               rec->disc_type = drec->type;
+
+               list_add_tail(&rec->list, rec_list);
+       }
+
+free_targets:
+       fw_free_targets(&targets);
+       return rc;
+}
+
+int discovery_offload_sendtargets(int host_no, int do_login,
+                                 discovery_rec_t *drec)
+{
+       struct sockaddr_storage ss;
+       char default_port[NI_MAXSERV];
+       iscsiadm_req_t req;
+       iscsiadm_rsp_t rsp;
+       int rc;
+
+       log_debug(4, "offload st though host %d to %s", host_no,
+                 drec->address);
+
+       memset(&req, 0, sizeof(req));
+       req.command = MGMT_IPC_SEND_TARGETS;
+       req.u.st.host_no = host_no;
+       req.u.st.do_login = do_login;
+
+       /* resolve the DiscoveryAddress to an IP address */
+       sprintf(default_port, "%d", drec->port);
+       rc = resolve_address(drec->address, default_port, &ss);
+       if (rc)
+               return rc;
+
+       req.u.st.ss = ss;
+
+       /*
+        * We only know how ask qla4xxx to do discovery and login
+        * to what it finds. We are not able to get what it finds or
+        * is able to log into so we just send the command and proceed.
+        *
+        * There is a way to just use the hw to send a sendtargets command
+        * and get back the results. We should do this since it would
+        * allows us to then process the results like software iscsi.
+        */
+       rc = iscsid_exec_req(&req, &rsp, 1, drec->iscsid_req_tmo);
+       if (rc) {
+               log_error("Could not offload sendtargets to %s.",
+                         drec->address);
+               iscsi_err_print_msg(rc);
+               return rc;
+       }
+
+       return 0;
+}
+
+static int
+iscsi_make_text_pdu(iscsi_session_t *session,
+                   struct iscsi_hdr *hdr,
+                   __attribute__((unused))char *data,
+                   __attribute__((unused))int max_data_length)
+{
+       struct iscsi_text *text_pdu = (struct iscsi_text *)hdr;
+
+       /* initialize the PDU header */
+       memset(text_pdu, 0, sizeof (*text_pdu));
+
+       text_pdu->opcode = ISCSI_OP_TEXT;
+       text_pdu->itt = htonl(session->itt);
+       text_pdu->ttt = ISCSI_RESERVED_TAG;
+       text_pdu->cmdsn = htonl(session->cmdsn++);
+       text_pdu->exp_statsn = htonl(session->conn[0].exp_statsn);
+
+       return 1;
+}
+
+static int
+request_targets(iscsi_session_t *session)
+{
+       char data[64];
+       struct iscsi_text text;
+       struct iscsi_hdr *hdr = (struct iscsi_hdr *) &text;
+
+       memset(&text, 0, sizeof (text));
+       memset(data, 0, sizeof (data));
+
+       /* make a text PDU with SendTargets=All */
+       if (!iscsi_make_text_pdu(session, hdr, data, sizeof (data))) {
+               log_error("failed to make a SendTargets PDU");
+               return 0;
+       }
+
+       if (!iscsi_add_text(hdr, data, sizeof (data), "SendTargets", "All")) {
+               log_error("failed to add SendTargets text key");
+               return 0;
+       }
+
+       text.ttt = ISCSI_RESERVED_TAG;
+       text.flags = ISCSI_FLAG_CMD_FINAL;
+
+       if (!iscsi_io_send_pdu(&session->conn[0], hdr, ISCSI_DIGEST_NONE, data,
+                   ISCSI_DIGEST_NONE, session->conn[0].active_timeout)) {
+               log_error("failed to send SendTargets PDU");
+               return 0;
+       }
+
+       return 1;
+}
+
+static int
+iterate_targets(iscsi_session_t *session, uint32_t ttt)
+{
+       char data[64];
+       struct iscsi_text text;
+       struct iscsi_hdr *pdu = (struct iscsi_hdr *) &text;
+
+       memset(&text, 0, sizeof (text));
+       memset(data, 0, sizeof (data));
+
+       /* make an empty text PDU */
+       if (!iscsi_make_text_pdu(session, pdu, data, sizeof (data))) {
+               log_error("failed to make an empty text PDU");
+               return 0;
+       }
+
+       text.ttt = ttt;
+       text.flags = ISCSI_FLAG_CMD_FINAL;
+
+       if (!iscsi_io_send_pdu(&session->conn[0], pdu, ISCSI_DIGEST_NONE, data,
+                   ISCSI_DIGEST_NONE, session->conn[0].active_timeout)) {
+               log_error("failed to send empty text PDU");
+               return 0;
+       }
+
+       return 1;
+}
+
+static int add_portal(struct list_head *rec_list, discovery_rec_t *drec,
+                     char *targetname, char *address, char *port, char *tag)
+{
+       struct sockaddr_storage ss;
+       struct node_rec *rec;
+
+       if (resolve_address(address, port, &ss)) {
+               log_error("cannot resolve %s", address);
+               return 0;
+       }
+
+       rec = calloc(1, sizeof(*rec));
+       if (!rec)
+               return 0;
+
+       idbm_node_setup_from_conf(rec);
+       rec->disc_type = drec->type;
+       rec->disc_port = drec->port;
+       strcpy(rec->disc_address, drec->address);
+
+       strlcpy(rec->name, targetname, TARGET_NAME_MAXLEN);
+       if (tag && *tag)
+               rec->tpgt = atoi(tag);
+       else
+               rec->tpgt = PORTAL_GROUP_TAG_UNKNOWN;
+       if (port && *port)
+               rec->conn[0].port = atoi(port);
+       else
+               rec->conn[0].port = ISCSI_LISTEN_PORT;
+       strlcpy(rec->conn[0].address, address, NI_MAXHOST);
+
+       list_add_tail(&rec->list, rec_list);
+       return 1;
+}
+
+static int
+add_target_record(char *name, char *end, discovery_rec_t *drec,
+                 struct list_head *rec_list)
+{
+       char *text = NULL;
+       char *nul = name;
+       size_t length;
+
+       /* address = IPv4
+        * address = [IPv6]
+        * address = DNSname
+        * address = IPv4:port
+        * address = [IPv6]:port
+        * address = DNSname:port
+        * address = IPv4,tag
+        * address = [IPv6],tag
+        * address = DNSname,tag
+        * address = IPv4:port,tag
+        * address = [IPv6]:port,tag
+        * address = DNSname:port,tag
+        */
+
+       log_debug(7, "adding target record %p, end %p", name, end);
+
+       /* find the end of the name */
+       while ((nul < end) && (*nul != '\0'))
+               nul++;
+
+       length = nul - name;
+       if (length > TARGET_NAME_MAXLEN) {
+               log_error("TargetName %s too long, ignoring", name);
+               return 0;
+       }
+       text = name + length;
+
+       /* skip NULs after the name */
+       while ((text < end) && (*text == '\0'))
+               text++;
+
+       /* if no address is provided, use the default */
+       if (text >= end) {
+               if (drec->address[0] == '\0') {
+                       log_error("no default address known for target %s",
+                                 name);
+                       return 0;
+               } else {
+                       char default_port[NI_MAXSERV];
+
+                       sprintf(default_port, "%d", drec->port);
+                       if (!add_portal(rec_list, drec, name, drec->address,
+                                       default_port, NULL)) {
+                               log_error("failed to add default portal, "
+                                         "ignoring target %s", name);
+                               return 0;
+                       }
+               }
+               /* finished adding the default */
+               return 1;
+       }
+
+       /* process TargetAddresses */
+       while (text < end) {
+               char *next = text + strlen(text) + 1;
+
+               log_debug(7, "text %p, next %p, end %p, %s", text, next, end,
+                        text);
+
+               if (strncmp(text, "TargetAddress=", 14) == 0) {
+                       char *port = NULL;
+                       char *tag = NULL;
+                       char *address = text + 14;
+                       char *temp;
+
+                       if ((tag = strrchr(text, ','))) {
+                               *tag = '\0';
+                               tag++;
+                       }
+                       if ((port = strrchr(text, ':'))) {
+                               *port = '\0';
+                               port++;
+                       }
+
+                       if (*address == '[') {
+                               address++;
+                               if ((temp = strrchr(text, ']')))
+                                       *temp = '\0';
+                       }
+
+                       if (!add_portal(rec_list, drec, name, address, port,
+                                       tag)) {
+                               log_error("failed to add default portal, "
+                                        "ignoring target %s", name);
+                               return 0;
+                       }
+               } else
+                       log_error("unexpected SendTargets data: %s",
+                              text);
+               text = next;
+       }
+
+       return 1;
+}
+
+static int
+process_sendtargets_response(struct str_buffer *sendtargets,
+                            int final, discovery_rec_t *drec,
+                            struct list_head *rec_list)
+{
+       char *start = str_buffer_data(sendtargets);
+       char *text = start;
+       char *end = text + str_data_length(sendtargets);
+       char *nul = end - 1;
+       char *record = NULL;
+       int num_targets = 0;
+
+       if (start == end) {
+               /* no SendTargets data */
+               goto done;
+       }
+
+       /* scan backwards to find the last NUL in the data, to ensure we
+        * don't walk off the end.  Since key=value pairs can span PDU
+        * boundaries, we're not guaranteed that the end of the data has a
+        * NUL.
+        */
+       while ((nul > start) && *nul)
+               nul--;
+
+       if (nul == start) {
+               /* couldn't find anything we can process now,
+                * it's one big partial string
+                */
+               goto done;
+       }
+
+       /* find the boundaries between target records (TargetName or final PDU)
+        */
+       for (;;) {
+               /* skip NULs */
+               while ((text < nul) && (*text == '\0'))
+                       text++;
+
+               if (text == nul)
+                       break;
+
+               log_debug(7,
+                        "processing sendtargets record %p, text %p, line %s",
+                        record, text, text);
+
+               /* look for the start of a new target record */
+               if (strncmp(text, "TargetName=", 11) == 0) {
+                       if (record) {
+                               /* send the last record, which we just found
+                                * the end of. don't bother passing the
+                                * "TargetName=" prefix.
+                                */
+                               if (!add_target_record(record + 11, text,
+                                                       drec, rec_list)) {
+                                       log_error(
+                                              "failed to add target record");
+                                       str_truncate_buffer(sendtargets, 0);
+                                       goto done;
+                               }
+                               num_targets++;
+                       }
+                       record = text;
+               }
+
+               /* everything up til the next NUL must be part of the
+                * current target record
+                */
+               while ((text < nul) && (*text != '\0'))
+                       text++;
+       }
+
+       if (record) {
+               if (final) {
+                       /* if this is the last PDU of the text sequence,
+                        * it also ends a target record
+                        */
+                       log_debug(7,
+                                "processing final sendtargets record %p, "
+                                "line %s",
+                                record, record);
+                       if (add_target_record (record + 11, text,
+                                              drec, rec_list)) {
+                               num_targets++;
+                               record = NULL;
+                               str_truncate_buffer(sendtargets, 0);
+                       } else {
+                               log_error("failed to add target record");
+                               str_truncate_buffer(sendtargets, 0);
+                               goto done;
+                       }
+               } else {
+                       /* remove the parts of the sendtargets buffer we've
+                        * processed, and move the parts we haven't to the
+                        * beginning of the buffer.
+                        */
+                       log_debug(7,
+                                "processed %d bytes of sendtargets data, "
+                                "%d remaining",
+                                (int)(record - str_buffer_data(sendtargets)),
+                                (int)(str_buffer_data(sendtargets) +
+                                str_data_length(sendtargets) - record));
+                       str_remove_initial(sendtargets,
+                                          record - str_buffer_data(sendtargets));
+               }
+       }
+
+      done:
+
+       return 1;
+}
+
+static void iscsi_free_session(struct iscsi_session *session)
+{
+       list_del_init(&session->list);
+       free(session);
+}
+
+static iscsi_session_t *
+iscsi_alloc_session(struct iscsi_sendtargets_config *config,
+                   struct iface_rec *iface, int *rc, int tmo)
+{
+       iscsi_session_t *session;
+
+       *rc = 0;
+
+       session = calloc(1, sizeof (*session));
+       if (session == NULL) {
+               *rc = ISCSI_ERR_NOMEM;
+               return NULL;
+       }
+
+       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.", iface->transport_name);
+               *rc = ISCSI_ERR_TRANS_NOT_FOUND;
+               goto fail;
+       }
+
+       INIT_LIST_HEAD(&session->list);
+       /* initialize the session's leading connection */
+       session->conn[0].id = 0;
+       session->conn[0].socket_fd = -1;
+       session->conn[0].session = session;
+       session->conn[0].login_timeout = config->conn_timeo.login_timeout;
+       session->conn[0].auth_timeout = config->conn_timeo.auth_timeout;
+       session->conn[0].active_timeout = config->conn_timeo.active_timeout;
+       session->conn[0].noop_out_timeout = 0;
+       session->conn[0].noop_out_interval = 0;
+       session->reopen_cnt = config->reopen_max + 1;
+       iscsi_copy_operational_params(&session->conn[0], &config->session_conf,
+                                     &config->conn_conf);
+
+       /* OUI and uniqifying number */
+       session->isid[0] = DRIVER_ISID_0;
+       session->isid[1] = DRIVER_ISID_1;
+       session->isid[2] = DRIVER_ISID_2;
+       session->isid[3] = 0;
+       session->isid[4] = 0;
+       session->isid[5] = 0;
+
+       if (strlen(iface->iname)) {
+               strcpy(initiator_name, iface->iname);
+               /* MNC TODO add iface alias */
+       } else {
+               *rc = request_initiator_name(tmo);
+               if (*rc) {
+                       log_error("Cannot perform discovery. Initiatorname "
+                                 "required.");
+                       goto fail;
+               } else if (initiator_name[0] == '\0') {
+                       log_error("Cannot perform discovery. Invalid "
+                                 "Initiatorname.");
+                       *rc = ISCSI_ERR_INVAL;
+                       goto fail;
+               }
+       }
+
+       iface_copy(&session->nrec.iface, iface);
+       session->initiator_name = initiator_name;
+       session->initiator_alias = initiator_alias;
+       session->portal_group_tag = PORTAL_GROUP_TAG_UNKNOWN;
+       session->type = ISCSI_SESSION_TYPE_DISCOVERY;
+       session->id = INVALID_SESSION_ID;
+
+       /* setup authentication variables for the session*/
+       *rc = iscsi_setup_authentication(session, &config->auth);
+       if (*rc)
+               goto fail;
+
+       list_add_tail(&session->list, &session->t->sessions);
+       return session;
+
+fail:
+       free(session);
+       return NULL;
+}
+
+static int
+process_recvd_pdu(struct iscsi_hdr *pdu,
+                 discovery_rec_t *drec,
+                 struct list_head *rec_list,
+                 iscsi_session_t *session,
+                 struct str_buffer *sendtargets,
+                 int *active,
+                 int *valid_text,
+                 char *data)
+{
+       int rc=0;
+
+       switch (pdu->opcode) {
+               case ISCSI_OP_TEXT_RSP:{
+                       struct iscsi_text_rsp *text_response =
+                               (struct iscsi_text_rsp *) pdu;
+                       int dlength = ntoh24(pdu->dlength);
+                       int final =
+                               (text_response->flags & ISCSI_FLAG_CMD_FINAL) ||
+                               (text_response-> ttt == ISCSI_RESERVED_TAG);
+                       size_t curr_data_length;
+
+                       log_debug(4, "discovery session to %s:%d received text"
+                                " response, %d data bytes, ttt 0x%x, "
+                                "final 0x%x",
+                                drec->address,
+                                drec->port,
+                                dlength,
+                                ntohl(text_response->ttt),
+                                text_response->flags & ISCSI_FLAG_CMD_FINAL);
+
+                       /* mark how much more data in the sendtargets
+                        * buffer is now valid
+                        */
+                       curr_data_length = str_data_length(sendtargets);
+                       if (str_enlarge_data(sendtargets, dlength)) {
+                               log_error("Could not allocate memory to "
+                                         "process SendTargets response.");
+                               rc = 0;
+                               goto done;
+                       }
+
+                       memcpy(str_buffer_data(sendtargets) + curr_data_length,
+                              data, dlength);
+
+                       *valid_text = 1;
+                       /* process as much as we can right now */
+                       process_sendtargets_response(sendtargets,
+                                                    final,
+                                                    drec,
+                                                    rec_list);
+
+                       if (final) {
+                               /* SendTargets exchange is now complete
+                                */
+                               *active = 0;
+                               /* from now on, after any reconnect,
+                                * assume LUNs may have changed
+                                */
+                       } else {
+                               /* ask for more targets */
+                               if (!iterate_targets(session,
+                                                    text_response->ttt)) {
+                                       rc = DISCOVERY_NEED_RECONNECT;
+                                       goto done;
+                               }
+                       }
+                       break;
+               }
+               default:
+                       log_warning(
+                              "discovery session to %s:%d received "
+                              "unexpected opcode 0x%x",
+                              drec->address, drec->port, pdu->opcode);
+                       rc = DISCOVERY_NEED_RECONNECT;
+                       goto done;
+       }
+ done:
+       return(rc);
+}
+
+#if 0 /* Unused */
+/*
+ * Make a best effort to logout the session.
+ */
+static void iscsi_logout(iscsi_session_t * session)
+{
+       struct iscsi_logout logout_req;
+       struct iscsi_logout_rsp logout_resp;
+       int rc;
+
+       /*
+        * Build logout request header
+        */
+       memset(&logout_req, 0, sizeof (logout_req));
+       logout_req.opcode = ISCSI_OP_LOGOUT | ISCSI_OP_IMMEDIATE;
+       logout_req.flags = ISCSI_FLAG_CMD_FINAL |
+               (ISCSI_LOGOUT_REASON_CLOSE_SESSION &
+                               ISCSI_FLAG_LOGOUT_REASON_MASK);
+       logout_req.itt = htonl(session->itt);
+       if (++session->itt == ISCSI_RESERVED_TAG)
+               session->itt = 1;
+       logout_req.cmdsn = htonl(session->cmdsn);
+       logout_req.exp_statsn = htonl(++session->conn[0].exp_statsn);
+
+       /*
+        * Send the logout request
+        */
+       rc = iscsi_io_send_pdu(&session->conn[0],(struct iscsi_hdr *)&logout_req,
+                           ISCSI_DIGEST_NONE, NULL, ISCSI_DIGEST_NONE, 3);
+       if (!rc) {
+               log_error(
+                      "iscsid: iscsi_logout - failed to send logout PDU.");
+               return;
+       }
+
+       /*
+        * Read the logout response
+        */
+       memset(&logout_resp, 0, sizeof(logout_resp));
+       rc = iscsi_io_recv_pdu(&session->conn[0],
+               (struct iscsi_hdr *)&logout_resp, ISCSI_DIGEST_NONE, NULL,
+               0, ISCSI_DIGEST_NONE, 1);
+       if (rc < 0) {
+               log_error("iscsid: logout - failed to receive logout resp");
+               return;
+       }
+       if (logout_resp.response != ISCSI_LOGOUT_SUCCESS) {
+               log_error("iscsid: logout failed - response = 0x%x",
+                      logout_resp.response);
+       }
+}
+#endif /* Unused */
+
+static void iscsi_destroy_session(struct iscsi_session *session)
+{
+       struct iscsi_transport *t = session->t;
+       struct iscsi_conn *conn = &session->conn[0];
+       int rc;
+
+       if (session->id == INVALID_SESSION_ID)
+               return;
+
+       if (!(t->caps & CAP_TEXT_NEGO)) {
+               iscsi_io_disconnect(&session->conn[0]);
+               goto done;
+       }
+
+       log_debug(2, "%s ep disconnect", __FUNCTION__);
+       t->template->ep_disconnect(conn);
+
+       log_debug(2, "stop conn");
+       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)",
+                         session->id, conn->id, rc);
+               goto done;
+        }
+
+       log_debug(2, "%s destroy conn", __FUNCTION__);
+        rc = ipc->destroy_conn(session->t->handle, session->id, conn->id);
+       if (rc) {
+               log_error("Could not safely destroy conn %d:%d (err %d)",
+                         session->id, conn->id, rc);
+               goto done;
+       }
+
+       log_debug(2, "%s destroy session", __FUNCTION__);
+       rc = ipc->destroy_session(session->t->handle, session->id);
+       if (rc)
+               log_error("Could not safely destroy session %d (err %d)",
+                         session->id, rc);
+done:
+       if (session->target_alias) {
+           free(session->target_alias);
+           session->target_alias = NULL;
+       }
+
+       if (conn->socket_fd >= 0) {
+               ipc->ctldev_close();
+               conn->socket_fd = -1;
+       }
+       session->id = INVALID_SESSION_ID;
+}
+
+static int iscsi_create_leading_conn(struct iscsi_session *session)
+{
+       struct iface_rec *iface = &session->nrec.iface;
+       struct iscsi_transport *t = session->t;
+       struct iscsi_conn *conn = &session->conn[0];
+       uint32_t host_no;
+       int rc, sleep_count = 0;
+
+       if (!(t->caps & CAP_TEXT_NEGO)) {
+               /*
+                * If the LLD does not support TEXT PDUs then we do
+                * discovery in userspace.
+                */
+               session->use_ipc = 0;
+
+               if (!iscsi_io_connect(conn))
+                       return ISCSI_ERR_TRANS;
+
+               session->id = 1;
+               return 0;
+       }
+       session->use_ipc = 1;
+
+       /*
+        * for software this is the tcp socket fd set in iscsi_io_connect
+        * and for offload this is the iscsi netlink socket fd
+        */
+       conn->socket_fd = ipc->ctldev_open();
+       if (conn->socket_fd < 0) {
+               log_error("Could not open netlink interface (err %d)",
+                         errno);
+               return ISCSI_ERR_INTERNAL;
+       }
+
+       host_no = iscsi_sysfs_get_host_no_from_hwinfo(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 = host_no;
+       }
+
+       rc = iscsi_host_set_net_params(iface, session);
+       if (rc) {
+               log_error("Could not set host net params (err %d)",
+                         rc);
+               if (rc != ISCSI_ERR_AGAIN)
+                       rc = ISCSI_ERR_INTERNAL;
+               goto close_ipc;
+       }
+
+       /* create interconnect endpoint */
+       log_debug(2, "%s discovery ep connect", __FUNCTION__);
+       rc = t->template->ep_connect(conn, 1);
+       if (rc < 0) {
+               rc = ISCSI_ERR_TRANS;
+               goto close_ipc;
+       }
+
+       do {
+               rc = t->template->ep_poll(conn, 1);
+               if (rc < 0) {
+                       rc = ISCSI_ERR_TRANS;
+                       goto disconnect;
+               } else if (rc == 0) {
+                       if (sleep_count == conn->login_timeout) {
+                               rc = ISCSI_ERR_TRANS_TIMEOUT;
+                               goto disconnect;
+                       }
+                       sleep_count++;
+                       sleep(1);
+               } else
+                       break;
+       } while (1);
+
+       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).", rc);
+               rc = ISCSI_ERR_INTERNAL;
+               goto disconnect;
+       }
+       log_debug(2, "%s discovery created session %u", __FUNCTION__,
+                 session->id);
+       session->isid[3] = (session->id >> 16) & 0xff;
+       session->isid[4] = (session->id >>  8) & 0xff;
+       session->isid[5] = session->id & 0xff;
+
+       log_debug(2, "%s discovery create conn", __FUNCTION__);
+       rc = ipc->create_conn(t->handle, session->id, conn->id, &conn->id);
+       if (rc) {
+               log_error("Could not create connection (err %d)", rc);
+               rc = ISCSI_ERR_INTERNAL;
+               goto disconnect;
+       }
+
+       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) {
+               log_error("Could not bind conn %d:%d to session %d, "
+                         "(err %d)", session->id, conn->id,
+                         session->id, rc);
+               rc = ISCSI_ERR_INTERNAL;
+               goto disconnect;
+       }
+
+       /* all set */
+       return 0;
+
+disconnect:
+       t->template->ep_disconnect(conn);
+
+       if (session->id != INVALID_SESSION_ID &&
+           iscsi_sysfs_session_has_leadconn(session->id)) {
+               if (ipc->destroy_conn(session->t->handle, session->id,
+                                      conn->id))
+                       log_error("Could not safely destroy connection %d:%d",
+                                 session->id, conn->id);
+       }
+
+       if (session->id != INVALID_SESSION_ID) {
+               if (ipc->destroy_session(session->t->handle, session->id))
+                       log_error("Could not safely destroy session %d",
+                                 session->id);
+               session->id = INVALID_SESSION_ID;
+       }
+
+close_ipc:
+       if (conn->socket_fd >= 0) {
+               ipc->ctldev_close();
+               conn->socket_fd = -1;
+       }
+
+       log_error("Connection to discovery portal %s failed: %s",
+                 conn->host, iscsi_err_to_str(rc));
+       return rc;
+}
+
+static struct iscsi_ev_context *
+iscsi_ev_context_get(__attribute__((unused))struct iscsi_conn *conn,
+                    int 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)
+               return NULL;
+
+       return &ipc_ev_context;
+}
+
+static void iscsi_ev_context_put(struct iscsi_ev_context *ev_context)
+{
+       if (ev_context->data)
+               free(ev_context->data);
+       ev_context->data = NULL;
+}
+
+static int iscsi_sched_ev_context(struct iscsi_ev_context *ev_context,
+                                 struct iscsi_conn *conn,
+                                 __attribute__((unused))unsigned long tmo,
+                                 int event)
+{
+       if (event == EV_CONN_RECV_PDU || event == EV_CONN_LOGIN) {
+               conn->recv_context = ev_context;
+               return 0;
+       }
+
+       return -EIO;
+}
+
+static struct iscsi_ipc_ev_clbk ipc_clbk = {
+        .get_ev_context         = iscsi_ev_context_get,
+        .put_ev_context         = iscsi_ev_context_put,
+        .sched_ev_context       = iscsi_sched_ev_context,
+};
+
+static int iscsi_wait_for_login(struct iscsi_conn *conn)
+{
+       struct iscsi_session *session = conn->session;
+       struct iscsi_transport *t = session->t;
+       struct pollfd pfd;
+       struct timeval connection_timer;
+       int timeout, rc;
+       uint32_t conn_state;
+       int status = 0;
+
+       if (!(t->caps & CAP_LOGIN_OFFLOAD))
+               return 0;
+
+       iscsi_timer_set(&connection_timer, conn->active_timeout);
+
+       /* prepare to poll */
+       memset(&pfd, 0, sizeof(pfd));
+       pfd.fd = conn->socket_fd;
+       pfd.events = POLLIN | POLLPRI;
+
+       timeout = iscsi_timer_msecs_until(&connection_timer);
+
+login_repoll:
+       log_debug(4, "discovery login process polling fd %d, "
+                "timeout in %f seconds", pfd.fd, timeout / 1000.0);
+
+       pfd.revents = 0;
+       rc = poll(&pfd, 1, timeout);
+
+       log_debug(7, "discovery login process returned from poll, rc %d", rc);
+
+       if (iscsi_timer_expired(&connection_timer)) {
+               log_warning("Discovery login session timed out.");
+               rc = ISCSI_ERR_INTERNAL;
+               goto done;
+       }
+
+       if (rc > 0) {
+               if (pfd.revents & (POLLIN | POLLPRI)) {
+                       timeout = iscsi_timer_msecs_until(&connection_timer);
+                       status = ipc->recv_conn_state(conn, &conn_state);
+                       if (status == -EAGAIN)
+                               goto login_repoll;
+                       else if (status < 0) {
+                               rc = ISCSI_ERR_TRANS;
+                               goto done;
+                       }
+
+                       if (conn_state != ISCSI_CONN_STATE_LOGGED_IN)
+                               rc = ISCSI_ERR_TRANS;
+                       else
+                               rc = 0;
+                       goto done;
+               }
+
+               if (pfd.revents & POLLHUP) {
+                       log_warning("discovery session"
+                                   "terminating after hangup");
+                        rc = ISCSI_ERR_TRANS;
+                        goto done;
+               }
+
+               if (pfd.revents & POLLNVAL) {
+                       log_warning("discovery POLLNVAL");
+                       rc = ISCSI_ERR_INTERNAL;
+                       goto done;
+               }
+
+               if (pfd.revents & POLLERR) {
+                       log_warning("discovery POLLERR");
+                       rc = ISCSI_ERR_INTERNAL;
+                       goto done;
+               }
+       } else if (rc < 0) {
+               log_error("Login poll error");
+               rc = ISCSI_ERR_INTERNAL;
+               goto done;
+       }
+
+done:
+       return rc;
+}
+
+static int iscsi_create_session(struct iscsi_session *session,
+                               struct iscsi_sendtargets_config *config,
+                               char *data, unsigned int data_len)
+{
+       struct iscsi_conn *conn = &session->conn[0];
+       int login_status, rc = 0, login_delay = 0;
+       uint8_t status_class = 0, status_detail = 0;
+       unsigned int login_failures = 0;
+       char serv[NI_MAXSERV];
+       struct iscsi_transport *t = session->t;
+
+set_address:
+       /*
+        * copy the saved address to the session,
+        * undoing any temporary redirect
+        */
+       conn->saddr = conn->failback_saddr;
+
+reconnect:
+       /* fix decrement and test */
+       if (--session->reopen_cnt < 0) {
+               log_error("connection login retries (reopen_max) %d exceeded",
+                         config->reopen_max);
+               rc = ISCSI_ERR_PDU_TIMEOUT;
+               goto login_failed;
+       }
+
+redirect_reconnect:
+       session->cmdsn = 1;
+       session->itt = 1;
+       session->portal_group_tag = PORTAL_GROUP_TAG_UNKNOWN;
+
+       /*
+        * On reconnect, just destroy the kernel structs and start over.
+        */
+       iscsi_destroy_session(session);
+
+       /* slowly back off the frequency of login attempts */
+       if (login_failures == 0)
+               login_delay = 0;
+       else if (login_failures < 10)
+               login_delay = 1;        /* 10 seconds at 1 sec each */
+       else if (login_failures < 20)
+               login_delay = 2;        /* 20 seconds at 2 sec each */
+       else if (login_failures < 26)
+               login_delay = 5;        /* 30 seconds at 5 sec each */
+       else if (login_failures < 34)
+               login_delay = 15;       /* 60 seconds at 15 sec each */
+       else
+               login_delay = 60;       /* after 2 minutes, try once a minute */
+
+       getnameinfo((struct sockaddr *) &conn->saddr,
+                   sizeof(conn->saddr), conn->host,
+                   sizeof(conn->host), serv, sizeof(serv),
+                   NI_NUMERICHOST|NI_NUMERICSERV);
+
+       if (login_delay) {
+               log_debug(4, "discovery session to %s:%s sleeping for %d "
+                        "seconds before next login attempt",
+                        conn->host, serv, login_delay);
+               sleep(login_delay);
+       }
+       rc = iscsi_create_leading_conn(session);
+       if (rc) {
+               login_failures++;
+               goto reconnect;
+       }
+
+       log_debug(1, "connected to discovery address %s", conn->host);
+
+       log_debug(4, "discovery session to %s:%s starting iSCSI login",
+                conn->host, serv);
+
+       /*
+        * Need to re-init settings because a previous login could
+        * have set them to what was negotiated for.
+        */
+       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;
+
+       status_class = 0;
+       status_detail = 0;
+       rc = ISCSI_ERR_LOGIN;
+
+       memset(data, 0, data_len);
+       login_status = iscsi_login(session, 0, data, data_len,
+                                  &status_class, &status_detail);
+
+       switch (login_status) {
+       case LOGIN_OK:
+       case LOGIN_REDIRECT:
+               break;
+
+       case LOGIN_IO_ERROR:
+       case LOGIN_REDIRECTION_FAILED:
+               /* try again */
+               log_warning("retrying discovery login to %s", conn->host);
+               login_failures++;
+               goto set_address;
+
+       default:
+       case LOGIN_FAILED:
+       case LOGIN_NEGOTIATION_FAILED:
+       case LOGIN_AUTHENTICATION_FAILED:
+       case LOGIN_VERSION_MISMATCH:
+       case LOGIN_INVALID_PDU:
+               log_error("discovery login to %s failed, giving up %d",
+                         conn->host, login_status);
+               rc = ISCSI_ERR_FATAL_LOGIN;
+               goto login_failed;
+       }
+
+       /* check the login status */
+       switch (status_class) {
+       case ISCSI_STATUS_CLS_SUCCESS:
+               log_debug(4, "discovery login success to %s", conn->host);
+               login_failures = 0;
+               break;
+       case ISCSI_STATUS_CLS_REDIRECT:
+               switch (status_detail) {
+                       /* the session IP address was changed by the login
+                        * library, so just try again with this portal
+                        * config but the new address.
+                        */
+               case ISCSI_LOGIN_STATUS_TGT_MOVED_TEMP:
+                       log_warning(
+                               "discovery login temporarily redirected to "
+                               "%s port %s", conn->host, serv);
+                       goto redirect_reconnect;
+               case ISCSI_LOGIN_STATUS_TGT_MOVED_PERM:
+                       log_warning(
+                               "discovery login permanently redirected to "
+                               "%s port %s", conn->host, serv);
+                       /* make the new address permanent */
+                       memset(&conn->failback_saddr, 0,
+                               sizeof(struct sockaddr_storage));
+                       conn->failback_saddr = conn->saddr;
+                       goto redirect_reconnect;
+               default:
+                       log_error(
+                              "discovery login rejected: redirection type "
+                              "0x%x not supported",
+                              status_detail);
+                       goto set_address;
+               }
+               break;
+       case ISCSI_STATUS_CLS_INITIATOR_ERR:
+               switch (status_detail) {
+               case ISCSI_LOGIN_STATUS_AUTH_FAILED:
+               case ISCSI_LOGIN_STATUS_TGT_FORBIDDEN:
+                       log_error("discovery login to %s rejected: "
+                                 "initiator failed authorization",
+                                conn->host);
+                       rc = ISCSI_ERR_LOGIN_AUTH_FAILED;
+                       goto login_failed;
+               default:
+                       log_error("discovery login to %s rejected: initiator "
+                                 "error (%02x/%02x), non-retryable, giving up",
+                                 conn->host, status_class, status_detail);
+                       rc = ISCSI_ERR_FATAL_LOGIN;
+               }
+               goto login_failed;
+       case ISCSI_STATUS_CLS_TARGET_ERR:
+               log_error(
+                       "discovery login to %s rejected: "
+                       "target error (%02x/%02x)",
+                       conn->host, status_class, status_detail);
+               login_failures++;
+               goto reconnect;
+       default:
+               log_error(
+                       "discovery login to %s failed, response "
+                       "with unknown status class 0x%x, detail 0x%x",
+                       conn->host,
+                       status_class, status_detail);
+               login_failures++;
+               goto reconnect;
+       }
+
+       if (!(t->caps & CAP_TEXT_NEGO))
+               return 0;
+
+start_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)", session->id, conn->id, rc);
+               rc = ISCSI_ERR_INTERNAL;
+               goto login_failed;
+       }
+
+       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);
+               rc = ISCSI_ERR_INTERNAL;
+               goto login_failed;
+       }
+
+       rc = iscsi_wait_for_login(conn);
+       if (!rc)
+               return 0;
+
+login_failed:
+       iscsi_destroy_session(session);
+       return rc;
+}
+
+int discovery_sendtargets(void *fndata, struct iface_rec *iface,
+                         struct list_head *rec_list)
+{
+       discovery_rec_t *drec = fndata;
+       iscsi_session_t *session;
+       struct pollfd pfd;
+       struct iscsi_hdr pdu_buffer;
+       struct iscsi_hdr *pdu = &pdu_buffer;
+       char *data = NULL;
+       int active = 0, valid_text = 0;
+       struct timeval connection_timer;
+       int timeout;
+       int rc = 0;
+       struct str_buffer sendtargets;
+       unsigned int data_len;
+       struct iscsi_sendtargets_config *config = &drec->u.sendtargets;
+
+       /* initial setup */
+       log_debug(1, "starting sendtargets discovery, address %s:%d, ",
+                drec->address, drec->port);
+       memset(&pdu_buffer, 0, sizeof (pdu_buffer));
+       iscsi_timer_clear(&connection_timer);
+
+       /* allocate a new session, and initialize default values */
+       session = iscsi_alloc_session(config, iface, &rc, drec->iscsid_req_tmo);
+       if (rc)
+               return rc;
+
+       ipc_ev_context.conn = &session->conn[0];
+       ipc_register_ev_callback(&ipc_clbk);
+
+       log_debug(4, "sendtargets discovery to %s:%d using "
+                "isid 0x%02x%02x%02x%02x%02x%02x",
+                drec->address, drec->port, session->isid[0],
+                session->isid[1], session->isid[2], session->isid[3],
+                session->isid[4], session->isid[5]);
+
+       /* allocate data buffers for SendTargets data */
+       data = malloc(session->conn[0].max_recv_dlength);
+       if (!data) {
+               rc = ISCSI_ERR_NOMEM;
+               goto free_session;
+       }
+       data_len = session->conn[0].max_recv_dlength;
+
+       str_init_buffer(&sendtargets, 0);
+
+       /* resolve the DiscoveryAddress to an IP address */
+       rc = iscsi_setup_portal(&session->conn[0], drec->address,
+                               drec->port);
+       if (rc) {
+               log_error("cannot resolve host name %s", drec->address);
+               goto free_sendtargets;
+       }
+
+       log_debug(4, "discovery timeouts: login %d, reopen_cnt %d, auth %d.",
+                session->conn[0].login_timeout, session->reopen_cnt,
+                session->conn[0].auth_timeout);
+
+reconnect:
+       rc = iscsi_create_session(session, &drec->u.sendtargets,
+                                 data, data_len);
+       if (rc)
+               goto free_sendtargets;
+
+       /* reinitialize */
+       str_truncate_buffer(&sendtargets, 0);
+
+       /* ask for targets */
+       if (!request_targets(session)) {
+               goto reconnect;
+       }
+       active = 1;
+
+       /* set timeouts */
+       iscsi_timer_set(&connection_timer, session->conn[0].active_timeout);
+
+       /* prepare to poll */
+       memset(&pfd, 0, sizeof (pfd));
+       pfd.fd = session->conn[0].socket_fd;
+       pfd.events = POLLIN | POLLPRI;
+
+repoll:
+       timeout = iscsi_timer_msecs_until(&connection_timer);
+       /* block until we receive a PDU, a TCP FIN, a TCP RST,
+        * or a timeout
+        */
+       log_debug(4,
+                "discovery process  %s:%d polling fd %d, "
+                "timeout in %f seconds",
+                drec->address, drec->port, pfd.fd,
+                timeout / 1000.0);
+
+       pfd.revents = 0;
+       rc = poll(&pfd, 1, timeout);
+
+       log_debug(7,
+                "discovery process to %s:%d returned from poll, rc %d",
+                drec->address, drec->port, rc);
+
+       if (iscsi_timer_expired(&connection_timer)) {
+               log_warning("Discovery session to %s:%d timed out.",
+                           drec->address, drec->port);
+               rc = ISCSI_ERR_TRANS_TIMEOUT;
+               goto reconnect;
+       }
+
+       if (rc > 0) {
+               if (pfd.revents & (POLLIN | POLLPRI)) {
+                       timeout = iscsi_timer_msecs_until(&connection_timer);
+
+                       rc = iscsi_io_recv_pdu(&session->conn[0],
+                                               pdu, ISCSI_DIGEST_NONE, data,
+                                               data_len, ISCSI_DIGEST_NONE,
+                                               timeout);
+                       if (rc == -EAGAIN)
+                               goto repoll;
+                       else if (rc < 0) {
+                               log_debug(1, "discovery session to "
+                                         "%s:%d failed to recv a PDU "
+                                         "response, terminating",
+                                          drec->address,
+                                          drec->port);
+                               rc = ISCSI_ERR_PDU_TIMEOUT;
+                               goto free_sendtargets;
+                       }
+
+                       /*
+                        * process iSCSI PDU received
+                        */
+                       rc = process_recvd_pdu(pdu, drec, rec_list,
+                                              session, &sendtargets,
+                                              &active, &valid_text, data);
+                       if (rc == (int)DISCOVERY_NEED_RECONNECT)
+                               goto reconnect;
+
+                       /* reset timers after receiving a PDU */
+                       if (active) {
+                               iscsi_timer_set(&connection_timer,
+                                      session->conn[0].active_timeout);
+                               goto repoll;
+                       }
+               }
+
+               if (pfd.revents & POLLHUP) {
+                       log_warning("discovery session to %s:%d "
+                                   "terminating after hangup",
+                                    drec->address, drec->port);
+                       rc = ISCSI_ERR_TRANS;
+                       goto free_sendtargets;
+               }
+
+               if (pfd.revents & POLLNVAL) {
+                       log_warning("discovery POLLNVAL");
+                       sleep(1);
+                       goto reconnect;
+               }
+
+               if (pfd.revents & POLLERR) {
+                       log_warning("discovery POLLERR");
+                       sleep(1);
+                       goto reconnect;
+               }
+       } else if (rc < 0) {
+               log_error("poll error");
+               rc = ISCSI_ERR;
+               goto free_sendtargets;
+       }
+
+       log_debug(1, "discovery process to %s:%d exiting",
+                drec->address, drec->port);
+       rc = 0;
+
+free_sendtargets:
+       str_free_buffer(&sendtargets);
+       free(data);
+       iscsi_destroy_session(session);
+free_session:
+       iscsi_free_session(session);
+       return rc;
+}
+
+#ifdef SLP_ENABLE
+int
+slp_discovery(struct iscsi_slp_config *config)
+{
+       struct sigaction action;
+       char *pl;
+       unsigned short flag = 0;
+
+       memset(&action, 0, sizeof (struct sigaction));
+       action.sa_sigaction = NULL;
+       action.sa_flags = 0;
+       action.sa_handler = SIG_DFL;
+       sigaction(SIGTERM, &action, NULL);
+       sigaction(SIGINT, &action, NULL);
+       sigaction(SIGPIPE, &action, NULL);
+
+       action.sa_handler = sighup_handler;
+       sigaction(SIGHUP, &action, NULL);
+
+       if (iscsi_process_should_exit()) {
+               log_debug(1, "slp discovery process %p exiting", discovery);
+               exit(0);
+       }
+
+       discovery->pid = getpid();
+
+       pl = generate_predicate_list(discovery, &flag);
+
+       while (1) {
+               if (flag == SLP_MULTICAST_ENABLED) {
+                       discovery->flag = SLP_MULTICAST_ENABLED;
+                       slp_multicast_srv_query(discovery, pl, GENERIC_QUERY);
+               }
+
+               if (flag == SLP_UNICAST_ENABLED) {
+                       discovery->flag = SLP_UNICAST_ENABLED;
+                       slp_unicast_srv_query(discovery, pl, GENERIC_QUERY);
+               }
+
+               sleep(config->poll_interval);
+       }
+
+       exit(0);
+}
+
+#endif
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/discovery.h b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/discovery.h
new file mode 100644 (file)
index 0000000..0575e2a
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * iSCSI discovery 
+ *
+ * Copyright (C) 2004 Dmitry Yusupov, Alex Aizman
+ * 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 DISCOVERY_H
+#define DISCOVERY_H
+
+
+/* discovery.c */
+struct discovery_rec;
+struct list_head;
+struct iface_rec;
+struct node_rec;
+struct boot_context;
+
+extern int discovery_isns_query(struct discovery_rec *drec, const char *iname,
+                               const char *targetname,
+                               struct list_head *rec_list);
+extern void discovery_isns_free_servername(void);
+extern int discovery_isns_set_servername(char *address, int port);
+extern int discovery_isns(void *data, struct iface_rec *iface,
+                         struct list_head *rec_list);
+extern int discovery_fw(void *data, struct iface_rec *iface,
+                       struct list_head *rec_list);
+extern int discovery_sendtargets(void *data, struct iface_rec *iface,
+                                struct list_head *rec_list);
+extern int discovery_offload_sendtargets(int host_no, int do_login,
+                                        struct discovery_rec *drec);
+#endif /* DISCOVERY_H */
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/discoveryd.c b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/discoveryd.c
new file mode 100644 (file)
index 0000000..08eb2bb
--- /dev/null
@@ -0,0 +1,1110 @@
+/*
+ * iSCSI Initiator discovery daemon
+ *
+ * Copyright (C) 2010 Mike Christie
+ * Copyright (C) 2010 Red Hat, Inc. All rights reserved.
+
+ * 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 <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include "discovery.h"
+#include "idbm.h"
+#include "list.h"
+#include "iscsi_proto.h"
+#include "sysdeps.h"
+#include "log.h"
+#include "session_mgmt.h"
+#include "iscsi_util.h"
+#include "event_poll.h"
+#include "iface.h"
+#include "session_mgmt.h"
+#include "session_info.h"
+#include "iscsi_err.h"
+#include <libisns/isns-proto.h>
+#include <libisns/isns.h>
+#include <libisns/paths.h>
+#include <libisns/message.h>
+
+#define DISC_DEF_POLL_INVL     30
+
+static LIST_HEAD(iscsi_targets);
+static int stop_discoveryd;
+
+static LIST_HEAD(isns_initiators);
+static LIST_HEAD(isns_refresh_list);
+static char *isns_entity_id = NULL;
+static uint32_t isns_refresh_interval;
+static int isns_register_nodes = 1;
+
+static void isns_reg_refresh_by_eid_qry(void *data);
+
+typedef void (do_disc_and_login_fn)(const char *def_iname,
+                                   struct discovery_rec *drec, int poll_inval);
+
+static int logout_session(void *data, struct list_head *list,
+                         struct session_info *info)
+{
+       struct list_head *rec_list = data;
+       struct node_rec *rec;
+
+       list_for_each_entry(rec, rec_list, list) {
+               if (iscsi_match_session(rec, info))
+                       return iscsi_logout_portal(info, list);
+       }
+       return -1;
+}
+
+static void discoveryd_stop(void)
+{
+       struct node_rec *rec, *tmp_rec;
+       int nr_found = 0;
+
+       if (list_empty(&iscsi_targets))
+               goto done;
+
+       /*
+        * User requested to just login and exit.
+        */
+       if (!stop_discoveryd)
+               goto done;
+
+       iscsi_logout_portals(&iscsi_targets, &nr_found, 1, logout_session);
+       list_for_each_entry_safe(rec, tmp_rec, &iscsi_targets, list) {
+               list_del(&rec->list);
+               free(rec);
+       }
+
+done:
+       exit(0);
+}
+
+static void catch_signal(int signo)
+{
+       log_debug(1, "%d caught signal -%d...", signo, getpid());
+       switch (signo) {
+       case SIGTERM:
+               stop_discoveryd = 1;
+               break;
+       default:
+               break;
+       }
+}
+
+static void setup_signal_handler(void)
+{
+       struct sigaction sa_old;
+       struct sigaction sa_new;
+
+       sa_new.sa_handler = catch_signal;
+       sigemptyset(&sa_new.sa_mask);
+       sa_new.sa_flags = 0;
+       sigaction(SIGTERM, &sa_new, &sa_old );
+}
+
+/*
+ * update_sessions - login/logout sessions
+ * @new_rec_list: new target portals recs bound to ifaces
+ * @targetname: if set we only update sessions for this target
+ * @iname: if set we only update session for that initiator
+ *
+ * This will login/logout of portals. When it returns the recs on
+ * new_rec_list will be freed or put on the iscsi_targets list.
+ *
+ * FIXME: if we are hitting a per problem this may be it. With targets
+ * that do a target per lun this could get ugly.
+ */
+static void update_sessions(struct list_head *new_rec_list,
+                           const char *targetname, const char *iname)
+{
+       struct node_rec *rec, *tmp_rec;
+       struct list_head stale_rec_list;
+       int nr_found;
+
+       INIT_LIST_HEAD(&stale_rec_list);
+       /*
+        * Check if a target portal is no longer being sent.
+        * Note: Due to how we reread ifaces this will also detect
+        * changes in ifaces being access through portals.
+        */
+       list_for_each_entry_safe(rec, tmp_rec, &iscsi_targets, list) {
+               log_debug(7, "Trying to match %s %s to %s %s %s",
+                          targetname, iname, rec->name, rec->conn[0].address,
+                           rec->iface.name);
+               if (targetname && strcmp(rec->name, targetname))
+                       continue;
+
+               if (iname) {
+                       if (strlen(rec->iface.iname) &&
+                           strcmp(rec->iface.iname, iname))
+                               continue;
+                       else if (strcmp(iname, isns_config.ic_source_name))
+                               continue;
+               }
+
+               log_debug(5, "Matched %s %s, checking if in new targets.",
+                         targetname, iname);
+               if (!idbm_find_rec_in_list(new_rec_list, rec->name,
+                                          rec->conn[0].address,
+                                          rec->conn[0].port, &rec->iface)) {
+                       log_debug(5, "Not found. Marking for logout");
+                       list_move_tail(&rec->list, &stale_rec_list);
+               }
+       }
+
+       list_for_each_entry_safe(rec, tmp_rec, new_rec_list, list) {
+               if (!iscsi_check_for_running_session(rec))
+                       iscsi_login_portal_nowait(rec);
+
+               if (!idbm_find_rec_in_list(&iscsi_targets, rec->name,
+                                          rec->conn[0].address,
+                                          rec->conn[0].port, &rec->iface)) {
+                       log_debug(5, "%s %s %s %s not on curr target list. "
+                                "Adding.", rec->name, rec->conn[0].address,
+                                rec->iface.name, rec->iface.iname);
+                       list_move_tail(&rec->list, &iscsi_targets);
+               } else {
+                       list_del(&rec->list);
+                       free(rec);
+               }
+       }
+
+       if (!list_empty(&stale_rec_list)) {
+               iscsi_logout_portals(&stale_rec_list, &nr_found, 0,
+                                    logout_session);
+               list_for_each_entry_safe(rec, tmp_rec, &stale_rec_list, list) {
+                       list_del(&rec->list);
+                       free(rec);
+               }
+       }
+}
+
+static void fork_disc(const char *def_iname, struct discovery_rec *drec,
+                     int poll_inval, do_disc_and_login_fn *do_disc_and_login)
+{
+       pid_t pid;
+
+       pid = fork();
+       if (pid == 0) {
+               setup_signal_handler();
+               do_disc_and_login(def_iname, drec, poll_inval);
+               exit(0);
+       } else if (pid < 0)
+               log_error("Fork failed (err %d - %s). Will not be able "
+                          "to perform discovery to %s.",
+                          errno, strerror(errno), drec->address);
+       else {
+               shutdown_callback(pid);
+               log_debug(1, "iSCSI disc and login helper pid=%d", pid);
+               reap_inc();
+       }
+}
+
+struct isns_node_list {
+       isns_source_t *source;
+       struct list_head list;
+};
+
+/* iSNS */
+static int isns_build_objs(isns_portal_info_t *portal_info,
+                          isns_object_list_t *objs)
+{
+       struct isns_node_list *node;
+       isns_object_t *inode, *entity;
+       unsigned int i, nportals = 1; 
+       int rc = 0;
+
+       log_debug(7, "isns_build_objs");
+
+       /* we currently just use all portals */
+       if (isns_portal_is_wildcard(portal_info)) {
+               static isns_portal_info_t *iflist;
+
+               nportals = isns_get_nr_portals();
+               log_debug(4, "got %d portals", nportals);
+               if (!nportals)
+                       return ISCSI_ERR_NO_OBJS_FOUND;
+
+               iflist = calloc(nportals, sizeof(isns_portal_info_t));
+               if (!iflist) {
+                       log_error("Unable to allocate %d portals.", nportals);
+                       return ISCSI_ERR_NOMEM;
+               }
+
+               nportals = isns_enumerate_portals(iflist, nportals);
+               if (nportals == 0) {
+                       log_error("Unable to enumerate portals - "
+                                 "no usable interfaces found");
+                       free(iflist);
+                       return ISCSI_ERR_NO_OBJS_FOUND;
+               }
+               for (i = 0; i < nportals; ++i) {
+                       iflist[i].addr.sin6_port = portal_info->addr.sin6_port;
+                       iflist[i].proto = portal_info->proto;
+               }
+               portal_info = iflist;
+       }
+
+       if (!isns_entity_id) {
+               isns_entity_id = calloc(1, 256);
+               if (!isns_entity_id)
+                       return ISCSI_ERR_NOMEM;
+
+               rc = getnameinfo((struct sockaddr *) &portal_info->addr,
+                                sizeof(portal_info->addr),
+                                isns_entity_id, 256, NULL, 0, 0);
+               if (rc) {
+                       free(isns_entity_id);
+                       isns_entity_id = NULL;
+
+                       log_error("Could not get hostname for EID.");
+                       return ISCSI_ERR;
+               }
+       }
+
+       entity = isns_create_entity(ISNS_ENTITY_PROTOCOL_ISCSI, isns_entity_id);
+       if (!entity) {
+               log_error("Could not create iSNS entity.");
+               return ISCSI_ERR_NOMEM;
+       }
+       isns_object_list_append(objs, entity);
+
+       for (i = 0; i < nportals; ++i, ++portal_info) { 
+               isns_object_t *portal;
+
+               portal = isns_create_portal(portal_info, entity);
+               if (!portal) {
+                       rc = ISCSI_ERR_NOMEM;
+                       goto fail;
+               }
+               isns_object_list_append(objs, portal);
+
+               if (!isns_object_set_uint32(portal, ISNS_TAG_SCN_PORT,
+                               isns_portal_tcpudp_port(portal_info))) {
+                       rc = ISCSI_ERR_INVAL;
+                       goto fail;
+               }
+       }
+
+       list_for_each_entry(node, &isns_initiators, list) {
+               inode = isns_create_storage_node2(node->source,
+                                                 ISNS_ISCSI_INITIATOR_MASK,
+                                                 NULL);
+               if (!inode) {
+                       rc = ISCSI_ERR_NOMEM;
+                       goto fail;
+               }
+               isns_object_list_append(objs, inode);           
+       }
+
+       return 0;
+fail:
+       isns_object_list_destroy(objs);
+       return rc;
+}
+
+struct isns_qry_data {
+       const char *iname;
+       const char *targetname;
+};
+
+static int isns_query_node(void *data, struct iface_rec *iface,
+                          struct list_head *recs)
+{
+       struct isns_qry_data *qry_data = data;
+       int is_def_iname = 0;
+       const char *iname;
+
+       if (qry_data->iname) {
+               if (!strcmp(qry_data->iname, isns_config.ic_source_name))
+                       is_def_iname = 1;
+
+               if ((!is_def_iname || strlen(iface->iname)) &&
+                   strcmp(iface->iname, qry_data->iname))
+                       return 0;
+
+               iname = qry_data->iname;
+       } else {
+               if (strlen(iface->iname))
+                       iname = iface->iname;
+               else
+                       iname = isns_config.ic_source_name;
+       }
+
+       return discovery_isns_query(NULL, iname, qry_data->targetname, recs);
+}
+
+static int isns_disc_new_portals(const char *targetname, const char *iname)
+{
+       struct list_head ifaces, rec_list;
+       struct iface_rec *iface, *tmp_iface;
+       struct isns_qry_data qry_data;
+       int rc;
+
+       INIT_LIST_HEAD(&rec_list);
+       INIT_LIST_HEAD(&ifaces);
+
+       qry_data.targetname = targetname;
+       qry_data.iname = iname;
+
+       iface_link_ifaces(&ifaces);
+       rc = idbm_bind_ifaces_to_nodes(isns_query_node, &qry_data, &ifaces,
+                                      &rec_list);
+       if (rc) {
+               log_error("Could not perform iSNS DevAttrQuery for node %s.",
+                         targetname);
+               goto free_ifaces;
+       }
+       update_sessions(&rec_list, targetname, iname);
+       rc = 0;
+
+free_ifaces:
+       list_for_each_entry_safe(iface, tmp_iface, &ifaces, list) {
+               list_del(&iface->list);
+               free(iface);
+       }
+
+       return rc;
+}
+
+static void isns_reg_refresh_with_disc(__attribute__((unused))void *data)
+{
+       int retries = 0, rc;
+
+       log_debug(1, "Refresh registration using DevAttrQuery");
+
+       /*
+        * it is ok to block here since we are not expecting SCNs
+        * from the server.
+        */
+       do {
+               /*
+                * Some servers do not support SCNs so we ping
+                * the server by doing discovery.
+                */
+               rc = isns_disc_new_portals(NULL, NULL);
+               if (rc) {
+                       log_debug(4, "Registration refresh using DevAttrQuery "
+                                 "failed (retires %d) err %d", retries, rc);
+                       sleep(1);
+                       retries++;
+                       continue;
+               }
+       } while (rc && retries < 3);
+
+       if (rc)
+               /*
+                * Try to reregister from scratch.
+                */
+                isns_register_nodes = 1;
+}
+
+struct isns_refresh_data {
+       isns_client_t *clnt;
+       isns_simple_t *qry;
+       uint32_t xid;
+       uint32_t interval;
+       time_t start_time;
+       struct list_head list;
+};
+
+static void isns_free_refresh_data(struct isns_refresh_data *refresh_data)
+{
+       list_del(&refresh_data->list);
+       if (refresh_data->qry)
+               isns_simple_free(refresh_data->qry);
+       if (refresh_data->clnt)
+               isns_client_destroy(refresh_data->clnt);
+       free(refresh_data);
+}
+
+static struct isns_refresh_data *isns_find_refresh_data(uint32_t xid)
+{
+       struct isns_refresh_data *refresh_data;
+
+       list_for_each_entry(refresh_data, &isns_refresh_list, list) {
+               if (refresh_data->xid == xid)
+                       return refresh_data;
+       }
+       return NULL;
+}
+
+static void isns_eid_qry_rsp(uint32_t xid, int status, isns_simple_t *rsp)
+{
+       struct isns_refresh_data *refresh_data;
+
+       refresh_data = isns_find_refresh_data(xid);
+       if (!refresh_data) {
+               log_error("EID Query respond could not match xid");
+               return;
+       }
+
+       if (refresh_data->clnt) {
+               isns_client_destroy(refresh_data->clnt);
+               refresh_data->clnt = NULL;
+       }
+
+       if (!rsp || status != ISNS_SUCCESS) {
+               log_debug(1, "Registration refresh using eid qry failed: %s",
+                         isns_strerror(status));
+               
+               isns_add_oneshot_timer(2, isns_reg_refresh_by_eid_qry,
+                                      refresh_data);
+               return;
+       }
+
+       log_debug(1, "eid qry successful");
+       refresh_data->start_time = time(NULL);
+       isns_add_oneshot_timer(isns_refresh_interval,
+                              isns_reg_refresh_by_eid_qry, refresh_data);
+}
+
+static void isns_reg_refresh_by_eid_qry(void *data)
+{
+       struct isns_refresh_data *refresh_data = data;
+       isns_attr_list_t qry_key = ISNS_ATTR_LIST_INIT;
+       isns_simple_t *qry;
+       isns_client_t *clnt;
+       int status, timeout;
+
+       log_debug(1, "Refresh registration using eid qry");
+       if ((time_t)(refresh_data->start_time + refresh_data->interval) <= time(NULL)) {
+               log_error("Could not refresh registration with server "
+                         "before registration period. Starting new "
+                         "registration.");
+               isns_free_refresh_data(refresh_data);
+               isns_register_nodes = 1;
+               return;
+       }
+
+       clnt = isns_create_default_client(NULL);
+       if (!clnt) {
+               log_error("iSNS registration refresh failed. Could not "
+                         "connect to server.");
+               goto rearm;
+       }
+       refresh_data->clnt = clnt;
+       /*
+        * if a operation has failed we will want to adjust timers
+        * and possibly reregister.
+        */
+       isns_socket_set_report_failure(clnt->ic_socket);
+
+       /*
+        * if this is a retry or re-refresh then there will be a qry
+        */
+       qry = refresh_data->qry;
+       if (qry)
+               goto send;
+
+       isns_attr_list_append_string(&qry_key, ISNS_TAG_ENTITY_IDENTIFIER,
+                                    isns_entity_id);
+       qry = isns_create_query(clnt, &qry_key);
+       isns_attr_list_destroy(&qry_key);
+       if (!qry)
+               goto rearm;
+       isns_query_request_attr_tag(qry, ISNS_TAG_ENTITY_PROTOCOL);
+       refresh_data->qry = qry;
+
+send:
+       timeout = (refresh_data->start_time + refresh_data->interval) -
+                                                               time(NULL);
+
+       status = isns_simple_transmit(clnt->ic_socket, qry, NULL,
+                                     timeout, isns_eid_qry_rsp);
+       if (status == ISNS_SUCCESS) {
+               log_debug(7, "sent eid qry with xid %u", qry->is_xid);
+
+               refresh_data->xid = qry->is_xid;
+               return;
+       }
+rearm:
+       if (refresh_data->clnt) {
+               isns_client_destroy(refresh_data->clnt);
+               refresh_data->clnt = NULL;
+       }
+       log_debug(1, "Could not send eid qry to refresh registration.");
+       isns_add_oneshot_timer(2, isns_reg_refresh_by_eid_qry, refresh_data);
+}
+
+static int isns_setup_registration_refresh(isns_simple_t *rsp, int poll_inval)
+{
+       isns_object_list_t objs = ISNS_OBJECT_LIST_INIT;
+       struct isns_refresh_data *refresh_data;
+       int status, rc = 0;
+       uint32_t interval = 0;
+
+       status = isns_query_response_get_objects(rsp, &objs);
+       if (status) {
+               log_error("Unable to extract object list from "
+                           "registration response: %s",
+                           isns_strerror(status));
+               return ISCSI_ERR;
+       }
+
+       for (unsigned int i = 0; i < objs.iol_count; ++i) {
+               isns_object_t *obj = objs.iol_data[i]; 
+
+               if (!isns_object_is_entity(obj))
+                       continue;
+
+               if (isns_object_get_uint32(obj, ISNS_TAG_REGISTRATION_PERIOD,
+                                          &interval))
+                       break;
+       }
+
+       if (!interval)
+               goto free_objs;
+
+       refresh_data = calloc(1, sizeof(*refresh_data));
+       if (!refresh_data) {
+               rc = ISCSI_ERR_NOMEM;
+               goto free_objs;
+       }
+       INIT_LIST_HEAD(&refresh_data->list);
+       list_add_tail(&refresh_data->list, &isns_refresh_list);
+       refresh_data->start_time = time(NULL);
+
+       /*
+        * Several servers do not support SCNs properly, so for the
+        * registration period refresh we do a DevAttrQuery for all targets
+        * if the poll_inval is greater than 0.
+        *
+        * If the target does support SCNs then we just send a query
+        * for our entity's protocol.
+        */
+
+       /* we cut in half to give us time to handle errors */
+       isns_refresh_interval = interval / 2;
+       if (!isns_refresh_interval) {
+               log_warning("iSNS Registration Period only %d seconds.",
+                           interval);
+               isns_refresh_interval = interval;
+       }
+       refresh_data->interval = interval;
+
+       if (poll_inval > 0) {
+               /* user wants to override server and do disc */
+               if ((int)isns_refresh_interval > poll_inval)
+                       isns_refresh_interval = poll_inval;
+               isns_add_timer(isns_refresh_interval,
+                              isns_reg_refresh_with_disc,
+                              refresh_data);
+       } else
+               /*
+                * user wants to use server value so we just ping
+                * with a simple qry
+                */
+               isns_add_oneshot_timer(isns_refresh_interval,
+                                      isns_reg_refresh_by_eid_qry,
+                                      refresh_data);
+       log_debug(5, "Got registration period of %u "
+                 "internval. Using interval of %u",
+                 interval, isns_refresh_interval);
+
+free_objs:
+       isns_flush_events();
+       isns_object_list_destroy(&objs);
+       return rc;
+}
+
+static void isns_cancel_refresh_timers(void)
+{
+       isns_cancel_timer(isns_reg_refresh_with_disc, NULL);
+       isns_cancel_timer(isns_reg_refresh_by_eid_qry, NULL);
+}
+
+static int isns_register_objs(isns_client_t *clnt, isns_object_list_t *objs,
+                             int poll_inval)
+{
+       struct isns_node_list *node;
+       isns_object_t *entity = NULL;
+       isns_simple_t *reg;
+       unsigned int i;
+       int status, rc = 0;
+
+       log_debug(7, "isns_register_objs");
+
+       for (i = 0; i < objs->iol_count; ++i) {
+               if (isns_object_is_entity(objs->iol_data[i])) {
+                       entity = objs->iol_data[i];
+                       break;
+               }
+       }
+
+       reg = isns_create_registration(clnt, entity);
+       if (!reg)
+               return ISCSI_ERR_NOMEM;
+
+       for (i = 0; i < objs->iol_count; ++i)
+               isns_registration_add_object(reg, objs->iol_data[i]);
+       isns_registration_set_replace(reg, 1);
+
+       status = isns_simple_call(clnt->ic_socket, &reg);
+       if (status != ISNS_SUCCESS) {
+               log_error("Could not register with iSNS server: %s",
+                         isns_strerror(status));
+               rc = ISCSI_ERR;
+               goto free_reg;
+       }
+       log_debug(4, "Registered objs");
+
+       if (!poll_inval)
+               goto free_reg;
+
+       rc = isns_setup_registration_refresh(reg, poll_inval);
+       if (rc)
+               goto free_reg;
+
+       list_for_each_entry(node, &isns_initiators, list) {
+               isns_simple_free(reg);
+               reg = isns_create_scn_registration2(clnt,
+                                          ISNS_SCN_OBJECT_UPDATED_MASK |
+                                          ISNS_SCN_OBJECT_ADDED_MASK |
+                                          ISNS_SCN_OBJECT_REMOVED_MASK |
+                                          ISNS_SCN_TARGET_AND_SELF_ONLY_MASK,
+                                          node->source);
+
+               if (!reg) {
+                       isns_cancel_refresh_timers();
+                       rc = ISCSI_ERR_NOMEM;
+                       goto done;
+               }
+
+               status = isns_simple_call(clnt->ic_socket, &reg);
+               if (status != ISNS_SUCCESS) {
+                       log_error("SCN registration for node %s failed: %s",
+                                 isns_source_name(node->source),
+                                 isns_strerror(status));
+                       /*
+                        * if the user was going to poll then ignore error
+                        * since user was probably using polling because SCNs
+                        * were not supported by server 
+                        */
+                       if (poll_inval < 0) {
+                               isns_cancel_refresh_timers();
+                               rc = ISCSI_ERR;
+                               break;
+                       }
+               }
+               log_debug(4, "Registered %s for SCNs",
+                         isns_source_name(node->source));
+       }
+
+free_reg:
+       isns_simple_free(reg);
+done:
+       return rc;
+}
+
+static int isns_scn_register(isns_socket_t *svr_sock, int poll_inval)
+{
+       isns_object_list_t objs = ISNS_OBJECT_LIST_INIT;
+       isns_portal_info_t portal_info;
+       isns_client_t *clnt;
+       int rc;
+
+       clnt = isns_create_default_client(NULL);
+       if (!clnt) {
+               log_error("iSNS setup failed. Could not connect to server.");
+               return ISCSI_ERR_TRANS;
+       }
+       isns_socket_set_disconnect_fatal(clnt->ic_socket);
+
+       log_debug(7, "isns_scn_register");
+
+       if (!isns_socket_get_portal_info(svr_sock, &portal_info)) {
+               log_error("Could not get portal info for iSNS registration.");
+               rc = ISCSI_ERR_NO_OBJS_FOUND;
+               goto destroy_clnt;
+       }
+
+       rc = isns_build_objs(&portal_info, &objs);
+       if (rc)
+               goto destroy_clnt;
+
+       rc = isns_register_objs(clnt, &objs, poll_inval);
+       isns_object_list_destroy(&objs);
+       if (!rc)
+               log_warning("iSNS: Registered network entity with EID %s with "
+                            "server.",  isns_entity_id);
+
+destroy_clnt:
+       isns_client_destroy(clnt);
+       return rc;
+}
+
+static isns_source_t *isns_lookup_node(char *iname)
+{
+       struct isns_node_list *node;
+
+       list_for_each_entry(node, &isns_initiators, list) {
+               if (!strcmp(iname, isns_source_name(node->source)))
+                       return node->source;
+       }
+       return NULL;
+}
+
+static struct isns_node_list *isns_create_node(const char *iname)
+{
+       isns_source_t *source;
+       struct isns_node_list *node;
+
+       source = isns_source_create_iscsi(iname);
+       if (!source)
+               return NULL;
+
+       node = calloc(1, sizeof(*node));
+       if (!node) {
+               isns_source_release(source);
+               return NULL;
+       }
+       INIT_LIST_HEAD(&node->list);
+       node->source = source;
+       return node;
+}
+
+static int isns_create_node_list(const char *def_iname)
+{
+       struct iface_rec *iface, *tmp_iface;
+       struct list_head ifaces;
+       struct isns_node_list *node, *tmp_node;
+       int rc = 0;
+
+       INIT_LIST_HEAD(&ifaces);
+       iface_link_ifaces(&ifaces);
+
+       if (def_iname) {
+               node = isns_create_node(def_iname);
+               if (!node) {
+                       rc = ISCSI_ERR_NOMEM;
+                       goto fail;
+               }
+               list_add_tail(&node->list, &isns_initiators);
+       }
+
+       list_for_each_entry(iface, &ifaces, list) {
+               if (strlen(iface->iname) &&
+                   !isns_lookup_node(iface->iname)) {
+                       node = isns_create_node(iface->iname);
+                       if (!node) {
+                               rc = ISCSI_ERR_NOMEM;
+                               goto fail;
+                       }
+                       list_add_tail(&node->list, &isns_initiators);
+               }
+       }
+       /* fix me */
+       rc = 0;
+       goto done;
+fail:
+       list_for_each_entry_safe(node, tmp_node, &isns_initiators, list) {
+               list_del(&node->list);
+               free(node);
+       }
+
+done:
+       list_for_each_entry_safe(iface, tmp_iface, &ifaces, list) {
+               list_del(&iface->list);
+               free(iface);
+       }
+       return rc;
+}
+
+static void isns_scn_callback(__attribute__((unused))isns_db_t *db,
+                             uint32_t bitmap,
+                             __attribute__((unused))isns_object_template_t *node_type,
+                             const char *node_name,
+                             const char *dst_name)
+{
+       log_error("SCN for initiator: %s (Target: %s, Event: %s.)",
+                   dst_name, node_name, isns_event_string(bitmap));
+       isns_disc_new_portals(node_name, dst_name);
+}
+
+static void isns_clear_refresh_list(void)
+{
+       struct isns_refresh_data *refresh_data, *tmp_refresh;
+
+       list_for_each_entry_safe(refresh_data, tmp_refresh, &isns_refresh_list,
+                                list)
+               isns_free_refresh_data(refresh_data);
+}
+
+static int isns_scn_recv(isns_server_t *svr, isns_socket_t *svr_sock,
+                        int poll_inval)
+{
+       isns_message_t *msg, *rsp;
+       struct timeval timeout = { 0, 0 };
+       time_t now, then, next_timeout;
+       unsigned int function;
+       int rc = 0;
+
+       log_debug(1, "isns_scn_recv");
+
+       while (!stop_discoveryd) {
+               /* reap disc/login procs */
+               reap_proc();
+               /*
+                * timer func could force a scn registration so check timers
+                * first
+                */
+               then = isns_run_timers();
+               now = time(NULL);
+               next_timeout = now + 3600;
+               if (then && then < next_timeout)
+                       next_timeout = then;
+
+               if (isns_register_nodes) {
+                       isns_clear_refresh_list();
+                       /*
+                        * it is ok to block here, because the server
+                        * should have unregistered us or this is our
+                        * first time registerting.
+                        */
+                       rc = isns_scn_register(svr_sock, poll_inval);
+                       if (rc) {
+                               sleep(5);
+                               continue;
+                       }
+
+                       isns_disc_new_portals(NULL, NULL);
+                       if (!poll_inval)
+                               break;
+                       isns_register_nodes = 0;
+                       /*
+                        * the scn reg may have added timers or changed
+                        * timeout values so recheck.
+                        */
+                       continue;
+               }
+
+               /* Determine how long we can sleep */
+               if (next_timeout <= now)
+                       continue;
+               timeout.tv_sec = next_timeout - now;
+
+               if ((msg = isns_recv_message(&timeout)) == NULL)
+                       continue;
+
+               function = isns_message_function(msg);
+               if (function != ISNS_STATE_CHANGE_NOTIFICATION) {
+                       log_warning("Discarding unexpected %s message",
+                                   isns_function_name(function));
+                       isns_message_release(msg);
+                       continue;
+               }
+
+               if ((rsp = isns_process_message(svr, msg)) != NULL) {
+                       isns_socket_t *sock = isns_message_socket(msg);
+
+                       isns_socket_send(sock, rsp);
+                       isns_message_release(rsp);
+               }
+
+               isns_message_release(msg);
+       }
+
+       log_debug(1, "isns_scn_recv done");
+       reap_proc();
+       return rc;
+}
+
+#define ISNS_EVENTD_PIDFILE    ISNS_RUNDIR"/iscsid.isns.pid"
+#define ISNS_EVENTD_CTL                ISNS_RUNDIR"/iscsid.isns.isnsctl"
+
+static int isns_eventd(const char *def_iname, char *disc_addr, int port,
+                      int poll_inval)
+{
+       static isns_socket_t *svr_sock;
+       isns_server_t *svr;
+       isns_db_t *db;
+       struct isns_node_list *tmp_node, *node;
+       int rc = 0;
+
+       isns_create_node_list(def_iname);
+       if (list_empty(&isns_initiators)) {
+               log_error("iSNS registration failed. Initiatorname not set.");
+               return ISCSI_ERR_INVAL;
+       }
+
+       /* use def_iname or if not set the first iface's iname for the src */
+       node = list_entry(isns_initiators.next, struct isns_node_list, list);
+       isns_assign_string(&isns_config.ic_source_name,
+                          isns_source_name(node->source));
+       isns_config.ic_security = 0;
+       isns_config.ic_pidfile = ISNS_EVENTD_PIDFILE;
+       isns_config.ic_control_socket = ISNS_EVENTD_CTL;
+
+       if (discovery_isns_set_servername(disc_addr, port)) {
+               rc = ISCSI_ERR_NOMEM;
+               goto fail;
+       }
+
+       isns_write_pidfile(isns_config.ic_pidfile);
+
+       db = isns_db_open(NULL);
+       if (!db) {
+               log_error("iSNS setup failed. Could not create db.");
+               rc = ISCSI_ERR_NOMEM;
+               goto fail;
+       }
+       svr = isns_create_server(node->source, db, &isns_callback_service_ops);
+       if (!svr) {
+               log_error("iSNS setup failed. Could not create server.");
+               rc = ISCSI_ERR_TRANS;
+               goto fail;
+       }
+       isns_server_set_scn_callback(svr, isns_scn_callback);
+
+       svr_sock = isns_create_server_socket(NULL, NULL, AF_INET6, SOCK_DGRAM);
+       if (!svr_sock) {
+               log_error("iSNS setup failed. Could not create server socket.");
+               rc = ISCSI_ERR_TRANS;
+               goto fail;
+       }
+
+       rc = isns_scn_recv(svr, svr_sock, poll_inval);
+       isns_cancel_refresh_timers();
+fail:
+       isns_clear_refresh_list();
+
+       list_for_each_entry_safe(node, tmp_node, &isns_initiators, list) {
+               list_del(&node->list);
+               free(node);
+       }
+
+       if (isns_entity_id)
+               free(isns_entity_id);
+       isns_entity_id = NULL;
+
+       discovery_isns_free_servername();
+
+       if (isns_config.ic_source_name)
+               free(isns_config.ic_source_name);
+       isns_config.ic_source_name = NULL;
+       return rc;
+}
+
+static void start_isns(const char *def_iname, struct discovery_rec *drec,
+                      int poll_inval)
+{
+       int rc, port = drec->port;
+
+       if (port < 0)
+               port = ISNS_DEFAULT_PORT;
+
+       rc = isns_eventd(def_iname, drec->address, port, poll_inval);
+       log_debug(1, "start isns done %d.", rc);
+       discoveryd_stop();
+}
+
+/* SendTargets */
+static void __do_st_disc_and_login(struct discovery_rec *drec)
+{
+       struct list_head rec_list, setup_ifaces;
+       struct iface_rec *iface, *tmp_iface;
+       int rc;
+
+       INIT_LIST_HEAD(&rec_list);
+       INIT_LIST_HEAD(&setup_ifaces);
+
+       /*
+        * The disc daemon will try again in poll_interval secs
+        * so no need to retry here
+        */
+       drec->u.sendtargets.reopen_max = 0;
+
+       iface_link_ifaces(&setup_ifaces);
+
+       rc = idbm_bind_ifaces_to_nodes(discovery_sendtargets, drec,
+                                       &setup_ifaces, &rec_list);
+       if (rc) {
+               log_error("Could not perform SendTargets to %s:%d.",
+                          drec->address, drec->port);
+               goto free_ifaces;
+       }
+
+       update_sessions(&rec_list, NULL, NULL);
+
+free_ifaces:
+       list_for_each_entry_safe(iface, tmp_iface, &setup_ifaces, list) {
+               list_del(&iface->list);
+               free(iface);
+       }
+}
+
+static void do_st_disc_and_login(__attribute__((unused))const char *def_iname,
+                                struct discovery_rec *drec, int poll_inval)
+{
+       if (poll_inval < 0)
+               poll_inval = DISC_DEF_POLL_INVL;
+
+       do {
+               __do_st_disc_and_login(drec);
+               if (!poll_inval)
+                       break;
+       } while (!stop_discoveryd && !sleep(poll_inval));
+
+       discoveryd_stop();
+}
+
+static int st_start(__attribute__((unused))void *data,
+                   struct discovery_rec *drec)
+{
+       log_debug(1, "st_start %s:%d %d", drec->address, drec->port,
+                 drec->u.sendtargets.use_discoveryd);
+       if (!drec->u.sendtargets.use_discoveryd)
+               return ISCSI_ERR_INVAL;
+
+       fork_disc(NULL, drec, drec->u.sendtargets.discoveryd_poll_inval,
+                 do_st_disc_and_login);
+       return 0;
+}
+
+static void discoveryd_st_start(void)
+{
+       idbm_for_each_st_drec(NULL, st_start);
+}
+
+static int isns_start(void *data, struct discovery_rec *drec)
+{
+       log_debug(1, "isns_start %s:%d %d", drec->address, drec->port,
+                 drec->u.isns.use_discoveryd);
+       if (!drec->u.isns.use_discoveryd)
+               return ISCSI_ERR_INVAL;
+
+       fork_disc(data, drec, drec->u.isns.discoveryd_poll_inval, start_isns);
+       return 0;
+}
+
+static void discoveryd_isns_start(const char *def_iname)
+{
+       idbm_for_each_isns_drec((void *)def_iname, isns_start);
+}
+
+void discoveryd_start(const char *def_iname)
+{
+       discoveryd_isns_start(def_iname);
+       discoveryd_st_start();
+}
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/discoveryd.h b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/discoveryd.h
new file mode 100644 (file)
index 0000000..9437ae9
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef _DISC_DAEMON_H
+#define _DISC_DAEMON_H
+
+extern void discoveryd_start(const char *def_iname);
+
+#endif
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/ethtool-copy.h b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/ethtool-copy.h
new file mode 100644 (file)
index 0000000..d366c3a
--- /dev/null
@@ -0,0 +1,597 @@
+/*
+ * ethtool.h: Defines for Linux ethtool.
+ *
+ * Copyright (C) 1998 David S. Miller (davem@redhat.com)
+ * Copyright 2001 Jeff Garzik <jgarzik@pobox.com>
+ * Portions Copyright 2001 Sun Microsystems (thockin@sun.com)
+ * Portions Copyright 2002 Intel (eli.kupermann@intel.com,
+ *                                christopher.leech@intel.com,
+ *                                scott.feldman@intel.com)
+ * Portions Copyright (C) Sun Microsystems 2008
+ */
+
+#ifndef _LINUX_ETHTOOL_H
+#define _LINUX_ETHTOOL_H
+
+#include <linux/types.h>
+
+/* This should work for both 32 and 64 bit userland. */
+struct ethtool_cmd {
+       __u32   cmd;
+       __u32   supported;      /* Features this interface supports */
+       __u32   advertising;    /* Features this interface advertises */
+       __u16   speed;          /* The forced speed, 10Mb, 100Mb, gigabit */
+       __u8    duplex;         /* Duplex, half or full */
+       __u8    port;           /* Which connector port */
+       __u8    phy_address;
+       __u8    transceiver;    /* Which transceiver to use */
+       __u8    autoneg;        /* Enable or disable autonegotiation */
+       __u8    mdio_support;
+       __u32   maxtxpkt;       /* Tx pkts before generating tx int */
+       __u32   maxrxpkt;       /* Rx pkts before generating rx int */
+       __u16   speed_hi;
+       __u8    eth_tp_mdix;
+       __u8    reserved2;
+       __u32   lp_advertising; /* Features the link partner advertises */
+       __u32   reserved[2];
+};
+
+static inline void ethtool_cmd_speed_set(struct ethtool_cmd *ep,
+                                               __u32 speed)
+{
+
+       ep->speed = (__u16)speed;
+       ep->speed_hi = (__u16)(speed >> 16);
+}
+
+static inline __u32 ethtool_cmd_speed(struct ethtool_cmd *ep)
+{
+       return (ep->speed_hi << 16) | ep->speed;
+}
+
+#define ETHTOOL_BUSINFO_LEN    32
+/* these strings are set to whatever the driver author decides... */
+struct ethtool_drvinfo {
+       __u32   cmd;
+       char    driver[32];     /* driver short name, "tulip", "eepro100" */
+       char    version[32];    /* driver version string */
+       char    fw_version[32]; /* firmware version string, if applicable */
+       char    bus_info[ETHTOOL_BUSINFO_LEN];  /* Bus info for this IF. */
+                               /* For PCI devices, use pci_name(pci_dev). */
+       char    reserved1[32];
+       char    reserved2[12];
+       __u32   n_priv_flags;   /* number of flags valid in ETHTOOL_GPFLAGS */
+       __u32   n_stats;        /* number of u64's from ETHTOOL_GSTATS */
+       __u32   testinfo_len;
+       __u32   eedump_len;     /* Size of data from ETHTOOL_GEEPROM (bytes) */
+       __u32   regdump_len;    /* Size of data from ETHTOOL_GREGS (bytes) */
+};
+
+#define SOPASS_MAX     6
+/* wake-on-lan settings */
+struct ethtool_wolinfo {
+       __u32   cmd;
+       __u32   supported;
+       __u32   wolopts;
+       __u8    sopass[SOPASS_MAX]; /* SecureOn(tm) password */
+};
+
+/* for passing single values */
+struct ethtool_value {
+       __u32   cmd;
+       __u32   data;
+};
+
+/* for passing big chunks of data */
+struct ethtool_regs {
+       __u32   cmd;
+       __u32   version; /* driver-specific, indicates different chips/revs */
+       __u32   len; /* bytes */
+       __u8    data[0];
+};
+
+/* for passing EEPROM chunks */
+struct ethtool_eeprom {
+       __u32   cmd;
+       __u32   magic;
+       __u32   offset; /* in bytes */
+       __u32   len; /* in bytes */
+       __u8    data[0];
+};
+
+/* for configuring coalescing parameters of chip */
+struct ethtool_coalesce {
+       __u32   cmd;    /* ETHTOOL_{G,S}COALESCE */
+
+       /* How many usecs to delay an RX interrupt after
+        * a packet arrives.  If 0, only rx_max_coalesced_frames
+        * is used.
+        */
+       __u32   rx_coalesce_usecs;
+
+       /* How many packets to delay an RX interrupt after
+        * a packet arrives.  If 0, only rx_coalesce_usecs is
+        * used.  It is illegal to set both usecs and max frames
+        * to zero as this would cause RX interrupts to never be
+        * generated.
+        */
+       __u32   rx_max_coalesced_frames;
+
+       /* Same as above two parameters, except that these values
+        * apply while an IRQ is being serviced by the host.  Not
+        * all cards support this feature and the values are ignored
+        * in that case.
+        */
+       __u32   rx_coalesce_usecs_irq;
+       __u32   rx_max_coalesced_frames_irq;
+
+       /* How many usecs to delay a TX interrupt after
+        * a packet is sent.  If 0, only tx_max_coalesced_frames
+        * is used.
+        */
+       __u32   tx_coalesce_usecs;
+
+       /* How many packets to delay a TX interrupt after
+        * a packet is sent.  If 0, only tx_coalesce_usecs is
+        * used.  It is illegal to set both usecs and max frames
+        * to zero as this would cause TX interrupts to never be
+        * generated.
+        */
+       __u32   tx_max_coalesced_frames;
+
+       /* Same as above two parameters, except that these values
+        * apply while an IRQ is being serviced by the host.  Not
+        * all cards support this feature and the values are ignored
+        * in that case.
+        */
+       __u32   tx_coalesce_usecs_irq;
+       __u32   tx_max_coalesced_frames_irq;
+
+       /* How many usecs to delay in-memory statistics
+        * block updates.  Some drivers do not have an in-memory
+        * statistic block, and in such cases this value is ignored.
+        * This value must not be zero.
+        */
+       __u32   stats_block_coalesce_usecs;
+
+       /* Adaptive RX/TX coalescing is an algorithm implemented by
+        * some drivers to improve latency under low packet rates and
+        * improve throughput under high packet rates.  Some drivers
+        * only implement one of RX or TX adaptive coalescing.  Anything
+        * not implemented by the driver causes these values to be
+        * silently ignored.
+        */
+       __u32   use_adaptive_rx_coalesce;
+       __u32   use_adaptive_tx_coalesce;
+
+       /* When the packet rate (measured in packets per second)
+        * is below pkt_rate_low, the {rx,tx}_*_low parameters are
+        * used.
+        */
+       __u32   pkt_rate_low;
+       __u32   rx_coalesce_usecs_low;
+       __u32   rx_max_coalesced_frames_low;
+       __u32   tx_coalesce_usecs_low;
+       __u32   tx_max_coalesced_frames_low;
+
+       /* When the packet rate is below pkt_rate_high but above
+        * pkt_rate_low (both measured in packets per second) the
+        * normal {rx,tx}_* coalescing parameters are used.
+        */
+
+       /* When the packet rate is (measured in packets per second)
+        * is above pkt_rate_high, the {rx,tx}_*_high parameters are
+        * used.
+        */
+       __u32   pkt_rate_high;
+       __u32   rx_coalesce_usecs_high;
+       __u32   rx_max_coalesced_frames_high;
+       __u32   tx_coalesce_usecs_high;
+       __u32   tx_max_coalesced_frames_high;
+
+       /* How often to do adaptive coalescing packet rate sampling,
+        * measured in seconds.  Must not be zero.
+        */
+       __u32   rate_sample_interval;
+};
+
+/* for configuring RX/TX ring parameters */
+struct ethtool_ringparam {
+       __u32   cmd;    /* ETHTOOL_{G,S}RINGPARAM */
+
+       /* Read only attributes.  These indicate the maximum number
+        * of pending RX/TX ring entries the driver will allow the
+        * user to set.
+        */
+       __u32   rx_max_pending;
+       __u32   rx_mini_max_pending;
+       __u32   rx_jumbo_max_pending;
+       __u32   tx_max_pending;
+
+       /* Values changeable by the user.  The valid values are
+        * in the range 1 to the "*_max_pending" counterpart above.
+        */
+       __u32   rx_pending;
+       __u32   rx_mini_pending;
+       __u32   rx_jumbo_pending;
+       __u32   tx_pending;
+};
+
+/* for configuring link flow control parameters */
+struct ethtool_pauseparam {
+       __u32   cmd;    /* ETHTOOL_{G,S}PAUSEPARAM */
+
+       /* If the link is being auto-negotiated (via ethtool_cmd.autoneg
+        * being true) the user may set 'autonet' here non-zero to have the
+        * pause parameters be auto-negotiated too.  In such a case, the
+        * {rx,tx}_pause values below determine what capabilities are
+        * advertised.
+        *
+        * If 'autoneg' is zero or the link is not being auto-negotiated,
+        * then {rx,tx}_pause force the driver to use/not-use pause
+        * flow control.
+        */
+       __u32   autoneg;
+       __u32   rx_pause;
+       __u32   tx_pause;
+};
+
+#define ETH_GSTRING_LEN                32
+enum ethtool_stringset {
+       ETH_SS_TEST             = 0,
+       ETH_SS_STATS,
+       ETH_SS_PRIV_FLAGS,
+};
+
+/* for passing string sets for data tagging */
+struct ethtool_gstrings {
+       __u32   cmd;            /* ETHTOOL_GSTRINGS */
+       __u32   string_set;     /* string set id e.c. ETH_SS_TEST, etc*/
+       __u32   len;            /* number of strings in the string set */
+       __u8    data[0];
+};
+
+enum ethtool_test_flags {
+       ETH_TEST_FL_OFFLINE     = (1 << 0),     /* online / offline */
+       ETH_TEST_FL_FAILED      = (1 << 1),     /* test passed / failed */
+};
+
+/* for requesting NIC test and getting results*/
+struct ethtool_test {
+       __u32   cmd;            /* ETHTOOL_TEST */
+       __u32   flags;          /* ETH_TEST_FL_xxx */
+       __u32   reserved;
+       __u32   len;            /* result length, in number of u64 elements */
+       __u64   data[0];
+};
+
+/* for dumping NIC-specific statistics */
+struct ethtool_stats {
+       __u32   cmd;            /* ETHTOOL_GSTATS */
+       __u32   n_stats;        /* number of u64's being returned */
+       __u64   data[0];
+};
+
+struct ethtool_perm_addr {
+       __u32   cmd;            /* ETHTOOL_GPERMADDR */
+       __u32   size;
+       __u8    data[0];
+};
+
+/* boolean flags controlling per-interface behavior characteristics.
+ * When reading, the flag indicates whether or not a certain behavior
+ * is enabled/present.  When writing, the flag indicates whether
+ * or not the driver should turn on (set) or off (clear) a behavior.
+ *
+ * Some behaviors may read-only (unconditionally absent or present).
+ * If such is the case, return EINVAL in the set-flags operation if the
+ * flag differs from the read-only value.
+ */
+enum ethtool_flags {
+       ETH_FLAG_LRO            = (1 << 15),    /* LRO is enabled */
+};
+
+/* The following structures are for supporting RX network flow
+ * classification configuration. Note, all multibyte fields, e.g.,
+ * ip4src, ip4dst, psrc, pdst, spi, etc. are expected to be in network
+ * byte order.
+ */
+struct ethtool_tcpip4_spec {
+       __be32  ip4src;
+       __be32  ip4dst;
+       __be16  psrc;
+       __be16  pdst;
+       __u8    tos;
+};
+
+struct ethtool_ah_espip4_spec {
+       __be32  ip4src;
+       __be32  ip4dst;
+       __be32  spi;
+       __u8    tos;
+};
+
+struct ethtool_rawip4_spec {
+       __be32  ip4src;
+       __be32  ip4dst;
+       __u8    hdata[64];
+};
+
+struct ethtool_ether_spec {
+       __be16  ether_type;
+       __u8    frame_size;
+       __u8    eframe[16];
+};
+
+#define        ETH_RX_NFC_IP4  1
+#define        ETH_RX_NFC_IP6  2
+
+struct ethtool_usrip4_spec {
+       __be32  ip4src;
+       __be32  ip4dst;
+       __be32  l4_4_bytes;
+       __u8    tos;
+       __u8    ip_ver;
+       __u8    proto;
+};
+
+struct ethtool_rx_flow_spec {
+       __u32           flow_type;
+       union {
+               struct ethtool_tcpip4_spec              tcp_ip4_spec;
+               struct ethtool_tcpip4_spec              udp_ip4_spec;
+               struct ethtool_tcpip4_spec              sctp_ip4_spec;
+               struct ethtool_ah_espip4_spec           ah_ip4_spec;
+               struct ethtool_ah_espip4_spec           esp_ip4_spec;
+               struct ethtool_rawip4_spec              raw_ip4_spec;
+               struct ethtool_ether_spec               ether_spec;
+               struct ethtool_usrip4_spec              usr_ip4_spec;
+               __u8                                    hdata[64];
+       } h_u, m_u; /* entry, mask */
+       __u64           ring_cookie;
+       __u32           location;
+};
+
+struct ethtool_rxnfc {
+       __u32                           cmd;
+       __u32                           flow_type;
+       /* The rx flow hash value or the rule DB size */
+       __u64                           data;
+       struct ethtool_rx_flow_spec     fs;
+       __u32                           rule_cnt;
+       __u32                           rule_locs[0];
+};
+
+#define ETHTOOL_FLASH_MAX_FILENAME     128
+enum ethtool_flash_op_type {
+       ETHTOOL_FLASH_ALL_REGIONS       = 0,
+};
+
+/* for passing firmware flashing related parameters */
+struct ethtool_flash {
+       __u32   cmd;
+       __u32   region;
+       char    data[ETHTOOL_FLASH_MAX_FILENAME];
+};
+
+
+/* CMDs currently supported */
+#define ETHTOOL_GSET           0x00000001 /* Get settings. */
+#define ETHTOOL_SSET           0x00000002 /* Set settings. */
+#define ETHTOOL_GDRVINFO       0x00000003 /* Get driver info. */
+#define ETHTOOL_GREGS          0x00000004 /* Get NIC registers. */
+#define ETHTOOL_GWOL           0x00000005 /* Get wake-on-lan options. */
+#define ETHTOOL_SWOL           0x00000006 /* Set wake-on-lan options. */
+#define ETHTOOL_GMSGLVL                0x00000007 /* Get driver message level */
+#define ETHTOOL_SMSGLVL                0x00000008 /* Set driver msg level. */
+#define ETHTOOL_NWAY_RST       0x00000009 /* Restart autonegotiation. */
+#define ETHTOOL_GLINK          0x0000000a /* Get link status (ethtool_value) */
+#define ETHTOOL_GEEPROM                0x0000000b /* Get EEPROM data */
+#define ETHTOOL_SEEPROM                0x0000000c /* Set EEPROM data. */
+#define ETHTOOL_GCOALESCE      0x0000000e /* Get coalesce config */
+#define ETHTOOL_SCOALESCE      0x0000000f /* Set coalesce config. */
+#define ETHTOOL_GRINGPARAM     0x00000010 /* Get ring parameters */
+#define ETHTOOL_SRINGPARAM     0x00000011 /* Set ring parameters. */
+#define ETHTOOL_GPAUSEPARAM    0x00000012 /* Get pause parameters */
+#define ETHTOOL_SPAUSEPARAM    0x00000013 /* Set pause parameters. */
+#define ETHTOOL_GRXCSUM                0x00000014 /* Get RX hw csum enable (ethtool_value) */
+#define ETHTOOL_SRXCSUM                0x00000015 /* Set RX hw csum enable (ethtool_value) */
+#define ETHTOOL_GTXCSUM                0x00000016 /* Get TX hw csum enable (ethtool_value) */
+#define ETHTOOL_STXCSUM                0x00000017 /* Set TX hw csum enable (ethtool_value) */
+#define ETHTOOL_GSG            0x00000018 /* Get scatter-gather enable
+                                           * (ethtool_value) */
+#define ETHTOOL_SSG            0x00000019 /* Set scatter-gather enable
+                                           * (ethtool_value). */
+#define ETHTOOL_TEST           0x0000001a /* execute NIC self-test. */
+#define ETHTOOL_GSTRINGS       0x0000001b /* get specified string set */
+#define ETHTOOL_PHYS_ID                0x0000001c /* identify the NIC */
+#define ETHTOOL_GSTATS         0x0000001d /* get NIC-specific statistics */
+#define ETHTOOL_GTSO           0x0000001e /* Get TSO enable (ethtool_value) */
+#define ETHTOOL_STSO           0x0000001f /* Set TSO enable (ethtool_value) */
+#define ETHTOOL_GPERMADDR      0x00000020 /* Get permanent hardware address */
+#define ETHTOOL_GUFO           0x00000021 /* Get UFO enable (ethtool_value) */
+#define ETHTOOL_SUFO           0x00000022 /* Set UFO enable (ethtool_value) */
+#define ETHTOOL_GGSO           0x00000023 /* Get GSO enable (ethtool_value) */
+#define ETHTOOL_SGSO           0x00000024 /* Set GSO enable (ethtool_value) */
+#define ETHTOOL_GFLAGS         0x00000025 /* Get flags bitmap(ethtool_value) */
+#define ETHTOOL_SFLAGS         0x00000026 /* Set flags bitmap(ethtool_value) */
+#define ETHTOOL_GPFLAGS                0x00000027 /* Get driver-private flags bitmap */
+#define ETHTOOL_SPFLAGS                0x00000028 /* Set driver-private flags bitmap */
+
+#define        ETHTOOL_GRXFH           0x00000029 /* Get RX flow hash configuration */
+#define        ETHTOOL_SRXFH           0x0000002a /* Set RX flow hash configuration */
+#define ETHTOOL_GGRO           0x0000002b /* Get GRO enable (ethtool_value) */
+#define ETHTOOL_SGRO           0x0000002c /* Set GRO enable (ethtool_value) */
+#define        ETHTOOL_GRXRINGS        0x0000002d /* Get RX rings available for LB */
+#define        ETHTOOL_GRXCLSRLCNT     0x0000002e /* Get RX class rule count */
+#define        ETHTOOL_GRXCLSRULE      0x0000002f /* Get RX classification rule */
+#define        ETHTOOL_GRXCLSRLALL     0x00000030 /* Get all RX classification rule */
+#define        ETHTOOL_SRXCLSRLDEL     0x00000031 /* Delete RX classification rule */
+#define        ETHTOOL_SRXCLSRLINS     0x00000032 /* Insert RX classification rule */
+#define        ETHTOOL_FLASHDEV        0x00000033 /* Flash firmware to device */
+#define        ETHTOOL_RESET           0x00000034 /* Reset hardware */
+
+/* compatibility with older code */
+#define SPARC_ETH_GSET         ETHTOOL_GSET
+#define SPARC_ETH_SSET         ETHTOOL_SSET
+
+/* Indicates what features are supported by the interface. */
+#define SUPPORTED_10baseT_Half         (1 << 0)
+#define SUPPORTED_10baseT_Full         (1 << 1)
+#define SUPPORTED_100baseT_Half                (1 << 2)
+#define SUPPORTED_100baseT_Full                (1 << 3)
+#define SUPPORTED_1000baseT_Half       (1 << 4)
+#define SUPPORTED_1000baseT_Full       (1 << 5)
+#define SUPPORTED_Autoneg              (1 << 6)
+#define SUPPORTED_TP                   (1 << 7)
+#define SUPPORTED_AUI                  (1 << 8)
+#define SUPPORTED_MII                  (1 << 9)
+#define SUPPORTED_FIBRE                        (1 << 10)
+#define SUPPORTED_BNC                  (1 << 11)
+#define SUPPORTED_10000baseT_Full      (1 << 12)
+#define SUPPORTED_Pause                        (1 << 13)
+#define SUPPORTED_Asym_Pause           (1 << 14)
+#define SUPPORTED_2500baseX_Full       (1 << 15)
+#define SUPPORTED_Backplane            (1 << 16)
+#define SUPPORTED_1000baseKX_Full      (1 << 17)
+#define SUPPORTED_10000baseKX4_Full    (1 << 18)
+#define SUPPORTED_10000baseKR_Full     (1 << 19)
+#define SUPPORTED_10000baseR_FEC       (1 << 20)
+
+/* Indicates what features are advertised by the interface. */
+#define ADVERTISED_10baseT_Half                (1 << 0)
+#define ADVERTISED_10baseT_Full                (1 << 1)
+#define ADVERTISED_100baseT_Half       (1 << 2)
+#define ADVERTISED_100baseT_Full       (1 << 3)
+#define ADVERTISED_1000baseT_Half      (1 << 4)
+#define ADVERTISED_1000baseT_Full      (1 << 5)
+#define ADVERTISED_Autoneg             (1 << 6)
+#define ADVERTISED_TP                  (1 << 7)
+#define ADVERTISED_AUI                 (1 << 8)
+#define ADVERTISED_MII                 (1 << 9)
+#define ADVERTISED_FIBRE               (1 << 10)
+#define ADVERTISED_BNC                 (1 << 11)
+#define ADVERTISED_10000baseT_Full     (1 << 12)
+#define ADVERTISED_Pause               (1 << 13)
+#define ADVERTISED_Asym_Pause          (1 << 14)
+#define ADVERTISED_2500baseX_Full      (1 << 15)
+#define ADVERTISED_Backplane           (1 << 16)
+#define ADVERTISED_1000baseKX_Full     (1 << 17)
+#define ADVERTISED_10000baseKX4_Full   (1 << 18)
+#define ADVERTISED_10000baseKR_Full    (1 << 19)
+#define ADVERTISED_10000baseR_FEC      (1 << 20)
+
+/* The following are all involved in forcing a particular link
+ * mode for the device for setting things.  When getting the
+ * devices settings, these indicate the current mode and whether
+ * it was foced up into this mode or autonegotiated.
+ */
+
+/* The forced speed, 10Mb, 100Mb, gigabit, 2.5Gb, 10GbE. */
+#define SPEED_10               10
+#define SPEED_100              100
+#define SPEED_1000             1000
+#define SPEED_2500             2500
+#define SPEED_10000            10000
+
+/* Duplex, half or full. */
+#define DUPLEX_HALF            0x00
+#define DUPLEX_FULL            0x01
+
+/* Which connector port. */
+#define PORT_TP                        0x00
+#define PORT_AUI               0x01
+#define PORT_MII               0x02
+#define PORT_FIBRE             0x03
+#define PORT_BNC               0x04
+#define PORT_DA                        0x05
+#define PORT_NONE              0xef
+#define PORT_OTHER             0xff
+
+/* Which transceiver to use. */
+#define XCVR_INTERNAL          0x00
+#define XCVR_EXTERNAL          0x01
+#define XCVR_DUMMY1            0x02
+#define XCVR_DUMMY2            0x03
+#define XCVR_DUMMY3            0x04
+
+/* Enable or disable autonegotiation.  If this is set to enable,
+ * the forced link modes above are completely ignored.
+ */
+#define AUTONEG_DISABLE                0x00
+#define AUTONEG_ENABLE         0x01
+
+/* Mode MDI or MDI-X */
+#define ETH_TP_MDI_INVALID     0x00
+#define ETH_TP_MDI             0x01
+#define ETH_TP_MDI_X           0x02
+
+/* Wake-On-Lan options. */
+#define WAKE_PHY               (1 << 0)
+#define WAKE_UCAST             (1 << 1)
+#define WAKE_MCAST             (1 << 2)
+#define WAKE_BCAST             (1 << 3)
+#define WAKE_ARP               (1 << 4)
+#define WAKE_MAGIC             (1 << 5)
+#define WAKE_MAGICSECURE       (1 << 6) /* only meaningful if WAKE_MAGIC */
+
+/* L3-L4 network traffic flow types */
+#define        TCP_V4_FLOW     0x01
+#define        UDP_V4_FLOW     0x02
+#define        SCTP_V4_FLOW    0x03
+#define        AH_ESP_V4_FLOW  0x04
+#define        TCP_V6_FLOW     0x05
+#define        UDP_V6_FLOW     0x06
+#define        SCTP_V6_FLOW    0x07
+#define        AH_ESP_V6_FLOW  0x08
+#define        AH_V4_FLOW      0x09
+#define        ESP_V4_FLOW     0x0a
+#define        AH_V6_FLOW      0x0b
+#define        ESP_V6_FLOW     0x0c
+#define        IP_USER_FLOW    0x0d
+#define IPV4_FLOW       0x10
+#define IPV6_FLOW       0x11
+
+/* L3-L4 network traffic flow hash options */
+#define        RXH_L2DA        (1 << 1)
+#define        RXH_VLAN        (1 << 2)
+#define        RXH_L3_PROTO    (1 << 3)
+#define        RXH_IP_SRC      (1 << 4)
+#define        RXH_IP_DST      (1 << 5)
+#define        RXH_L4_B_0_1    (1 << 6) /* src port in case of TCP/UDP/SCTP */
+#define        RXH_L4_B_2_3    (1 << 7) /* dst port in case of TCP/UDP/SCTP */
+#define        RXH_DISCARD     (1 << 31)
+
+#define        RX_CLS_FLOW_DISC        0xffffffffffffffffULL
+
+/* Reset flags */
+/* The reset() operation must clear the flags for the components which
+ * were actually reset.  On successful return, the flags indicate the
+ * components which were not reset, either because they do not exist
+ * in the hardware or because they cannot be reset independently.  The
+ * driver must never reset any components that were not requested.
+ */
+enum ethtool_reset_flags {
+       /* These flags represent components dedicated to the interface
+        * the command is addressed to.  Shift any flag left by
+        * ETH_RESET_SHARED_SHIFT to reset a shared component of the
+        * same type.
+        */
+       ETH_RESET_MGMT          = 1 << 0,       /* Management processor */
+       ETH_RESET_IRQ           = 1 << 1,       /* Interrupt requester */
+       ETH_RESET_DMA           = 1 << 2,       /* DMA engine */
+       ETH_RESET_FILTER        = 1 << 3,       /* Filtering/flow direction */
+       ETH_RESET_OFFLOAD       = 1 << 4,       /* Protocol offload */
+       ETH_RESET_MAC           = 1 << 5,       /* Media access controller */
+       ETH_RESET_PHY           = 1 << 6,       /* Transceiver/PHY */
+       ETH_RESET_RAM           = 1 << 7,       /* RAM shared between
+                                                * multiple components */
+
+       ETH_RESET_DEDICATED     = 0x0000ffff,   /* All components dedicated to
+                                                * this interface */
+       ETH_RESET_ALL           = 0xffffffff,   /* All components used by this
+                                                * interface, even if shared */
+};
+#define ETH_RESET_SHARED_SHIFT 16
+
+#endif /* _LINUX_ETHTOOL_H */
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/event_poll.c b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/event_poll.c
new file mode 100644 (file)
index 0000000..f39f899
--- /dev/null
@@ -0,0 +1,244 @@
+/*
+ * iSCSI daemon event handler 
+ *
+ * Copyright (C) 2004 Dmitry Yusupov, Alex Aizman
+ * Copyright (C) 2006 Mike Christie
+ * Copyright (C) 2006 Red Hat, Inc. All rights reserved.
+ * maintained by open-iscsi@googlegroups.com
+ *
+ * Originally based on:
+ * (C) 2004 FUJITA Tomonori <tomof@acm.org>
+ *
+ * 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 <stdlib.h>
+#include <errno.h>
+#include <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"
+#include "sysfs.h"
+#include "iscsid.h"
+#include "log.h"
+#include "iscsi_ipc.h"
+#include "actor.h"
+#include "initiator.h"
+#include "iscsi_err.h"
+
+static unsigned int reap_count;
+
+/* track pid of reload fork, while running */
+static pid_t reload_pid = 0;
+static void (*reload_callback)(void);
+
+#define REAP_WAKEUP 1000 /* in millisecs */
+
+void reap_inc(void)
+{
+       reap_count++;
+}
+
+/* track the reload process to be reaped, when done */
+void reap_track_reload_process(pid_t reload_proc_pid, void (*reload_done_callback)(void))
+{
+       reload_pid = reload_proc_pid;
+       reload_callback = reload_done_callback;
+       reap_inc();
+}
+
+void reap_proc(void)
+{
+       int i, max_reaps;
+       pid_t rc;
+
+       /*
+        * We don't really need reap_count, but calling wait() all the
+        * time seems excessive.
+        */
+       max_reaps = reap_count;
+       for (i = 0; i < max_reaps; i++) {
+               rc = waitpid(0, NULL, WNOHANG);
+               if (rc > 0) {
+                       if (rc == reload_pid) {
+                               log_debug(6, "reaped reload process");
+                               reload_callback();
+                       }
+                       reap_count--;
+                       log_debug(6, "reaped pid %d, reap_count now %d",
+                                 (int)rc, reap_count);
+               }
+       }
+}
+
+static LIST_HEAD(shutdown_callbacks);
+
+struct shutdown_callback {
+       struct list_head list;
+       pid_t pid;
+};
+
+int shutdown_callback(pid_t pid)
+{
+       struct shutdown_callback *cb;
+
+       cb = calloc(1, sizeof(*cb));
+       if (!cb)
+               return ENOMEM;
+
+       INIT_LIST_HEAD(&cb->list);
+       cb->pid = pid;
+       log_debug(1, "adding %d for shutdown cb", pid);
+       list_add_tail(&cb->list, &shutdown_callbacks);
+       return 0;
+}
+
+static void shutdown_notify_pids(void)
+{
+       struct shutdown_callback *cb;
+
+       list_for_each_entry(cb, &shutdown_callbacks, list) {
+               log_debug(1, "Killing %d", cb->pid);
+               kill(cb->pid, SIGTERM);
+       }
+}
+
+static int shutdown_wait_pids(void)
+{
+       struct shutdown_callback *cb, *tmp;
+
+       list_for_each_entry_safe(cb, tmp, &shutdown_callbacks, list) {
+               /*
+                * the proc reaper could clean it up, so wait for any
+                * sign that it is gone.
+                */
+               if (waitpid(cb->pid, NULL, WNOHANG)) {
+                       log_debug(1, "%d done", cb->pid);
+                       list_del(&cb->list);
+                       free(cb);
+               }
+       }
+
+       return list_empty(&shutdown_callbacks);
+}
+
+#define POLL_CTRL      0
+#define POLL_IPC       1
+#define POLL_ALARM     2
+#define POLL_MAX       3
+
+static volatile int event_loop_stop;
+static queue_task_t *shutdown_qtask; 
+
+void event_loop_exit(queue_task_t *qtask)
+{
+       shutdown_qtask = qtask;
+       event_loop_stop = 1;
+}
+
+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) {
+               if (event_loop_stop) {
+                       if (!has_shutdown_children) {
+                               has_shutdown_children = 1;
+                               shutdown_notify_pids();
+                       }
+                       if (shutdown_wait_pids())
+                               break;
+               }
+
+               /* 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)
+                               ipc->ctldev_handle();
+
+                       if (poll_array[POLL_IPC].revents) {
+                               switch (ipc->auth_type) {
+                               case ISCSI_IPC_AUTH_UID:
+                                       mgmt_ipc_handle_uid_only(mgmt_ipc_fd);
+                                       break;
+                               default:
+                                       mgmt_ipc_handle(mgmt_ipc_fd);
+                                       break;
+                               }
+                       }
+
+                       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");
+                       } else {
+                               log_error("got poll() error (%d), errno (%d), "
+                                         "exiting", res, errno);
+                               break;
+                       }
+               }
+
+               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/pkgs/open-iscsi/open-iscsi-2.1.8/usr/event_poll.h b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/event_poll.h
new file mode 100644 (file)
index 0000000..f23132b
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * iSCSI event poll/loop 
+ *
+ * Copyright (C) 2004 Dmitry Yusupov, Alex Aizman
+ * 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 EVENT_POLL_H
+#define EVENT_POLL_H
+
+struct iscsi_ipc;
+struct queue_task;
+
+int shutdown_callback(pid_t pid);
+void reap_proc(void);
+void reap_inc(void);
+void reap_track_reload_process(pid_t realod_proc_pid, void (*reload_done_callback)(void));
+void event_loop(struct iscsi_ipc *ipc, int control_fd, int mgmt_ipc_fd);
+void event_loop_exit(struct queue_task *qtask);
+
+#endif
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/flashnode.c b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/flashnode.c
new file mode 100644 (file)
index 0000000..fd01cd4
--- /dev/null
@@ -0,0 +1,621 @@
+/*
+ * 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(__attribute__((unused))void *data,
+                             struct flashnode_rec *fnode,
+                             __attribute__((unused))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(__attribute__((unused))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(__attribute__((unused))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(__attribute__((unused))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(__attribute__((unused))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/pkgs/open-iscsi/open-iscsi-2.1.8/usr/flashnode.h b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/flashnode.h
new file mode 100644 (file)
index 0000000..2950fb5
--- /dev/null
@@ -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/pkgs/open-iscsi/open-iscsi-2.1.8/usr/fwparam_ibft/Makefile b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/fwparam_ibft/Makefile
new file mode 100644 (file)
index 0000000..7977491
--- /dev/null
@@ -0,0 +1,69 @@
+#
+#  Copyright (C) IBM Corporation. 2007
+#  Author: Doug Maxey <dwm@austin.ibm.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.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+#  Authors: Patrick Mansfield <patmans@us.ibm.com>
+#          Mike Anderson <andmike@us.ibm.com>
+#          Doug Maxey <dwm@austin.ibm.com>
+#          "Prasanna Mumbai" <mumbai.prasanna@gmail.com>
+#
+ifeq ($(TOPDIR),)
+       TOPDIR = ../..
+endif
+
+BISON = bison
+
+SBINDIR ?= $(DESTDIR)/sbin
+
+SYSDEPS_OBJS = $(sort $(wildcard ../sysdeps/*.o))
+OBJS := fw_entry.o fwparam_sysfs.o \
+       prom_lex.o prom_parse.tab.o fwparam_ppc.o
+CLEANFILES = $(OBJS) *.output
+
+CFLAGS ?= -O2 -g
+WARNFLAGS ?= -Wall -Wstrict-prototypes -Wno-format-truncation
+CFLAGS += -fPIC $(WARNFLAGS) -I$(TOPDIR)/include -I$(TOPDIR)/usr -D_GNU_SOURCE \
+         -I$(TOPDIR)/libopeniscsiusr
+CFLAGS += -DSBINDIR=\"$(SBINDIR)\" \
+         -DISCSI_VERSION_STR=\"$(ISCSI_VERSION_STR)\"
+
+all: $(OBJS)
+
+clean:
+       $(RM) $(CLEANFILES) .depend
+
+$(OBJS): prom_parse.tab.h prom_parse.h
+
+#
+# This directory is set up so that lex and bison should not have
+# to be run to generate C files, since the C files have already
+# been checked in and are present. This eliminates the need to run
+# them on systems where those tools may not be present. If you wish
+# to run either of them to regenerate their output files, remove
+# the output files first. This prevents these tools from being run
+# again if the output files are already present.
+#
+
+prom_lex.c: prom_lex.l
+       @[ -f $@ ] || $(LEX) -t $? > $@
+
+prom_parse.tab.c prom_parse.tab.h: prom_parse.y
+       @[ -f prom_parse.tab.c ] && [ -f prom_parse.tab.h ] || $(BISON) -H $?
+
+depend:
+       $(CC) $(CFLAGS) -M `ls *.c` > .depend
+
+-include .depend
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/fwparam_ibft/README b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/fwparam_ibft/README
new file mode 100644 (file)
index 0000000..0888cf9
--- /dev/null
@@ -0,0 +1,27 @@
+The files in this directory are used by
+iscsi programs in "usr" to access and parse
+the iBFT data.
+
+This code uses bison/lex to parse the data,
+but at some point it was decided to check in
+the output files from bison and flex, so that
+the average source-code user would not have
+to run those tools to compile the code.
+
+Now it is likely that most folks can get those
+tools, but the system of having static
+parsing and lexical analysis has worked for
+so long (and isn't broken), it would be a
+shame to change and break it. So the static
+files remain, for now. If you actually wish
+to rerun either of these tools, the Makefile
+is set up so that you have to first remove the
+generated files (prom_lex.c for lex, prom_parse.tab.c,
+and prom_parse.tab.h for bison).
+
+Note: if you wish to use these object files,
+they have two external requirements: they
+need the compatability routines in sysdeps.o,
+and they need the file iscsi_net_util.o.
+
+Lee Duncan     Mar, 2022
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/fwparam_ibft/fw_entry.c b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/fwparam_ibft/fw_entry.c
new file mode 100644 (file)
index 0000000..96af145
--- /dev/null
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) IBM Corporation. 2007
+ * Author: Doug Maxey <dwm@austin.ibm.com>
+ * based on code written by "Prasanna Mumbai" <mumbai.prasanna@gmail.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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stddef.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <net/route.h>
+
+#include "fw_context.h"
+#include "fwparam.h"
+#include "idbm_fields.h"
+#include "iscsi_net_util.h"
+#include "iscsi_err.h"
+#include "config.h"
+#include "iface.h"
+
+/**
+ * fw_setup_nics - setup nics (ethXs) based on ibft net info
+ *
+ * If this is a offload card, this function does nothing. The
+ * net info is used by the iscsi iface settings for the iscsi
+ * function.
+ */
+int fw_setup_nics(void)
+{
+       struct boot_context *context;
+       struct list_head targets;
+       char *iface_prev = NULL, transport[16];
+       int needs_bringup = 0, ret = 0, err;
+
+       INIT_LIST_HEAD(&targets);
+
+       ret = fw_get_targets(&targets);
+       if (ret || list_empty(&targets)) {
+               printf("Could not setup fw entries.\n");
+               return ISCSI_ERR_NO_OBJS_FOUND;
+       }
+
+       /*
+        * For each target in iBFT bring up required NIC and use routing
+        * to force iSCSI traffic through correct NIC
+        */
+       list_for_each_entry(context, &targets, list) {
+               if (iface_prev == NULL || strcmp(context->iface, iface_prev)) {
+                               /* Note: test above works because there is a
+                                * maximum of two targets in the iBFT
+                                */
+                               iface_prev = context->iface;
+                               needs_bringup = 1;
+               }
+               if (net_get_transport_name_from_netdev(context->iface, transport)) {
+                       /* Setup software NIC, */
+                       printf("Setting up software interface %s\n", context->iface);
+                       err = net_setup_netdev(context->iface, context->ipaddr,
+                                                                  context->mask, context->gateway,
+                                                                  context->vlan,
+                                                                  context->target_ipaddr, needs_bringup);
+                       if (err) {
+                               printf("Setting up software interface %s failed\n",
+                                               context->iface);
+                               ret = err;
+                       }
+               } else {
+                       /* Setup offload NIC. */
+                       struct iface_rec iface;
+
+                       memset(&iface, 0, sizeof(iface));
+                       iface_setup_defaults(&iface);
+                       printf("Setting up offload interface %s\n", context->iface);
+                       if (!iface_setup_from_boot_context(&iface, context)) {
+                                       printf("Setting up offload interface %s failed\n",
+                                                  context->iface);
+
+                                       ret = ISCSI_ERR;
+                       }
+               }
+       }
+
+       fw_free_targets(&targets);
+       if (ret)
+               return ISCSI_ERR;
+       else
+               return 0;
+}
+
+/**
+ * fw_get_entry - return boot context of portal used for boot
+ * @context: firmware info of portal
+ *
+ * Returns non-zero if no portal was used for boot.
+ *
+ * This function is not thread safe.
+ */
+int fw_get_entry(struct boot_context *context)
+{
+       int ret;
+
+       ret = fwparam_ppc_boot_info(context);
+       if (ret)
+               ret = fwparam_sysfs_boot_info(context);
+       return ret;
+}
+
+/**
+ * fw_get_targets - get a boot_context struct for each target
+ * @list: list to add entires on.
+ *
+ * Returns zero if entries were found that can be traversed with the
+ * list.h helpers, or non-zero if no entries are found.
+ *
+ * fw_free_targets should be called to free the list.
+ *
+ * This function is not thread safe.
+ */
+int fw_get_targets(struct list_head *list)
+{
+       int ret;
+
+       ret = fwparam_ppc_get_targets(list);
+       if (ret)
+               ret = fwparam_sysfs_get_targets(list);
+       return ret;
+}
+
+void fw_free_targets(struct list_head *list)
+{
+       struct boot_context *curr, *tmp;
+
+       if (!list || list_empty(list))
+               return;
+
+       list_for_each_entry_safe(curr, tmp, list, list) {
+               list_del(&curr->list);
+               free(curr);
+       }
+}
+
+static void dump_initiator(struct boot_context *context)
+{
+       struct iface_rec iface;
+
+       memset(&iface, 0, sizeof(iface));
+       iface_setup_defaults(&iface);
+       iface_setup_from_boot_context(&iface, context);
+
+       if (strlen(context->initiatorname))
+               printf("%s = %s\n", IFACE_INAME, context->initiatorname);
+
+       if (strlen(context->isid))
+               printf("%s = %s\n", IFACE_ISID, context->isid);
+
+       printf("%s = %s\n", IFACE_TRANSPORTNAME, iface.transport_name);
+}
+
+static void dump_target(struct boot_context *context)
+{
+       if (strlen(context->targetname))
+               printf("%s = %s\n", NODE_NAME, context->targetname);
+
+       if (strlen(context->target_ipaddr))
+               printf(CONN_ADDR" = %s\n", 0, context->target_ipaddr);
+       printf(CONN_PORT" = %d\n", 0, context->target_port);
+
+       if (strlen(context->chap_name))
+               printf("%s = %s\n", SESSION_USERNAME, context->chap_name);
+       if (strlen(context->chap_password))
+               printf("%s = %s\n", SESSION_PASSWORD, context->chap_password);
+       if (strlen(context->chap_name_in))
+               printf("%s = %s\n", SESSION_USERNAME_IN, context->chap_name_in);
+       if (strlen(context->chap_password_in))
+               printf("%s = %s\n", SESSION_PASSWORD_IN,
+                      context->chap_password_in);
+
+       if (strlen(context->lun))
+               printf("%s = %s\n", NODE_BOOT_LUN, context->lun);
+}
+
+static void dump_network(struct boot_context *context)
+{
+       /* Dump the 8 byte mac address (not iser support) */
+       if (strlen(context->mac))
+               printf("%s = %s\n", IFACE_HWADDR, context->mac);
+       /*
+        * 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 ((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);
+       if (strlen(context->ipaddr))
+               printf("%s = %s\n", IFACE_IPADDR, context->ipaddr);
+       if (context->prefix)
+               printf("%s = %d\n", IFACE_PREFIX_LEN, context->prefix);
+       if (strlen(context->mask))
+               printf("%s = %s\n", IFACE_SUBNET_MASK, context->mask);
+       if (strlen(context->gateway))
+               printf("%s = %s\n", IFACE_GATEWAY, context->gateway);
+       if (strlen(context->primary_dns))
+               printf("%s = %s\n", IFACE_PRIMARY_DNS, context->primary_dns);
+       if (strlen(context->secondary_dns))
+               printf("%s = %s\n", IFACE_SEC_DNS, context->secondary_dns);
+       if (strlen(context->vlan))
+               printf("%s = %s\n", IFACE_VLAN_ID, context->vlan);
+       if (strlen(context->iface))
+               printf("%s = %s\n", IFACE_NETNAME, context->iface);
+}
+
+/**
+ * fw_print_entry - print boot context info of portal used for boot
+ * @context: firmware info of portal
+ *
+ * Does not print anything if no portal was used for boot.
+ *
+ * TODO: Merge this in with idbm.c helpers.
+ */
+void fw_print_entry(struct boot_context *context)
+{
+       printf("%s\n", ISCSI_BEGIN_REC);
+       dump_initiator(context);
+       dump_network(context);
+       dump_target(context);
+       printf("%s\n", ISCSI_END_REC);
+}
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/fwparam_ibft/fwparam.h b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/fwparam_ibft/fwparam.h
new file mode 100644 (file)
index 0000000..141def7
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
+ * USA.
+ */
+#ifndef FWPARAM_H_
+#define FWPARAM_H_
+
+#include <stdint.h>
+#include "fw_context.h"
+
+#define FILENAMESZ (1024)
+
+struct boot_context;
+
+int fwparam_sysfs_boot_info(struct boot_context *context);
+int fwparam_sysfs_get_targets(struct list_head *list);
+int fwparam_ppc_boot_info(struct boot_context *context);
+int fwparam_ppc_get_targets(struct list_head *list);
+
+#endif /* FWPARAM_IBFT_H_ */
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/fwparam_ibft/fwparam_ppc.c b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/fwparam_ibft/fwparam_ppc.c
new file mode 100644 (file)
index 0000000..7013d6c
--- /dev/null
@@ -0,0 +1,615 @@
+/*
+ * Copyright (C) IBM Corporation. 2007
+ * Author: Doug Maxey <dwm@austin.ibm.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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define         _XOPEN_SOURCE 500
+#include <ftw.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "fwparam.h"
+#include "fw_context.h"
+#include "iscsi_obp.h"
+#include "prom_parse.h"
+#include "sysdeps.h"
+#include "iscsi_err.h"
+
+void* yy_scan_string(const char *str);
+int yyparse(struct ofw_dev *ofwdev);
+
+#define BOOTPATH "/chosen/bootpath"
+#define DT_TOP "/proc/device-tree"
+#define LOCAL_MAC_FILE "/local-mac-address"
+
+static int devtree_offset;
+static char *bootpath_val;
+static int bytes_read;
+#define OFWDEV_MAX (10)
+static struct ofw_dev *ofwdevs[OFWDEV_MAX];
+static char *niclist[OFWDEV_MAX];
+static int nic_count;
+static int debug;
+static int dev_count;
+
+static void cp_param(char *dest,
+                    __attribute__((unused))const char *name,
+                    struct ofw_dev *dev,
+                    enum obp_param item, int len)
+{
+       if (dev->param[item])
+               strlcpy(dest, dev->param[item]->val, len);
+}
+
+static void cp_int_param(int *dest,
+                        __attribute__((unused))const char *name,
+                        struct ofw_dev *dev,
+                        enum obp_param item)
+{
+       if (dev->param[item])
+               *dest = strtol(dev->param[item]->val, NULL, 10);
+}
+
+static char *find_devtree(const char *filename)
+{
+       char *devtree = strdup(filename);
+       char *chop_at;
+       struct stat dt_stat;
+       int error;
+
+       /*
+        * What is the path to the device-tree?  The only valid
+        * directories to locate the property are under /aliases or
+        * /chosen.
+        */
+
+       if (!devtree)
+               return NULL;
+
+       chop_at = strstr(devtree, "/chosen");
+       if (!chop_at)
+               chop_at = strstr(devtree, "/aliases");
+
+       if (!chop_at) {
+               char *vdev = malloc(strlen(filename) + strlen("/vdevice") + 1);
+
+               /*
+                * test to see if there is /vdevice dir
+                */
+               if (vdev) {
+                       sprintf(vdev, "%s%s", filename, "/vdevice");
+                       error = stat(vdev, &dt_stat);
+                       free(vdev);
+                       if (error) {
+                               free(devtree);
+                               return NULL;
+                       }
+               }
+       } else
+               devtree[chop_at - devtree] = 0;
+
+       if (devtree)
+               devtree_offset = strlen(devtree);
+
+       return devtree;
+}
+
+/*
+ * Take the path to the property under chosen, and swizzle to make that
+ * the base for the device path discovered.
+ */
+static int locate_mac(const char *devtree, struct ofw_dev *ofwdev)
+{
+       int error = 0;
+       int mac_path_len = strlen(ofwdev->dev_path) + strlen(LOCAL_MAC_FILE) +
+               2;
+       char *mac_file;
+       int mac_fd;
+
+       mac_path_len += strlen(devtree);
+       mac_file = malloc(mac_path_len);
+       if (!mac_file) {
+               error = ENOMEM;
+               fprintf(stderr, "%s: malloc , %s\n", __func__,
+                       strerror(errno));
+               goto lpm_bail;
+       }
+
+       snprintf(mac_file, mac_path_len, "%s%s%s", devtree, ofwdev->dev_path,
+                LOCAL_MAC_FILE);
+       mac_fd = open(mac_file, O_RDONLY);
+       if (mac_fd < 0) {
+               error = errno;
+               fprintf(stderr, "%s: open %s, %s\n", __func__, mac_file,
+                       strerror(errno));
+               free(mac_file);
+               goto lpm_bail;
+       }
+
+       bytes_read = read(mac_fd, ofwdev->mac, 6);
+       if (bytes_read != 6) {
+               error = EIO;
+               fprintf(stderr, "%s: read %s, %s\n", __func__, mac_file,
+                       strerror(errno));
+       }
+       free(mac_file);
+       close(mac_fd);
+
+lpm_bail:
+       return error;
+}
+
+const char *obp_qual_set(struct ofw_dev *ofwdev, const char *qual)
+{
+       if (!strcmp("bootp", qual))
+               ofwdev->quals[ofwdev->qual_count++] = OBP_QUAL_BOOTP;
+       else if (!strcmp("dhcpv6", qual))
+               ofwdev->quals[ofwdev->qual_count++] = OBP_QUAL_DHCPV6;
+       else if (!strcmp("ipv6", qual))
+               ofwdev->quals[ofwdev->qual_count++] = OBP_QUAL_IPV6;
+       else if (!strcmp("iscsi", qual)) {
+               ofwdev->type = OFW_DT_ISCSI;
+               ofwdev->quals[ofwdev->qual_count++] = OBP_QUAL_ISCSI;
+       } else if (!strcmp("ping", qual))
+               ofwdev->quals[ofwdev->qual_count++] = OBP_QUAL_PING;
+       else
+               printf("%s: %s UNKNOWN\n", __func__, qual);
+       return qual;
+}
+
+void add_obp_parm(struct ofw_dev *ofwdev, enum obp_param parm, const char *str)
+{
+       int psz = sizeof(struct ofw_obp_param) + strlen(str);
+
+       ofwdev->param[parm] = malloc(psz);
+       if (ofwdev->param[parm] == NULL) {
+               printf("%s: ENOMEM!\n", __func__);
+               return;
+       }
+       memset(ofwdev->param[parm], 0, psz);
+       ofwdev->param[parm]->len = psz;
+       strcpy(ofwdev->param[parm]->val, str);
+}
+
+void obp_parm_addr(struct ofw_dev *ofwdev, const char *parm, const char *addr)
+{
+       if (!strcmp("ciaddr", parm))
+               add_obp_parm(ofwdev, OBP_PARAM_CIADDR, addr);
+       else if (!strcmp("dhcp", parm))
+               add_obp_parm(ofwdev, OBP_PARAM_DHCP, addr);
+       else if (!strcmp("giaddr", parm))
+               add_obp_parm(ofwdev, OBP_PARAM_GIADDR, addr);
+       else if (!strcmp("isns", parm))
+               add_obp_parm(ofwdev, OBP_PARAM_ISNS, addr);
+       else if (!strcmp("siaddr", parm))
+               add_obp_parm(ofwdev, OBP_PARAM_SIADDR, addr);
+       else if (!strcmp("slp", parm))
+               add_obp_parm(ofwdev, OBP_PARAM_SLP, addr);
+       else if (!strcmp("subnet-mask", parm))
+               add_obp_parm(ofwdev, OBP_PARAM_SUBNET_MASK, addr);
+       else
+               printf("%s: %s UNKNOWN\n", __func__, parm);
+}
+
+void obp_parm_iqn(struct ofw_dev *ofwdev, const char *parm, const char *iqn)
+{
+       if (!strcmp("itname", parm))
+               add_obp_parm(ofwdev, OBP_PARAM_ITNAME, iqn);
+       else if (!strcmp("iname", parm))
+               add_obp_parm(ofwdev, OBP_PARAM_INAME, iqn);
+       else
+               printf("%s: %s UNKNOWN\n", __func__, parm);
+}
+
+void obp_parm_hexnum(struct ofw_dev *ofwdev, const char *parm,
+                    const char *numstr)
+{
+       if (!strcmp("bootp-retries", parm))
+               add_obp_parm(ofwdev, OBP_PARAM_BOOTP_RETRIES, numstr);
+       else if (!strcmp("tftp-retries", parm))
+               add_obp_parm(ofwdev, OBP_PARAM_TFTP_RETRIES, numstr);
+       else if (!strcmp("iport", parm))
+               add_obp_parm(ofwdev, OBP_PARAM_IPORT, numstr);
+       else if (!strcmp("ilun", parm))
+               add_obp_parm(ofwdev, OBP_PARAM_ILUN, numstr);
+       else if (!strcmp("isid", parm))
+               add_obp_parm(ofwdev, OBP_PARAM_ISID, numstr);
+       else
+               printf("%s: %s UNKNOWN <%s>\n", __func__, parm, numstr);
+}
+
+void obp_parm_str(struct ofw_dev *ofwdev, const char *parm, const char *str)
+{
+       if (!strcmp("filename", parm))
+               add_obp_parm(ofwdev, OBP_PARAM_FILENAME, str);
+       else if (!strcmp("ichapid", parm))
+               add_obp_parm(ofwdev, OBP_PARAM_ICHAPID, str);
+       else if (!strcmp("ichappw", parm))
+               add_obp_parm(ofwdev, OBP_PARAM_ICHAPPW, str);
+       else if (!strcmp("chapid", parm))
+               add_obp_parm(ofwdev, OBP_PARAM_CHAPID, str);
+       else if (!strcmp("chappw", parm))
+               add_obp_parm(ofwdev, OBP_PARAM_CHAPPW, str);
+       else
+               printf("%s: %s UNKNOWN <%s>\n", __func__, parm, str);
+}
+
+void yyerror(struct ofw_dev *ofwdev,
+            __attribute__((unused))const char *msg)
+{
+       fprintf(stderr, "%s: error in <%s> at l%d.c%d\n", "fwparam_ppc",
+               ofwdev->prop_path, yylloc.last_line, yylloc.last_column);
+}
+
+static int parse_params(const char *buf, struct ofw_dev *ofwdev)
+{
+       int error = 0;
+#if YYDEBUG
+       yydebug = 1;
+#endif
+
+
+       if (yy_scan_string(buf))
+               error = yyparse(ofwdev);
+
+       return error;
+}
+
+static int find_file(const char *filename)
+{
+       int error, fd;
+       struct stat bootpath_stat;
+
+       error = stat(filename, &bootpath_stat);
+       if (error < 0) {
+               fprintf(stderr, "%s: stat %s, %s\n", __func__, filename,
+                       strerror(errno));
+               return error;
+       }
+
+       bootpath_val = malloc(bootpath_stat.st_size);
+       if (!bootpath_val) {
+               error = ENOMEM;
+               fprintf(stderr, "%s: Could not open %s: %s (%d)\n",
+                       __func__, filename, strerror(error), error);
+               return -1;
+       }
+
+       fd = open(filename, O_RDONLY);
+       if (fd < 0) {
+               fprintf(stderr, "%s: Could not open %s: %s (%d)\n",
+                       __func__, filename, strerror(errno), errno);
+               free(bootpath_val);
+               bootpath_val = NULL;
+               return -1;
+       }
+
+       bytes_read = read(fd, bootpath_val, bootpath_stat.st_size);
+       close(fd);
+       if (bytes_read != bootpath_stat.st_size) {
+               fprintf(stderr, "%s: Failed to read %s: %s (%d)\n",
+                       __func__, filename, strerror(EIO), EIO);
+               free(bootpath_val);
+               bootpath_val = NULL;
+               return -1;
+       }
+
+       return 1;
+}
+
+static int find_nics(const char *fpath,
+                    __attribute__((unused))const struct stat *sb,
+                    int tflag,
+                    struct FTW *ftw)
+{
+       if (tflag == FTW_D &&
+           (strstr(fpath + ftw->base, "iscsi-toe") ||
+            strstr(fpath + ftw->base, "ethernet"))) {
+
+               if (nic_count < OFWDEV_MAX)
+                       niclist[nic_count++] = strdup(fpath + devtree_offset);
+
+       }
+       return 0;
+}
+
+static int nic_cmp(const void *a, const void *b)
+{
+       return strcmp(a, b);
+}
+
+static int find_initiator(const char *fpath,
+                         __attribute__((unused))const struct stat *sb,
+                         int tflag,
+                         struct FTW *ftw)
+{
+       struct ofw_dev *dev;
+
+       if (tflag == FTW_F && (strstr(fpath + ftw->base,
+                                     "/aliases/iscsi-disk"))) {
+
+               if (dev_count < OFWDEV_MAX) {
+                       dev = calloc(sizeof(struct ofw_dev), 1);
+                       if (!dev)
+                               return -ENOMEM;
+
+                       dev->prop_path = strdup(fpath + devtree_offset);
+                       if (!dev->prop_path) {
+                               free(dev);
+                               return errno;
+                       }
+                       ofwdevs[dev_count++] = dev;
+               }
+       }
+       return 0;
+}
+
+static int loop_devs(const char *devtree)
+{
+       int error;
+       int i;
+       char prefix[256];
+
+       nic_count = 0;
+       error = nftw(devtree, find_nics, 20, 0);
+       if (error)
+               return error;
+
+       /*
+        * Sort the nics into "natural" order.  The proc fs
+        * device-tree has them in somewhat random, or reversed order.
+        */
+       qsort(niclist, nic_count, sizeof(char *), nic_cmp);
+
+       snprintf(prefix, sizeof(prefix), "%s/%s", devtree, "aliases");
+       dev_count = 0;
+       error = nftw(prefix, find_initiator, 20, 0);
+       if (error)
+               return error;
+
+       for (i = 0; i < dev_count; i++) {
+               snprintf(prefix, sizeof(prefix), "%s%s", devtree,
+                        ofwdevs[i]->prop_path);
+               if (find_file(prefix) > 0) {
+                       error = parse_params(bootpath_val, ofwdevs[i]);
+                       if (!error)
+                               error = locate_mac(devtree, ofwdevs[i]);
+
+                       free(bootpath_val);
+                       bootpath_val = NULL;
+               }
+       }
+       return error;
+}
+
+#define set_context(fld,abrv,item)                                     \
+       cp_param(context->fld, (abrv), ofwdev, (item), sizeof(context->fld))
+#define set_int_context(fld,abrv,item)                                     \
+       cp_int_param(&context->fld, (abrv), ofwdev, (item))
+
+static void fill_context(struct boot_context *context, struct ofw_dev *ofwdev)
+{
+       int ndx;
+
+       memset(context, 0, sizeof(*context));
+
+       set_context(initiatorname, "NAME", OBP_PARAM_ITNAME);
+
+       snprintf(context->mac, sizeof(context->mac),
+                "%02x:%02x:%02x:%02x:%02x:%02x",
+                ofwdev->mac[0], ofwdev->mac[1], ofwdev->mac[2],
+                ofwdev->mac[3], ofwdev->mac[4], ofwdev->mac[5]);
+
+       /*
+        * nic parameters
+        */
+       for (ndx = 0; ndx < nic_count; ndx++) {
+               if (!strcmp(niclist[ndx], ofwdev->dev_path)) {
+                       snprintf(context->iface, sizeof(context->iface),
+                                "eth%d", ndx);
+                       break;
+               }
+       }
+
+       set_context(ipaddr, "IPADDR", OBP_PARAM_CIADDR);
+       set_context(mask, "MASK", OBP_PARAM_SUBNET_MASK);
+
+       /*
+        * target parameters
+        */
+       set_context(target_ipaddr, "IPADDR", OBP_PARAM_SIADDR);
+       set_int_context(target_port, "PORT", OBP_PARAM_IPORT);
+       set_context(lun, "LUN", OBP_PARAM_ILUN);
+       set_context(targetname, "NAME", OBP_PARAM_INAME);
+       set_context(isid, "ISID", OBP_PARAM_ISID);
+
+       /*
+        * chap stuff is always associated with the target
+        */
+       set_context(chap_name, "CHAP_NAME", OBP_PARAM_ICHAPID);
+       set_context(chap_password, "CHAP_PASSWORD", OBP_PARAM_ICHAPPW);
+       set_context(chap_name_in, "CHAP_NAME_IN", OBP_PARAM_CHAPID);
+       set_context(chap_password_in, "CHAP_PASSWORD_IN", OBP_PARAM_CHAPPW);
+
+}
+
+int fwparam_ppc_boot_info(struct boot_context *context)
+{
+       char filename[FILENAMESZ];
+       int error;
+       char *devtree;
+       int i;
+
+       /*
+        * For powerpc, our operations are fundamentally to locate
+        * either the one boot target (the singleton disk), or to find
+        * the nics that support iscsi boot.  The only nics in IBM
+        * systems that can support iscsi are the ones that provide
+        * the appropriate FCODE with a load method.
+        */
+       memset(filename, 0, FILENAMESZ);
+       snprintf(filename, FILENAMESZ, "%s%s", DT_TOP, BOOTPATH);
+
+       if (debug)
+               fprintf(stderr, "%s: file:%s; debug:%d\n", __func__, filename,
+                       debug);
+
+       devtree = find_devtree(filename);
+       if (!devtree)
+               return ISCSI_ERR_INVAL;
+
+       /*
+        * Always search the device-tree to find the capable nic devices.
+        */
+       error = loop_devs(devtree);
+       if (error)
+               goto free_devtree;
+
+       if (find_file(filename) < 1) {
+               error = ISCSI_ERR_NO_OBJS_FOUND;
+               goto free_devtree;
+       } else {
+               if (debug)
+                       printf("%s:\n%s\n\n", filename, bootpath_val);
+               /*
+                * We find *almost* everything we need in the
+                * bootpath, save the mac-address.
+                */
+
+               if (!strstr(bootpath_val, "iscsi")) {
+                       error = ISCSI_ERR_INVAL;
+                       goto free_bootpath_val;
+               }
+               ofwdevs[0] = calloc(1, sizeof(struct ofw_dev));
+               if (!ofwdevs[0]) {
+                       error = ISCSI_ERR_NOMEM;
+                       goto free_bootpath_val;
+               }
+
+               error = parse_params(bootpath_val, ofwdevs[0]);
+               if (!error)
+                       error = locate_mac(devtree, ofwdevs[0]);
+               if (!error) {
+                       if (!context)
+                               error = ISCSI_ERR_NOMEM;
+                       else
+                               fill_context(context, ofwdevs[0]);
+               }
+               free(ofwdevs[0]);
+       }
+
+free_bootpath_val:
+       free(bootpath_val);
+       bootpath_val = NULL;
+
+free_devtree:
+       free(devtree);
+       for (i = 0; i < dev_count; i++)
+               if (ofwdevs[i])
+                       free(ofwdevs[i]);
+
+       return error;
+}
+
+/*
+ * Due to lack of time this is just fwparam_ppc_boot_info which
+ * adds the target used for boot to the list. It does not add
+ * all possible targets (IBM please add).
+ */
+int fwparam_ppc_get_targets(struct list_head *list)
+{
+       char filename[FILENAMESZ];
+       struct boot_context *context;
+       int error;
+       char *devtree;
+       int i;
+
+       /*
+        * For powerpc, our operations are fundamentally to locate
+        * either the one boot target (the singleton disk), or to find
+        * the nics that support iscsi boot.  The only nics in IBM
+        * systems that can support iscsi are the ones that provide
+        * the appropriate FCODE with a load method.
+        */
+       memset(filename, 0, FILENAMESZ);
+       snprintf(filename, FILENAMESZ, "%s%s", DT_TOP, BOOTPATH);
+
+       if (debug)
+               fprintf(stderr, "%s: file:%s; debug:%d\n", __func__, filename,
+                       debug);
+
+       devtree = find_devtree(filename);
+       if (!devtree)
+               return ISCSI_ERR_INVAL;
+
+       /*
+        * Always search the device-tree to find the capable nic devices.
+        */
+       error = loop_devs(devtree);
+       if (error)
+               goto free_devtree;
+
+       if (find_file(filename) < 1) {
+               error = ISCSI_ERR_NO_OBJS_FOUND;
+               goto free_devtree;
+       } else {
+               if (debug)
+                       printf("%s:\n%s\n\n", filename, bootpath_val);
+               /*
+                * We find *almost* everything we need in the
+                * bootpath, save the mac-address.
+                */
+
+               if (!strstr(bootpath_val, "iscsi")) {
+                       error = ISCSI_ERR_INVAL;
+                       goto free_bootpath_val;
+               }
+               ofwdevs[0] = calloc(1, sizeof(struct ofw_dev));
+               if (!ofwdevs[0]) {
+                       error = ISCSI_ERR_NOMEM;
+                       goto free_bootpath_val;
+               }
+
+               error = parse_params(bootpath_val, ofwdevs[0]);
+               if (!error)
+                       error = locate_mac(devtree, ofwdevs[0]);
+               if (!error) {
+                       context = calloc(1, sizeof(*context));
+                       if (!context)
+                               error = ISCSI_ERR_NOMEM;
+                       else {
+                               fill_context(context, ofwdevs[0]);
+                               list_add_tail(&context->list, list);
+                       }
+               }
+               free(ofwdevs[0]);
+       }
+free_bootpath_val:
+       free(bootpath_val);
+       bootpath_val = NULL;
+
+free_devtree:
+       free(devtree);
+       for (i = 0; i < dev_count; i++)
+               if (ofwdevs[i])
+                       free(ofwdevs[i]);
+
+       return error;
+}
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/fwparam_ibft/fwparam_sysfs.c b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/fwparam_ibft/fwparam_sysfs.c
new file mode 100644 (file)
index 0000000..f46e8f2
--- /dev/null
@@ -0,0 +1,533 @@
+/*
+ * Copyright (C) IBM Corporation. 2007
+ * Author: Konrad Rzeszutek <konradr@linux.vnet.ibm.com>
+ * Copyright (C) Red Hat, Inc.  All rights reserved. 2008 - 2010
+ * Copyright (C) Mike Christie 2008 - 2010
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define  _XOPEN_SOURCE 500
+#define _DEFAULT_SOURCE
+#include <ftw.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <dirent.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "sysfs.h"
+#include "fw_context.h"
+#include "fwparam.h"
+#include "sysdeps.h"
+#include "iscsi_net_util.h"
+#include "iscsi_err.h"
+
+#define ISCSI_BOOT_MAX         255
+#define IBFT_SYSFS_ROOT                "/sys/firmware/ibft/"
+#define IBFT_SUBSYS            "ibft"
+
+#define ISCSI_LLD_ROOT         "/sys/firmware/"
+#define ISCSI_LLD_SUBSYS_PREFIX        "iscsi_boot"
+
+static char *target_list[ISCSI_BOOT_MAX];
+static char *nic_list[ISCSI_BOOT_MAX];
+static int nic_cnt;
+static int tgt_cnt;
+
+static int file_exist(const char *file)
+{
+       struct stat bootpath_stat;
+
+       return !stat(file, &bootpath_stat);
+}
+
+/*
+ * Finds the etherrnetX and targetX under the sysfs directory.
+ */
+static int find_sysfs_dirs(const char *fpath,
+                          __attribute__((unused))const struct stat *sb,
+                          int tflag,
+                          struct FTW *ftw)
+{
+       if (tflag == FTW_D && (strstr(fpath + ftw->base, "target"))) {
+               if (tgt_cnt == ISCSI_BOOT_MAX) {
+                       printf("Too many targets found in iSCSI boot data."
+                              "Max number of targets %d\n", ISCSI_BOOT_MAX);
+                       return 0;
+               }
+               target_list[tgt_cnt++] = strdup(strstr(fpath, "target"));
+       }
+
+       if (tflag == FTW_D && (strstr(fpath + ftw->base, "ethernet"))) {
+               if (nic_cnt == ISCSI_BOOT_MAX) {
+                       printf("Too many nics found in iSCSI boot data."
+                              "Max number of nics %d\n", ISCSI_BOOT_MAX);
+                       return 0;
+               }
+               nic_list[nic_cnt++] = strdup(strstr(fpath, "ethernet"));
+       }
+
+       return 0;
+}
+static int get_iface_from_device(char *id, struct boot_context *context)
+{
+       char dev_dir[FILENAMESZ];
+       int rc = ENODEV;
+       DIR *dirfd;
+       struct dirent *dent;
+
+       memset(dev_dir, 0, FILENAMESZ);
+       snprintf(dev_dir, FILENAMESZ, IBFT_SYSFS_ROOT"/%s/device", id);
+
+       if (!file_exist(dev_dir))
+               return 0;
+
+       dirfd = opendir(dev_dir);
+       if (!dirfd)
+               return errno;
+
+       while ((dent = readdir(dirfd))) {
+               if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..") ||
+                   strncmp(dent->d_name, "net:", 4))
+                       continue;
+
+               if (!strncmp(dent->d_name, "net:", 4)) {
+                       if ((strlen(dent->d_name) - 4) >
+                           (sizeof(context->iface) - 1)) {
+                               rc = EINVAL;
+                               printf("Net device %s too big for iface "
+                                      "buffer.\n", dent->d_name);
+                               break;
+                       }
+
+                       if (sscanf(dent->d_name, "net:%s", context->iface) != 1) {
+                               rc = EINVAL;
+                               break;
+                       }
+
+                       rc = 0;
+                       break;
+               } else {
+                       printf("Could not read ethernet to net link.\n");
+                       rc = EOPNOTSUPP;
+                       break;
+               }
+       }
+
+       closedir(dirfd);
+
+       if (rc != ENODEV)
+               return rc;
+
+       /* If not found try again with newer kernel networkdev sysfs layout */
+       strlcat(dev_dir, "/net", FILENAMESZ);
+
+       if (!file_exist(dev_dir))
+               return rc;
+
+       dirfd = opendir(dev_dir);
+       if (!dirfd)
+               return errno;
+
+       while ((dent = readdir(dirfd))) {
+               if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
+                       continue;
+
+               /* Take the first "regular" directory entry */
+               if (strlen(dent->d_name) > (sizeof(context->iface) - 1)) {
+                       rc = EINVAL;
+                       printf("Net device %s too big for iface buffer.\n",
+                              dent->d_name);
+                       break;
+               }
+
+               strcpy(context->iface, dent->d_name);
+               rc = 0;
+               break;
+       }
+
+       closedir(dirfd);
+       return rc;
+}
+
+/*
+ * Routines to fill in the context values.
+ */
+static int fill_nic_context(char *subsys, char *id,
+                           struct boot_context *context)
+{
+       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)
+               return rc;
+
+       /*
+        * Some offload cards like bnx2i use different MACs for the net and
+        * iscsi functions, so we have to follow the sysfs links.
+        *
+        * Other ibft implementations may not be tied to a pci function,
+        * so there will not be any device/net link, so we drop down to
+        * the MAC matching.
+        *
+        * And finally, some cards like be2iscsi and qla4xxx do not have
+        * any linux network subsys representation. These hosts will
+        * not have the ibft subsys. Instead the subsys is the scsi host
+        * number.
+        */
+       if (!strcmp(IBFT_SUBSYS, subsys)) {
+               rc = get_iface_from_device(id, context);
+               if (rc) {
+                       rc = net_get_netdev_from_hwaddress(context->mac,
+                                                          context->iface);
+                       if (rc)
+                               return rc;
+               }
+       } else
+               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,
+                     sizeof(context->vlan));
+       sysfs_get_str(id, subsys, "subnet-mask", context->mask,
+                     sizeof(context->mask));
+       sysfs_get_int(id, subsys, "prefix-len", &context->prefix);
+       sysfs_get_str(id, subsys, "gateway", context->gateway,
+                     sizeof(context->gateway));
+       sysfs_get_str(id, subsys, "primary-dns", context->primary_dns,
+                     sizeof(context->primary_dns));
+       sysfs_get_str(id, subsys, "secondary-dns", context->secondary_dns,
+                     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;
+}
+
+static void fill_initiator_context(char *subsys, struct boot_context *context)
+{
+       sysfs_get_str("initiator", subsys, "initiator-name",
+                     context->initiatorname,
+                     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)
+               return rc;
+
+       rc = sysfs_get_str(id, subsys, "ip-addr", context->target_ipaddr,
+                          sizeof(context->target_ipaddr));
+       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.
+        */
+       if (sysfs_get_int(id, subsys, "port", &context->target_port))
+               context->target_port = ISCSI_LISTEN_PORT;
+
+       sysfs_get_str(id, subsys, "lun", context->lun,
+                     sizeof(context->lun));
+       sysfs_get_str(id, subsys, "chap-name", context->chap_name,
+                     sizeof(context->chap_name));
+       sysfs_get_str(id, subsys, "chap-secret", context->chap_password,
+                     sizeof(context->chap_password));
+       sysfs_get_str(id, subsys, "rev-chap-name", context->chap_name_in,
+                     sizeof(context->chap_name_in));
+       sysfs_get_str(id, subsys, "rev-chap-name-secret",
+                     context->chap_password_in,
+                     sizeof(context->chap_password_in));
+       return 0;
+}
+
+#define IBFT_SYSFS_FLAG_FW_SEL_BOOT 2
+
+static int find_boot_flag(char *subsys, char *list[], ssize_t size,
+                         int *boot_idx)
+{
+       int rc = ENODEV;
+       int i, flag = 0;
+
+       for (i = 0; i < size; i++, flag = -1) {
+               rc = sysfs_get_int(list[i], subsys, "flags", &flag);
+               if (rc)
+                       continue;
+
+               if (flag & IBFT_SYSFS_FLAG_FW_SEL_BOOT) {
+                       *boot_idx = i;
+                       rc = 0;
+                       break;
+               }
+               rc = ENODEV;
+               flag = 0;
+
+       }
+
+       return rc;
+}
+
+static void deallocate_lists(void)
+{
+       int i;
+
+       for (i = 0; i < nic_cnt; i++)
+               free(nic_list[i]);
+
+       nic_cnt = 0;
+       for (i = 0; i < tgt_cnt; i++)
+               free(target_list[i]);
+
+       tgt_cnt = 0;
+
+}
+
+static int get_boot_info(struct boot_context *context, char *rootdir,
+                        char *subsys)
+{
+       char initiator_dir[FILENAMESZ];
+       int rc = ENODEV;
+       int nic_idx = -1, tgt_idx = -1;
+
+       memset(&initiator_dir, 0 , FILENAMESZ);
+       snprintf(initiator_dir, FILENAMESZ, "%sinitiator", rootdir);
+
+       nic_cnt = 0;
+       tgt_cnt = 0;
+       if (file_exist(initiator_dir)) {
+               /* Find the targets and the ethernets */
+               rc = nftw(rootdir, find_sysfs_dirs, 20, 1);
+
+               /* Find wihch target and which ethernet have
+               the boot flag set. */
+               rc = find_boot_flag(subsys, nic_list, nic_cnt, &nic_idx);
+               if (rc)
+                       goto free;
+
+               rc = find_boot_flag(subsys, target_list, tgt_cnt, &tgt_idx);
+               if (rc)
+                       goto free;
+
+               /* Fill in the context values */
+               rc = fill_nic_context(subsys, nic_list[nic_idx], context);
+               rc |= fill_tgt_context(subsys, target_list[tgt_idx], context);
+               fill_initiator_context(subsys, context);
+       }
+free:
+       deallocate_lists();
+       return rc;
+}
+
+int fwparam_sysfs_boot_info(struct boot_context *context)
+{
+       struct dirent *dent;
+       DIR *dirfd;
+       int rc = 0;
+
+       if (!get_boot_info(context, IBFT_SYSFS_ROOT, IBFT_SUBSYS))
+               return 0;
+       /*
+        * We could have multiple iscsi llds and each lld could have
+        * multiple targets/ethernet ports
+        */
+       dirfd = opendir(ISCSI_LLD_ROOT);
+       if (!dirfd)
+               return ISCSI_ERR_SYSFS_LOOKUP;
+
+       while ((dent = readdir(dirfd))) {
+               char lld_root[FILENAMESZ];
+
+               memset(&lld_root, 0 , FILENAMESZ);
+
+               if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
+                       continue;
+
+               if (strncmp(dent->d_name, ISCSI_LLD_SUBSYS_PREFIX, 10))
+                       continue;
+
+               snprintf(lld_root, FILENAMESZ, ISCSI_LLD_ROOT"%s/",
+                        dent->d_name);
+               if (!get_boot_info(context, lld_root, dent->d_name))
+                       goto done;
+       }
+       rc = ISCSI_ERR_NO_OBJS_FOUND;
+done:
+       closedir(dirfd);
+       return rc;
+}
+
+static int get_targets(struct list_head *list, char *rootdir, char *subsys)
+{
+       struct boot_context *context;
+       int rc = 0, i, nic_idx, nic;
+       char initiator_dir[FILENAMESZ];
+
+       memset(&initiator_dir, 0 , FILENAMESZ);
+       snprintf(initiator_dir, FILENAMESZ, "%sinitiator", rootdir);
+
+       if (!file_exist(initiator_dir))
+               return ENODEV;
+
+       nic_cnt = 0;
+       tgt_cnt = 0;
+
+       /* 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));
+               if (!context) {
+                       rc = ENOMEM;
+                       break;
+               }
+
+               rc = fill_tgt_context(subsys, target_list[i], context);
+               if (rc)
+                       goto cleanup;
+
+               rc = sysfs_get_int(target_list[i], subsys, "nic-assoc",
+                                  &nic_idx);
+               if (rc)
+                       goto cleanup;
+
+               for (nic = 0; nic < nic_cnt; nic++) {
+                       int id;
+
+                       rc = sysfs_get_int(nic_list[nic], subsys, "index",
+                                          &id);
+                       if (!rc && (id == nic_idx))
+                               break;
+               }
+
+               if (nic == nic_cnt) {
+                       printf("Invalid nic-assoc of %d. Max id %d.\n",
+                              nic_idx, nic_cnt);
+                       goto cleanup;
+               }
+
+               rc = fill_nic_context(subsys, nic_list[nic], context);
+               if (rc)
+                       goto cleanup;
+
+               fill_initiator_context(subsys, context);
+               list_add_tail(&context->list, list);
+               continue;
+cleanup:
+               free(context);
+               context = NULL;
+       }
+
+       if (rc) {
+               if (context)
+                       free(context);
+               /*
+                * If there are some valid targets return them. Most likely,
+                * the driver/ibft-implementation reported partial info
+                * for targets/initiators that were not used for boot.
+                */
+               if (!list_empty(list))
+                       rc = 0;
+       }
+
+       deallocate_lists();
+       return rc;
+}
+
+int fwparam_sysfs_get_targets(struct list_head *list)
+{
+       struct dirent *dent;
+       DIR *dirfd;
+       int rc = 0;
+
+       /* ibft only has one instance */
+       get_targets(list, IBFT_SYSFS_ROOT, IBFT_SUBSYS);
+       /*
+        * We could have multiple iscsi llds and each lld could have
+        * multiple targets/ethernet ports
+        */
+       dirfd = opendir(ISCSI_LLD_ROOT);
+       if (!dirfd) {
+               rc = ISCSI_ERR_SYSFS_LOOKUP;
+               goto done;
+       }
+
+       while ((dent = readdir(dirfd))) {
+               char lld_root[FILENAMESZ];
+
+               memset(&lld_root, 0 , FILENAMESZ);
+               if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
+                       continue;
+
+               if (strncmp(dent->d_name, ISCSI_LLD_SUBSYS_PREFIX, 10))
+                       continue;
+
+               snprintf(lld_root, FILENAMESZ, ISCSI_LLD_ROOT"%s/",
+                        dent->d_name);
+               get_targets(list, lld_root, dent->d_name);
+       }
+       closedir(dirfd);
+done:
+       if (!rc && list_empty(list))
+               rc = ISCSI_ERR_NO_OBJS_FOUND;
+       if (rc)
+               fw_free_targets(list);
+       return rc;
+}
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/fwparam_ibft/iscsi_obp.h b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/fwparam_ibft/iscsi_obp.h
new file mode 100644 (file)
index 0000000..8580052
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) IBM Corporation. 2007
+ * Author: Doug Maxey <dwm@austin.ibm.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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef ISCSI_OBP_H_
+#define ISCSI_OBP_H_
+
+enum  ofw_dev_type {
+       OFW_DT_NONE,
+       OFW_DT_BLOCK,
+       OFW_DT_NETWORK,
+       OFW_DT_ISCSI,
+};
+
+enum obp_tftp_qual {
+       OBP_QUAL_NONE,
+       OBP_QUAL_BOOTP,
+       OBP_QUAL_DHCPV6,
+       OBP_QUAL_IPV6,
+       OBP_QUAL_ISCSI,
+       OBP_QUAL_PING,
+       OBP_QUAL_COUNT,         /* Numnber of defined OBP qualifiers */
+};
+
+enum obp_param {
+       /*
+        * Defined iscsi boot parameters.
+        */
+       OBP_PARAM_NONE,
+       OBP_PARAM_BLKSIZE,      /* default is 512 */
+       OBP_PARAM_BOOTP_RETRIES, /* default 5 */
+       OBP_PARAM_CHAPID,       /* target chap id */
+       OBP_PARAM_CHAPPW,       /* target chap password */
+       OBP_PARAM_CIADDR,       /* client (my) ip addr */
+       OBP_PARAM_DHCP,         /* dhcp server address */
+       OBP_PARAM_FILENAME,     /* boot filename */
+       OBP_PARAM_GIADDR,       /* gateway addr */
+       OBP_PARAM_ICHAPID,      /* initiator chapid */
+       OBP_PARAM_ICHAPPW,      /* initiator chap password */
+       OBP_PARAM_ILUN,         /* misnomer, really the target lun */
+       OBP_PARAM_INAME,        /* NB: target iqn */
+       OBP_PARAM_IPORT,        /* initiator port, defaults to 3260 */
+       OBP_PARAM_ISID,         /* session id */
+       OBP_PARAM_ISNS,         /* sns server address */
+       OBP_PARAM_ITNAME,       /* NB: Initiator iqn */
+       OBP_PARAM_SIADDR,       /* iscsi server ip address. */
+       OBP_PARAM_SLP,          /* slp server address */
+       OBP_PARAM_SUBNET_MASK,
+       OBP_PARAM_TFTP_RETRIES, /* default 5 */
+       OBP_PARAM_TIMEOUT,      /* ping timeout period. */
+
+       OBP_PARAM_COUNT,        /* number of defined OBP_PARAMs */
+};
+
+struct ofw_obp_param {
+       unsigned char  len;     /* length of value string. */
+       char           val[1];  /* string value from the property */
+};
+
+struct ofw_dev {
+       char *prop_path; /* where we found these properties. */
+       enum ofw_dev_type type; /* known type of boot device. */
+       int qual_count;         /* count of qualifiers. */
+       enum obp_tftp_qual quals[OBP_QUAL_COUNT];
+       struct ofw_obp_param *param[OBP_PARAM_COUNT];
+       int cfg_part;           /* boot partition number. */
+       char *dev_path;         /* path to this ofw device. */
+       unsigned char mac[6];   /* The binary mac address. */
+};
+
+const char *obp_qual_set(struct ofw_dev *ofwdev, const char *qual);
+void add_obp_parm(struct ofw_dev *ofwdev, enum obp_param parm, const char *str);
+void obp_parm_addr(struct ofw_dev *ofwdev, const char *parm, const char *addr);
+void obp_parm_iqn(struct ofw_dev *ofwdev, const char *parm, const char *iqn);
+void obp_parm_hexnum(struct ofw_dev *ofwdev, const char *parm,
+                    const char *numstr);
+void obp_parm_str(struct ofw_dev *ofwdev, const char *parm, const char *str);
+
+#endif /* ISCSI_OBP_H_ */
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/fwparam_ibft/prom_lex.c b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/fwparam_ibft/prom_lex.c
new file mode 100644 (file)
index 0000000..c8ed9cb
--- /dev/null
@@ -0,0 +1,2298 @@
+
+#line 3 "<stdout>"
+
+#define  YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+#define YY_FLEX_SUBMINOR_VERSION 35
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* First, we deal with  platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types. 
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t; 
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN               (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN              (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN              (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX               (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX              (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX              (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX              (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX             (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX             (4294967295U)
+#endif
+
+#endif /* ! C99 */
+
+#endif /* ! FLEXINT_H */
+
+#ifdef __cplusplus
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else  /* ! __cplusplus */
+
+/* C99 requires __STDC__ to be defined as 1. */
+#if defined (__STDC__)
+
+#define YY_USE_CONST
+
+#endif /* defined (__STDC__) */
+#endif /* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index.  If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* Enter a start condition.  This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN (yy_start) = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state.  The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START (((yy_start) - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE yyrestart(yyin  )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k.
+ * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case.
+ * Ditto for the __ia64__ case accordingly.
+ */
+#define YY_BUF_SIZE 32768
+#else
+#define YY_BUF_SIZE 16384
+#endif /* __ia64__ */
+#endif
+
+/* The state buf must be large enough to hold one state per character in the main buffer.
+ */
+#define YY_STATE_BUF_SIZE   ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+extern int yyleng;
+
+extern FILE *yyin, *yyout;
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+    #define YY_LESS_LINENO(n)
+    
+/* Return all but the first "n" matched characters back to the input stream. */
+#define yyless(n) \
+       do \
+               { \
+               /* Undo effects of setting up yytext. */ \
+        int yyless_macro_arg = (n); \
+        YY_LESS_LINENO(yyless_macro_arg);\
+               *yy_cp = (yy_hold_char); \
+               YY_RESTORE_YY_MORE_OFFSET \
+               (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
+               YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+               } \
+       while ( 0 )
+
+#define unput(c) yyunput( c, (yytext_ptr)  )
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+       {
+       FILE *yy_input_file;
+
+       char *yy_ch_buf;                /* input buffer */
+       char *yy_buf_pos;               /* current position in input buffer */
+
+       /* Size of input buffer in bytes, not including room for EOB
+        * characters.
+        */
+       yy_size_t yy_buf_size;
+
+       /* Number of characters read into yy_ch_buf, not including EOB
+        * characters.
+        */
+       int yy_n_chars;
+
+       /* Whether we "own" the buffer - i.e., we know we created it,
+        * and can realloc() it to grow it, and should free() it to
+        * delete it.
+        */
+       int yy_is_our_buffer;
+
+       /* Whether this is an "interactive" input source; if so, and
+        * if we're using stdio for input, then we want to use getc()
+        * instead of fread(), to make sure we stop fetching input after
+        * each newline.
+        */
+       int yy_is_interactive;
+
+       /* Whether we're considered to be at the beginning of a line.
+        * If so, '^' rules will be active on the next match, otherwise
+        * not.
+        */
+       int yy_at_bol;
+
+    int yy_bs_lineno; /**< The line count. */
+    int yy_bs_column; /**< The column count. */
+    
+       /* Whether to try to fill the input buffer when we reach the
+        * end of it.
+        */
+       int yy_fill_buffer;
+
+       int yy_buffer_status;
+
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+       /* When an EOF's been seen but there's still some text to process
+        * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+        * shouldn't try reading from the input source any more.  We might
+        * still have a bunch of tokens to match, though, because of
+        * possible backing-up.
+        *
+        * When we actually see the EOF, we change the status to "new"
+        * (via yyrestart()), so that the user can continue scanning by
+        * just pointing yyin at a new input file.
+        */
+#define YY_BUFFER_EOF_PENDING 2
+
+       };
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+/* Stack of input buffers. */
+static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */
+static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */
+static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ *
+ * Returns the top of the stack, or NULL.
+ */
+#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \
+                          ? (yy_buffer_stack)[(yy_buffer_stack_top)] \
+                          : NULL)
+
+/* Same as previous macro, but useful when we know that the buffer stack is not
+ * NULL or when we need an lvalue. For internal use only.
+ */
+#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)]
+
+/* yy_hold_char holds the character lost when yytext is formed. */
+static char yy_hold_char;
+static int yy_n_chars;         /* number of characters read into yy_ch_buf */
+int yyleng;
+
+/* Points to current character in buffer. */
+static char *yy_c_buf_p = (char *) 0;
+static int yy_init = 0;                /* whether we need to initialize */
+static int yy_start = 0;       /* start state number */
+
+/* Flag which is used to allow yywrap()'s to do buffer switches
+ * instead of setting up a fresh yyin.  A bit of a hack ...
+ */
+static int yy_did_buffer_switch_on_eof;
+
+void yyrestart (FILE *input_file  );
+void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer  );
+YY_BUFFER_STATE yy_create_buffer (FILE *file,int size  );
+void yy_delete_buffer (YY_BUFFER_STATE b  );
+void yy_flush_buffer (YY_BUFFER_STATE b  );
+void yypush_buffer_state (YY_BUFFER_STATE new_buffer  );
+void yypop_buffer_state (void );
+
+static void yyensure_buffer_stack (void );
+static void yy_load_buffer_state (void );
+static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file  );
+
+#define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER )
+
+YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size  );
+YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str  );
+YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,int len  );
+
+void *yyalloc (yy_size_t  );
+void *yyrealloc (void *,yy_size_t  );
+void yyfree (void *  );
+
+#define yy_new_buffer yy_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+       { \
+       if ( ! YY_CURRENT_BUFFER ){ \
+        yyensure_buffer_stack (); \
+               YY_CURRENT_BUFFER_LVALUE =    \
+            yy_create_buffer(yyin,YY_BUF_SIZE ); \
+       } \
+       YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+       }
+
+#define yy_set_bol(at_bol) \
+       { \
+       if ( ! YY_CURRENT_BUFFER ){\
+        yyensure_buffer_stack (); \
+               YY_CURRENT_BUFFER_LVALUE =    \
+            yy_create_buffer(yyin,YY_BUF_SIZE ); \
+       } \
+       YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+       }
+
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+/* Begin user sect3 */
+
+#define yywrap(n) 1
+#define YY_SKIP_YYWRAP
+
+typedef unsigned char YY_CHAR;
+
+FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0;
+
+typedef int yy_state_type;
+
+extern int yylineno;
+
+int yylineno = 1;
+
+extern char yytext[];
+
+static yy_state_type yy_get_previous_state (void );
+static yy_state_type yy_try_NUL_trans (yy_state_type current_state  );
+static int yy_get_next_buffer (void );
+static void yy_fatal_error (yyconst char msg[]  );
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+       (yytext_ptr) = yy_bp; \
+       yyleng = (size_t) (yy_cp - yy_bp); \
+       (yy_hold_char) = *yy_cp; \
+       *yy_cp = '\0'; \
+       if ( yyleng >= YYLMAX ) \
+               YY_FATAL_ERROR( "token too large, exceeds YYLMAX" ); \
+       yy_flex_strncpy( yytext, (yytext_ptr), yyleng + 1 ); \
+       (yy_c_buf_p) = yy_cp;
+
+#define YY_NUM_RULES 17
+#define YY_END_OF_BUFFER 18
+/* This struct is not used in this scanner,
+   but its presence is necessary. */
+struct yy_trans_info
+       {
+       flex_int32_t yy_verify;
+       flex_int32_t yy_nxt;
+       };
+static yyconst flex_int16_t yy_accept[444] =
+    {   0,
+        0,    0,   18,   16,   15,   15,   12,   12,   16,   12,
+       12,   12,   12,   12,   12,   16,   16,   16,   16,   16,
+       16,   16,   16,   16,   16,   15,    0,   12,   12,   14,
+        0,    0,    0,   12,    0,    0,   12,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,   10,    0,
+        0,    0,    0,    0,    0,    0,   12,   12,   14,    7,
+        0,    0,    0,    0,    0,    4,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,   11,    0,
+
+        0,    0,    0,    0,   12,    0,    0,    0,    0,    0,
+       11,    0,    0,    0,    0,    0,    0,    0,    6,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+       13,    0,    0,    6,    0,    0,    0,    0,    0,    0,
+        0,    3,    0,    9,    6,    0,    0,    5,    0,    0,
+        0,    0,    0,    0,   13,    0,    0,    0,    0,    0,
+        0,    0,    0,    9,    0,    0,    0,    0,    0,    8,
+        0,   13,    0,    0,    0,    0,    0,    9,    0,    0,
+        0,    0,    0,    0,    2,    8,   13,    1,    0,    9,
+        0,    0,    0,    0,    0,    0,    8,   13,    0,    9,
+
+        0,    0,   10,    0,    0,    0,   13,    0,    9,    0,
+        0,    0,    0,    0,   13,    0,    9,    0,    0,    0,
+       13,    0,    9,    0,    0,   13,    9,    0,    0,   13,
+        9,   13,    9,   13,    9,    9,    9,    9,    9,    9,
+        9,    9,    9,    9,    9,    9,    9,    9,    9,    9,
+        9,    9,    9,    9,    9,    9,    9,    9,    9,    9,
+        9,    9,    9,    9,    9,    9,    9,    9,    9,    9,
+        9,    9,    9,    9,    9,    9,    9,    9,    9,    9,
+        9,    9,    9,    9,    9,    9,    9,    9,    9,    9,
+        9,    9,    9,    9,    9,    9,    9,    9,    9,    9,
+
+        9,    9,    9,    9,    9,    9,    9,    9,    9,    9,
+        9,    9,    9,    9,    9,    9,    9,    9,    9,    9,
+        9,    9,    9,    9,    9,    9,    9,    9,    9,    9,
+        9,    9,    9,    9,    9,    9,    9,    9,    9,    9,
+        9,    9,    9,    9,    9,    9,    9,    9,    9,    9,
+        9,    9,    9,    9,    9,    9,    9,    9,    9,    9,
+        9,    9,    9,    9,    9,    9,    9,    9,    9,    9,
+        9,    9,    9,    9,    9,    9,    9,    9,    9,    9,
+        9,    9,    9,    9,    9,    9,    9,    9,    9,    9,
+        9,    9,    9,    9,    9,    9,    9,    9,    9,    9,
+
+        9,    9,    9,    9,    9,    9,    9,    9,    9,    9,
+        9,    9,    9,    9,    9,    9,    9,    9,    9,    9,
+        9,    9,    9,    9,    9,    9,    9,    9,    9,    9,
+        9,    9,    9,    9,    9,    9,    9,    9,    9,    9,
+        9,    9,    0
+    } ;
+
+static yyconst flex_int32_t yy_ec[256] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    2,    3,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    2,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    4,    5,    1,    6,    6,    7,
+        6,    6,    6,    8,    6,    6,    6,    9,    1,    1,
+        1,    1,    1,    1,   10,   10,   10,   10,   10,   10,
+       11,   11,   11,   11,   11,   11,   11,   11,   11,   11,
+       11,   11,   11,   11,   11,   11,   11,   11,   11,   11,
+        1,   12,    1,    1,    1,    1,   13,   14,   15,   16,
+
+       17,   18,   19,   20,   21,   11,   22,   23,   24,   25,
+       26,   27,   28,   29,   30,   31,   32,   33,   34,   11,
+       11,   35,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1
+    } ;
+
+static yyconst flex_int32_t yy_meta[36] =
+    {   0,
+        1,    1,    1,    2,    3,    4,    4,    4,    5,    4,
+        2,    6,    4,    4,    4,    4,    4,    4,    2,    2,
+        2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
+        2,    2,    2,    2,    2
+    } ;
+
+static yyconst flex_int16_t yy_base[680] =
+    {   0,
+        0,    0, 1198, 1199,   34,   36,   35, 1192,    0,   39,
+       40,   41,   47,   42,   44,   29,   67, 1176, 1182, 1179,
+     1180,   86, 1174, 1161, 1174,   51,   69,   73, 1184,    0,
+     1175, 1165, 1160,   43, 1172, 1171,   51, 1168, 1152, 1161,
+     1157, 1166, 1163, 1162, 1156, 1158, 1142, 1160,   25, 1147,
+       85, 1146, 1153, 1139, 1147, 1133, 1135, 1135, 1199, 1151,
+     1136, 1148, 1130, 1146, 1142,   80, 1153, 1152,    0, 1199,
+     1126, 1124, 1128, 1126, 1136, 1199, 1124, 1128, 1132, 1131,
+     1131, 1116, 1132, 1119, 1119, 1113, 1133, 1135, 1109, 1122,
+     1107, 1123, 1122, 1130, 1112, 1119, 1110, 1114, 1199, 1104,
+
+     1101, 1094,   97,  106,    0, 1105,   42, 1101,   94, 1108,
+     1090, 1093, 1096, 1104, 1098, 1091, 1100, 1085, 1199,    0,
+     1094, 1090, 1099, 1086, 1095, 1093, 1105, 1087,  117, 1102,
+        0, 1071, 1076,  104, 1088, 1069, 1073, 1093, 1075, 1086,
+     1069, 1199,   99,    0, 1093, 1079, 1069, 1199, 1065, 1062,
+     1063, 1076,  121,  125,    0, 1073, 1070, 1059, 1056, 1069,
+     1061, 1068, 1049,    0,  120, 1056, 1077, 1063, 1062,  131,
+     1073,    0, 1047, 1059, 1055, 1043, 1056,    0, 1046, 1050,
+     1044, 1038, 1044, 1036, 1199,  134,    0, 1199, 1035,    0,
+     1039, 1034, 1046, 1046, 1048, 1031, 1199,    0, 1030,    0,
+
+     1027, 1035, 1199, 1039, 1025, 1033,    0, 1032,    0, 1039,
+      137, 1018, 1028, 1032,    0, 1031,    0, 1018, 1025, 1015,
+        0, 1014,    0,  145,  142,    0,    0,  120,  132,    0,
+        0,    0,    0, 1199,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0, 1199, 1199,  149,  152,  156,  159,  163,  144,  166,
+      143,  170,  142,  174,  131,  178,  115,  182,  112,  186,
+       92,  190,   89,  194,   87,  198,   85,  202,   67,  206,
+       56,  210,  214,  218,  222,  226,  230,  234,  238,  242,
+      246,  250,  254,  258,  262,  266,  270,  274,  278,  282,
+      286,  290,  294,  298,  302,  306,  310,  314,  318,  322,
+
+      326,  330,  334,  338,  342,  346,  350,  354,  358,  362,
+      366,  370,  374,  378,  382,  386,  390,  394,  398,  402,
+      406,  410,  414,  418,  422,  426,  430,  434,  438,  442,
+      446,  450,  454,  458,  462,  466,  470,  474,  478,  482,
+      486,  490,  494,  498,  502,  506,  510,  514,  518,  522,
+      526,  530,  534,  538,  542,  546,  550,  554,  558,  562,
+      566,  570,  574,  578,  582,  586,  590,  594,  598,  602,
+      606,  610,  614,  618,  622,  626,  630,  634,  638,  642,
+      646,  650,  654,  658,  662,  666,  670,  674,  678,  682,
+      686,  690,  694,  698,  702,  706,  710,  714,  718,  722,
+
+      726,  730,  734,  738,  742,  746,  750,  754,  758,  762,
+      766,  770,  774,  778,  782,  786,  790,  794,  798,  802,
+      806,  810,  814,  818,  822,  826,  830,  834,  838,  842,
+      846,  850,  854,  858,  862,  866,  870,  874,  878,  882,
+      886,  890,  894,  898,  902,  906,  910,  914,  918,  922,
+      926,  930,  934,  938,  942,  946,  950,  954,  958,  962,
+      966,  970,  974,  978,  982,  986,  990,  994,  998, 1002,
+     1006, 1010, 1014, 1018, 1022, 1026, 1030, 1034, 1038
+    } ;
+
+static yyconst flex_int16_t yy_def[680] =
+    {   0,
+      443,    1,  443,  443,  443,  443,  444,  444,  445,  444,
+      444,  444,  444,  444,  444,  443,  443,  443,  443,  443,
+      443,  443,  443,  443,  443,  443,  443,  446,  446,  447,
+      443,  443,  443,  446,  443,  443,  446,  443,  443,  443,
+      443,  443,  443,  443,  443,  443,  443,  443,  443,  443,
+      443,  443,  443,  443,  443,  443,  443,  443,  443,  443,
+      443,  443,  443,  443,  443,  443,  448,  448,  447,  443,
+      443,  443,  443,  443,  443,  443,  443,  443,  443,  443,
+      443,  443,  443,  443,  443,  443,  443,  443,  443,  443,
+      443,  443,  443,  443,  443,  443,  443,  443,  443,  443,
+
+      443,  443,  443,  443,  449,  443,  443,  443,  443,  443,
+      443,  443,  443,  443,  443,  443,  443,  443,  443,  450,
+      443,  443,  443,  443,  443,  443,  443,  443,  443,  443,
+      451,  443,  443,  443,  443,  443,  443,  443,  443,  443,
+      443,  443,  443,  452,  443,  443,  443,  443,  443,  443,
+      443,  443,  443,  443,  453,  443,  443,  443,  443,  443,
+      443,  443,  443,  454,  443,  443,  443,  443,  443,  443,
+      443,  455,  443,  443,  443,  443,  443,  456,  443,  443,
+      443,  443,  443,  443,  443,  443,  457,  443,  443,  458,
+      443,  443,  443,  443,  443,  443,  443,  459,  443,  460,
+
+      443,  443,  443,  443,  443,  443,  461,  443,  462,  443,
+      443,  443,  443,  443,  463,  443,  464,  443,  443,  443,
+      465,  443,  466,  443,  443,  467,  468,  443,  443,  469,
+      470,  471,  472,  443,  473,  474,  475,  476,  477,  478,
+      479,  480,  481,  482,  483,  484,  485,  486,  487,  488,
+      489,  490,  491,  492,  493,  494,  495,  496,  497,  498,
+      499,  500,  501,  502,  503,  504,  505,  506,  507,  508,
+      509,  510,  511,  512,  513,  514,  515,  516,  517,  518,
+      519,  520,  521,  522,  523,  524,  525,  526,  527,  528,
+      529,  530,  531,  532,  533,  534,  535,  536,  537,  538,
+
+      539,  540,  541,  542,  543,  544,  545,  546,  547,  548,
+      549,  550,  551,  552,  553,  554,  555,  556,  557,  558,
+      559,  560,  561,  562,  563,  564,  565,  566,  567,  568,
+      569,  570,  571,  572,  573,  574,  575,  576,  577,  578,
+      579,  580,  581,  582,  583,  584,  585,  586,  587,  588,
+      589,  590,  591,  592,  593,  594,  595,  596,  597,  598,
+      599,  600,  601,  602,  603,  604,  605,  606,  607,  608,
+      609,  610,  611,  612,  613,  614,  615,  616,  617,  618,
+      619,  620,  621,  622,  623,  624,  625,  626,  627,  628,
+      629,  630,  631,  632,  633,  634,  635,  636,  637,  638,
+
+      639,  640,  641,  642,  643,  644,  645,  646,  647,  648,
+      649,  650,  651,  652,  653,  654,  655,  656,  657,  658,
+      659,  660,  661,  662,  663,  664,  665,  666,  667,  668,
+      669,  670,  671,  672,  673,  674,  675,  676,  677,  678,
+      679,  443,    0,  443,  443,  443,  443,  443,  443,  443,
+      443,  443,  443,  443,  443,  443,  443,  443,  443,  443,
+      443,  443,  443,  443,  443,  443,  443,  443,  443,  443,
+      443,  443,  443,  443,  443,  443,  443,  443,  443,  443,
+      443,  443,  443,  443,  443,  443,  443,  443,  443,  443,
+      443,  443,  443,  443,  443,  443,  443,  443,  443,  443,
+
+      443,  443,  443,  443,  443,  443,  443,  443,  443,  443,
+      443,  443,  443,  443,  443,  443,  443,  443,  443,  443,
+      443,  443,  443,  443,  443,  443,  443,  443,  443,  443,
+      443,  443,  443,  443,  443,  443,  443,  443,  443,  443,
+      443,  443,  443,  443,  443,  443,  443,  443,  443,  443,
+      443,  443,  443,  443,  443,  443,  443,  443,  443,  443,
+      443,  443,  443,  443,  443,  443,  443,  443,  443,  443,
+      443,  443,  443,  443,  443,  443,  443,  443,  443,  443,
+      443,  443,  443,  443,  443,  443,  443,  443,  443,  443,
+      443,  443,  443,  443,  443,  443,  443,  443,  443,  443,
+
+      443,  443,  443,  443,  443,  443,  443,  443,  443,  443,
+      443,  443,  443,  443,  443,  443,  443,  443,  443,  443,
+      443,  443,  443,  443,  443,  443,  443,  443,  443,  443,
+      443,  443,  443,  443,  443,  443,  443,  443,  443,  443,
+      443,  443,  443,  443,  443,  443,  443,  443,  443,  443,
+      443,  443,  443,  443,  443,  443,  443,  443,  443,  443,
+      443,  443,  443,  443,  443,  443,  443,  443,  443,  443,
+      443,  443,  443,  443,  443,  443,  443,  443,  443
+    } ;
+
+static yyconst flex_int16_t yy_nxt[1235] =
+    {   0,
+        4,    5,    6,    4,    4,    7,    7,    7,    4,    8,
+        4,    9,   10,   11,   12,   13,   14,   15,   16,    4,
+       17,    4,   18,    4,   19,    4,   20,    4,   21,   22,
+       23,   24,   25,    4,    4,   26,   26,   26,   26,   27,
+       28,   28,   28,  443,  443,  443,  443,  443,  443,   42,
+       86,  443,   26,   26,  133,  443,   34,   87,   43,  234,
+       35,   36,   32,   37,   41,   33,   38,   39,  134,   31,
+      232,   73,   40,   44,   66,   66,   66,   27,   67,   67,
+       67,   45,   46,   76,  103,  104,  104,  104,  230,   47,
+      226,   48,  221,   49,   50,  215,   51,   52,   57,   89,
+
+       58,   59,  129,  129,  129,   90,   60,  158,   61,   91,
+      103,  130,  130,  130,  135,  207,  159,   62,  198,  162,
+      136,  153,  154,  154,  154,  163,  170,  170,  170,  153,
+      171,  171,  171,  179,  187,  180,  186,  186,  186,  197,
+      197,  197,  203,  203,  203,  172,  155,  131,  188,  188,
+      181,   29,   29,   30,   30,   30,  229,   30,   68,   68,
+       69,   69,   69,  228,   69,  105,  105,  144,  144,  144,
+      144,  164,  164,  164,  164,  178,  178,  178,  178,  190,
+      190,  190,  190,  200,  200,  200,  200,  209,  209,  209,
+      209,  217,  217,  217,  217,  223,  223,  223,  223,  227,
+
+      227,  227,  227,  231,  231,  231,  231,  233,  233,  233,
+      233,  235,  235,  235,  235,  236,  236,  236,  236,  237,
+      237,  237,  237,  238,  238,  238,  238,  239,  239,  239,
+      239,  240,  240,  240,  240,  241,  241,  241,  241,  242,
+      242,  242,  242,  243,  243,  243,  243,  244,  244,  244,
+      244,  245,  245,  245,  245,  246,  246,  246,  246,  247,
+      247,  247,  247,  248,  248,  248,  248,  249,  249,  249,
+      249,  250,  250,  250,  250,  251,  251,  251,  251,  252,
+      252,  252,  252,  253,  253,  253,  253,  254,  254,  254,
+      254,  255,  255,  255,  255,  256,  256,  256,  256,  257,
+
+      257,  257,  257,  258,  258,  258,  258,  259,  259,  259,
+      259,  260,  260,  260,  260,  261,  261,  261,  261,  262,
+      262,  262,  262,  263,  263,  263,  263,  264,  264,  264,
+      264,  265,  265,  265,  265,  266,  266,  266,  266,  267,
+      267,  267,  267,  268,  268,  268,  268,  269,  269,  269,
+      269,  270,  270,  270,  270,  271,  271,  271,  271,  272,
+      272,  272,  272,  273,  273,  273,  273,  274,  274,  274,
+      274,  275,  275,  275,  275,  276,  276,  276,  276,  277,
+      277,  277,  277,  278,  278,  278,  278,  279,  279,  279,
+      279,  280,  280,  280,  280,  281,  281,  281,  281,  282,
+
+      282,  282,  282,  283,  283,  283,  283,  284,  284,  284,
+      284,  285,  285,  285,  285,  286,  286,  286,  286,  287,
+      287,  287,  287,  288,  288,  288,  288,  289,  289,  289,
+      289,  290,  290,  290,  290,  291,  291,  291,  291,  292,
+      292,  292,  292,  293,  293,  293,  293,  294,  294,  294,
+      294,  295,  295,  295,  295,  296,  296,  296,  296,  297,
+      297,  297,  297,  298,  298,  298,  298,  299,  299,  299,
+      299,  300,  300,  300,  300,  301,  301,  301,  301,  302,
+      302,  302,  302,  303,  303,  303,  303,  304,  304,  304,
+      304,  305,  305,  305,  305,  306,  306,  306,  306,  307,
+
+      307,  307,  307,  308,  308,  308,  308,  309,  309,  309,
+      309,  310,  310,  310,  310,  311,  311,  311,  311,  312,
+      312,  312,  312,  313,  313,  313,  313,  314,  314,  314,
+      314,  315,  315,  315,  315,  316,  316,  316,  316,  317,
+      317,  317,  317,  318,  318,  318,  318,  319,  319,  319,
+      319,  320,  320,  320,  320,  321,  321,  321,  321,  322,
+      322,  322,  322,  323,  323,  323,  323,  324,  324,  324,
+      324,  325,  325,  325,  325,  326,  326,  326,  326,  327,
+      327,  327,  327,  328,  328,  328,  328,  329,  329,  329,
+      329,  330,  330,  330,  330,  331,  331,  331,  331,  332,
+
+      332,  332,  332,  333,  333,  333,  333,  334,  334,  334,
+      334,  335,  335,  335,  335,  336,  336,  336,  336,  337,
+      337,  337,  337,  338,  338,  338,  338,  339,  339,  339,
+      339,  340,  340,  340,  340,  341,  341,  341,  341,  342,
+      342,  342,  342,  343,  343,  343,  343,  344,  344,  344,
+      344,  345,  345,  345,  345,  346,  346,  346,  346,  347,
+      347,  347,  347,  348,  348,  348,  348,  349,  349,  349,
+      349,  350,  350,  350,  350,  351,  351,  351,  351,  352,
+      352,  352,  352,  353,  353,  353,  353,  354,  354,  354,
+      354,  355,  355,  355,  355,  356,  356,  356,  356,  357,
+
+      357,  357,  357,  358,  358,  358,  358,  359,  359,  359,
+      359,  360,  360,  360,  360,  361,  361,  361,  361,  362,
+      362,  362,  362,  363,  363,  363,  363,  364,  364,  364,
+      364,  365,  365,  365,  365,  366,  366,  366,  366,  367,
+      367,  367,  367,  368,  368,  368,  368,  369,  369,  369,
+      369,  370,  370,  370,  370,  371,  371,  371,  371,  372,
+      372,  372,  372,  373,  373,  373,  373,  374,  374,  374,
+      374,  375,  375,  375,  375,  376,  376,  376,  376,  377,
+      377,  377,  377,  378,  378,  378,  378,  379,  379,  379,
+      379,  380,  380,  380,  380,  381,  381,  381,  381,  382,
+
+      382,  382,  382,  383,  383,  383,  383,  384,  384,  384,
+      384,  385,  385,  385,  385,  386,  386,  386,  386,  387,
+      387,  387,  387,  388,  388,  388,  388,  389,  389,  389,
+      389,  390,  390,  390,  390,  391,  391,  391,  391,  392,
+      392,  392,  392,  393,  393,  393,  393,  394,  394,  394,
+      394,  395,  395,  395,  395,  396,  396,  396,  396,  397,
+      397,  397,  397,  398,  398,  398,  398,  399,  399,  399,
+      399,  400,  400,  400,  400,  401,  401,  401,  401,  402,
+      402,  402,  402,  403,  403,  403,  403,  404,  404,  404,
+      404,  405,  405,  405,  405,  406,  406,  406,  406,  407,
+
+      407,  407,  407,  408,  408,  408,  408,  409,  409,  409,
+      409,  410,  410,  410,  410,  411,  411,  411,  411,  412,
+      412,  412,  412,  413,  413,  413,  413,  414,  414,  414,
+      414,  415,  415,  415,  415,  416,  416,  416,  416,  417,
+      417,  417,  417,  418,  418,  418,  418,  419,  419,  419,
+      419,  420,  420,  420,  420,  421,  421,  421,  421,  422,
+      422,  422,  422,  423,  423,  423,  423,  424,  424,  424,
+      424,  425,  425,  425,  425,  426,  426,  426,  426,  427,
+      427,  427,  427,  428,  428,  428,  428,  429,  429,  429,
+      429,  430,  430,  430,  430,  431,  431,  431,  431,  432,
+
+      432,  432,  432,  433,  433,  433,  433,  434,  434,  434,
+      434,  435,  435,  435,  435,  436,  436,  436,  436,  437,
+      437,  437,  437,  438,  438,  438,  438,  439,  439,  439,
+      439,  440,  440,  440,  440,  441,  441,  441,  441,  442,
+      442,  442,  442,   99,   99,  225,  224,  222,  220,   99,
+      219,  218,  216,  214,  213,  212,  211,  210,  208,  206,
+      205,  204,  203,  202,  201,  199,  196,  195,  194,  193,
+      192,  191,   99,   59,  188,  189,  188,  153,  185,  184,
+      183,  182,   99,   99,  177,  176,  175,  174,  173,   99,
+      169,  168,  167,   99,  166,   99,  165,   99,  161,  160,
+
+      119,   99,   99,   99,  157,  156,  103,  152,  151,  150,
+      149,  148,  147,  146,  145,   99,   99,  143,  142,  141,
+      140,  139,  138,  137,   59,  132,  128,  127,  126,  125,
+       70,   70,  124,  123,   70,  122,   99,   99,  121,  120,
+      119,  118,  117,   99,  116,  115,  114,  113,  112,   59,
+      111,  110,  109,  108,  107,  106,  443,   27,  102,   70,
+      101,  100,   99,   98,   97,   96,   95,   70,   94,   93,
+       92,   88,   85,   84,   70,   83,   70,   82,   81,   80,
+       79,   78,   77,   75,   74,   72,   71,   70,  443,   65,
+       64,   63,   56,   55,   54,   53,  443,  443,    3,  443,
+
+      443,  443,  443,  443,  443,  443,  443,  443,  443,  443,
+      443,  443,  443,  443,  443,  443,  443,  443,  443,  443,
+      443,  443,  443,  443,  443,  443,  443,  443,  443,  443,
+      443,  443,  443,  443
+    } ;
+
+static yyconst flex_int16_t yy_chk[1235] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    5,    5,    6,    6,    7,
+        7,    7,    7,   10,   11,   12,   14,   34,   15,   16,
+       49,   13,   26,   26,  107,   37,   12,   49,   16,  471,
+       12,   12,   11,   13,   15,   11,   13,   13,  107,   10,
+      469,   34,   14,   17,   27,   27,   27,   28,   28,   28,
+       28,   17,   17,   37,   66,   66,   66,   66,  467,   17,
+      465,   17,  463,   17,   17,  461,   17,   17,   22,   51,
+
+       22,   22,  103,  103,  103,   51,   22,  134,   22,   51,
+      104,  104,  104,  104,  109,  459,  134,   22,  457,  143,
+      109,  129,  129,  129,  129,  143,  153,  153,  153,  154,
+      154,  154,  154,  165,  455,  165,  170,  170,  170,  186,
+      186,  186,  211,  211,  211,  453,  451,  449,  229,  228,
+      165,  444,  444,  445,  445,  445,  225,  445,  446,  446,
+      447,  447,  447,  224,  447,  448,  448,  450,  450,  450,
+      450,  452,  452,  452,  452,  454,  454,  454,  454,  456,
+      456,  456,  456,  458,  458,  458,  458,  460,  460,  460,
+      460,  462,  462,  462,  462,  464,  464,  464,  464,  466,
+
+      466,  466,  466,  468,  468,  468,  468,  470,  470,  470,
+      470,  472,  472,  472,  472,  473,  473,  473,  473,  474,
+      474,  474,  474,  475,  475,  475,  475,  476,  476,  476,
+      476,  477,  477,  477,  477,  478,  478,  478,  478,  479,
+      479,  479,  479,  480,  480,  480,  480,  481,  481,  481,
+      481,  482,  482,  482,  482,  483,  483,  483,  483,  484,
+      484,  484,  484,  485,  485,  485,  485,  486,  486,  486,
+      486,  487,  487,  487,  487,  488,  488,  488,  488,  489,
+      489,  489,  489,  490,  490,  490,  490,  491,  491,  491,
+      491,  492,  492,  492,  492,  493,  493,  493,  493,  494,
+
+      494,  494,  494,  495,  495,  495,  495,  496,  496,  496,
+      496,  497,  497,  497,  497,  498,  498,  498,  498,  499,
+      499,  499,  499,  500,  500,  500,  500,  501,  501,  501,
+      501,  502,  502,  502,  502,  503,  503,  503,  503,  504,
+      504,  504,  504,  505,  505,  505,  505,  506,  506,  506,
+      506,  507,  507,  507,  507,  508,  508,  508,  508,  509,
+      509,  509,  509,  510,  510,  510,  510,  511,  511,  511,
+      511,  512,  512,  512,  512,  513,  513,  513,  513,  514,
+      514,  514,  514,  515,  515,  515,  515,  516,  516,  516,
+      516,  517,  517,  517,  517,  518,  518,  518,  518,  519,
+
+      519,  519,  519,  520,  520,  520,  520,  521,  521,  521,
+      521,  522,  522,  522,  522,  523,  523,  523,  523,  524,
+      524,  524,  524,  525,  525,  525,  525,  526,  526,  526,
+      526,  527,  527,  527,  527,  528,  528,  528,  528,  529,
+      529,  529,  529,  530,  530,  530,  530,  531,  531,  531,
+      531,  532,  532,  532,  532,  533,  533,  533,  533,  534,
+      534,  534,  534,  535,  535,  535,  535,  536,  536,  536,
+      536,  537,  537,  537,  537,  538,  538,  538,  538,  539,
+      539,  539,  539,  540,  540,  540,  540,  541,  541,  541,
+      541,  542,  542,  542,  542,  543,  543,  543,  543,  544,
+
+      544,  544,  544,  545,  545,  545,  545,  546,  546,  546,
+      546,  547,  547,  547,  547,  548,  548,  548,  548,  549,
+      549,  549,  549,  550,  550,  550,  550,  551,  551,  551,
+      551,  552,  552,  552,  552,  553,  553,  553,  553,  554,
+      554,  554,  554,  555,  555,  555,  555,  556,  556,  556,
+      556,  557,  557,  557,  557,  558,  558,  558,  558,  559,
+      559,  559,  559,  560,  560,  560,  560,  561,  561,  561,
+      561,  562,  562,  562,  562,  563,  563,  563,  563,  564,
+      564,  564,  564,  565,  565,  565,  565,  566,  566,  566,
+      566,  567,  567,  567,  567,  568,  568,  568,  568,  569,
+
+      569,  569,  569,  570,  570,  570,  570,  571,  571,  571,
+      571,  572,  572,  572,  572,  573,  573,  573,  573,  574,
+      574,  574,  574,  575,  575,  575,  575,  576,  576,  576,
+      576,  577,  577,  577,  577,  578,  578,  578,  578,  579,
+      579,  579,  579,  580,  580,  580,  580,  581,  581,  581,
+      581,  582,  582,  582,  582,  583,  583,  583,  583,  584,
+      584,  584,  584,  585,  585,  585,  585,  586,  586,  586,
+      586,  587,  587,  587,  587,  588,  588,  588,  588,  589,
+      589,  589,  589,  590,  590,  590,  590,  591,  591,  591,
+      591,  592,  592,  592,  592,  593,  593,  593,  593,  594,
+
+      594,  594,  594,  595,  595,  595,  595,  596,  596,  596,
+      596,  597,  597,  597,  597,  598,  598,  598,  598,  599,
+      599,  599,  599,  600,  600,  600,  600,  601,  601,  601,
+      601,  602,  602,  602,  602,  603,  603,  603,  603,  604,
+      604,  604,  604,  605,  605,  605,  605,  606,  606,  606,
+      606,  607,  607,  607,  607,  608,  608,  608,  608,  609,
+      609,  609,  609,  610,  610,  610,  610,  611,  611,  611,
+      611,  612,  612,  612,  612,  613,  613,  613,  613,  614,
+      614,  614,  614,  615,  615,  615,  615,  616,  616,  616,
+      616,  617,  617,  617,  617,  618,  618,  618,  618,  619,
+
+      619,  619,  619,  620,  620,  620,  620,  621,  621,  621,
+      621,  622,  622,  622,  622,  623,  623,  623,  623,  624,
+      624,  624,  624,  625,  625,  625,  625,  626,  626,  626,
+      626,  627,  627,  627,  627,  628,  628,  628,  628,  629,
+      629,  629,  629,  630,  630,  630,  630,  631,  631,  631,
+      631,  632,  632,  632,  632,  633,  633,  633,  633,  634,
+      634,  634,  634,  635,  635,  635,  635,  636,  636,  636,
+      636,  637,  637,  637,  637,  638,  638,  638,  638,  639,
+      639,  639,  639,  640,  640,  640,  640,  641,  641,  641,
+      641,  642,  642,  642,  642,  643,  643,  643,  643,  644,
+
+      644,  644,  644,  645,  645,  645,  645,  646,  646,  646,
+      646,  647,  647,  647,  647,  648,  648,  648,  648,  649,
+      649,  649,  649,  650,  650,  650,  650,  651,  651,  651,
+      651,  652,  652,  652,  652,  653,  653,  653,  653,  654,
+      654,  654,  654,  655,  655,  655,  655,  656,  656,  656,
+      656,  657,  657,  657,  657,  658,  658,  658,  658,  659,
+      659,  659,  659,  660,  660,  660,  660,  661,  661,  661,
+      661,  662,  662,  662,  662,  663,  663,  663,  663,  664,
+      664,  664,  664,  665,  665,  665,  665,  666,  666,  666,
+      666,  667,  667,  667,  667,  668,  668,  668,  668,  669,
+
+      669,  669,  669,  670,  670,  670,  670,  671,  671,  671,
+      671,  672,  672,  672,  672,  673,  673,  673,  673,  674,
+      674,  674,  674,  675,  675,  675,  675,  676,  676,  676,
+      676,  677,  677,  677,  677,  678,  678,  678,  678,  679,
+      679,  679,  679,  222,  220,  219,  218,  216,  214,  213,
+      212,  210,  208,  206,  205,  204,  202,  201,  199,  196,
+      195,  194,  193,  192,  191,  189,  184,  183,  182,  181,
+      180,  179,  177,  176,  175,  174,  173,  171,  169,  168,
+      167,  166,  163,  162,  161,  160,  159,  158,  157,  156,
+      152,  151,  150,  149,  147,  146,  145,  141,  140,  139,
+
+      138,  137,  136,  135,  133,  132,  130,  128,  127,  126,
+      125,  124,  123,  122,  121,  118,  117,  116,  115,  114,
+      113,  112,  111,  110,  108,  106,  102,  101,  100,   98,
+       97,   96,   95,   94,   93,   92,   91,   90,   89,   88,
+       87,   86,   85,   84,   83,   82,   81,   80,   79,   78,
+       77,   75,   74,   73,   72,   71,   68,   67,   65,   64,
+       63,   62,   61,   60,   58,   57,   56,   55,   54,   53,
+       52,   50,   48,   47,   46,   45,   44,   43,   42,   41,
+       40,   39,   38,   36,   35,   33,   32,   31,   29,   25,
+       24,   23,   21,   20,   19,   18,    8,    3,  443,  443,
+
+      443,  443,  443,  443,  443,  443,  443,  443,  443,  443,
+      443,  443,  443,  443,  443,  443,  443,  443,  443,  443,
+      443,  443,  443,  443,  443,  443,  443,  443,  443,  443,
+      443,  443,  443,  443
+    } ;
+
+static yy_state_type yy_last_accepting_state;
+static char *yy_last_accepting_cpos;
+
+extern int yy_flex_debug;
+int yy_flex_debug = 0;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+#ifndef YYLMAX
+#define YYLMAX 8192
+#endif
+
+char yytext[YYLMAX];
+char *yytext_ptr;
+#line 1 "prom_lex.l"
+/*
+ * Copyright (C) IBM Corporation. 2007
+ * Author: Doug Maxey <dwm@austin.ibm.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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+/* definitions */
+#line 23 "prom_lex.l"
+#include "prom_parse.h"
+
+#undef LEXDEBUG
+#ifdef LEXDEBUG
+#define dbg(a) dbgprint((a))
+#else
+#define dbg(a) do {} while (0)
+#endif  /* LEXDEBUG */
+
+#define upval(d)                               \
+    dbg(#d);                                   \
+    yylval.str[0] = 0;                          \
+    strcat(yylval.str, yytext);                        \
+    yylloc.first_column = yylloc.last_column;  \
+    yylloc.last_column += yyleng;              \
+    return d
+
+void dbgprint(const char *item) { fprintf(stderr, "%s: \"%s\" len=%d ", item, yytext, yyleng);}
+
+#define YY_NO_INPUT 1
+/* CHOSEN uses only boot related paths. */
+#line 975 "<stdout>"
+
+#define INITIAL 0
+
+#ifndef YY_NO_UNISTD_H
+/* Special case for "unistd.h", since it is non-ANSI. We include it way
+ * down here because we want the user's section 1 to have been scanned first.
+ * The user has a chance to override it with an option.
+ */
+#include <unistd.h>
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+static int yy_init_globals (void );
+
+/* Accessor methods to globals.
+   These are made visible to non-reentrant scanners for convenience. */
+
+int yylex_destroy (void );
+
+int yyget_debug (void );
+
+void yyset_debug (int debug_flag  );
+
+YY_EXTRA_TYPE yyget_extra (void );
+
+void yyset_extra (YY_EXTRA_TYPE user_defined  );
+
+FILE *yyget_in (void );
+
+void yyset_in  (FILE * in_str  );
+
+FILE *yyget_out (void );
+
+void yyset_out  (FILE * out_str  );
+
+int yyget_leng (void );
+
+char *yyget_text (void );
+
+int yyget_lineno (void );
+
+void yyset_lineno (int line_number  );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int yywrap (void );
+#else
+extern int yywrap (void );
+#endif
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int );
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * );
+#endif
+
+#ifndef YY_NO_INPUT
+
+#ifdef __cplusplus
+static int yyinput (void );
+#else
+static int input (void );
+#endif
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k */
+#define YY_READ_BUF_SIZE 16384
+#else
+#define YY_READ_BUF_SIZE 8192
+#endif /* __ia64__ */
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO do { if (fwrite( yytext, yyleng, 1, yyout )) {} } while (0)
+#endif
+
+/* Gets input and stuffs it into "buf".  number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+       if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
+               { \
+               int c = '*'; \
+               size_t n; \
+               for ( n = 0; n < max_size && \
+                            (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+                       buf[n] = (char) c; \
+               if ( c == '\n' ) \
+                       buf[n++] = (char) c; \
+               if ( c == EOF && ferror( yyin ) ) \
+                       YY_FATAL_ERROR( "input in flex scanner failed" ); \
+               result = n; \
+               } \
+       else \
+               { \
+               errno=0; \
+               while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \
+                       { \
+                       if( errno != EINTR) \
+                               { \
+                               YY_FATAL_ERROR( "input in flex scanner failed" ); \
+                               break; \
+                               } \
+                       errno=0; \
+                       clearerr(yyin); \
+                       } \
+               }\
+\
+
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
+#endif
+
+/* end tables serialization structures and prototypes */
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int yylex (void);
+
+#define YY_DECL int yylex (void)
+#endif /* !YY_DECL */
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+       YY_USER_ACTION
+
+/** The main scanner function which does all the work.
+ */
+YY_DECL
+{
+       register yy_state_type yy_current_state;
+       register char *yy_cp, *yy_bp;
+       register int yy_act;
+    
+#line 65 "prom_lex.l"
+
+
+#line 1163 "<stdout>"
+
+       if ( !(yy_init) )
+               {
+               (yy_init) = 1;
+
+#ifdef YY_USER_INIT
+               YY_USER_INIT;
+#endif
+
+               if ( ! (yy_start) )
+                       (yy_start) = 1; /* first start state */
+
+               if ( ! yyin )
+                       yyin = stdin;
+
+               if ( ! yyout )
+                       yyout = stdout;
+
+               if ( ! YY_CURRENT_BUFFER ) {
+                       yyensure_buffer_stack ();
+                       YY_CURRENT_BUFFER_LVALUE =
+                               yy_create_buffer(yyin,YY_BUF_SIZE );
+               }
+
+               yy_load_buffer_state( );
+               }
+
+       while ( 1 )             /* loops until end-of-file is reached */
+               {
+               yy_cp = (yy_c_buf_p);
+
+               /* Support of yytext. */
+               *yy_cp = (yy_hold_char);
+
+               /* yy_bp points to the position in yy_ch_buf of the start of
+                * the current run.
+                */
+               yy_bp = yy_cp;
+
+               yy_current_state = (yy_start);
+yy_match:
+               do
+                       {
+                       register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+                       if ( yy_accept[yy_current_state] )
+                               {
+                               (yy_last_accepting_state) = yy_current_state;
+                               (yy_last_accepting_cpos) = yy_cp;
+                               }
+                       while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+                               {
+                               yy_current_state = (int) yy_def[yy_current_state];
+                               if ( yy_current_state >= 444 )
+                                       yy_c = yy_meta[(unsigned int) yy_c];
+                               }
+                       yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+                       ++yy_cp;
+                       }
+               while ( yy_current_state != 443 );
+               yy_cp = (yy_last_accepting_cpos);
+               yy_current_state = (yy_last_accepting_state);
+
+yy_find_action:
+               yy_act = yy_accept[yy_current_state];
+
+               YY_DO_BEFORE_ACTION;
+
+do_action:     /* This label is used only to access EOF actions. */
+
+               switch ( yy_act )
+       { /* beginning of action switch */
+                       case 0: /* must back up */
+                       /* undo the effects of YY_DO_BEFORE_ACTION */
+                       *yy_cp = (yy_hold_char);
+                       yy_cp = (yy_last_accepting_cpos);
+                       yy_current_state = (yy_last_accepting_state);
+                       goto yy_find_action;
+
+case 1:
+YY_RULE_SETUP
+#line 67 "prom_lex.l"
+{ upval(CHOSEN); }
+       YY_BREAK
+case 2:
+YY_RULE_SETUP
+#line 68 "prom_lex.l"
+{ upval(VDEVICE); }
+       YY_BREAK
+case 3:
+YY_RULE_SETUP
+#line 69 "prom_lex.l"
+{ upval(VDEVINST); }
+       YY_BREAK
+case 4:
+YY_RULE_SETUP
+#line 70 "prom_lex.l"
+{ upval(VDEVDEV); }
+       YY_BREAK
+case 5:
+YY_RULE_SETUP
+#line 71 "prom_lex.l"
+{ upval(VDEVRAW); }
+       YY_BREAK
+case 6:
+YY_RULE_SETUP
+#line 72 "prom_lex.l"
+{ upval(OBPQUAL); }
+       YY_BREAK
+case 7:
+YY_RULE_SETUP
+#line 73 "prom_lex.l"
+{ upval(BUSNAME); }
+       YY_BREAK
+case 8:
+YY_RULE_SETUP
+#line 74 "prom_lex.l"
+{ upval(IPV4); }
+       YY_BREAK
+case 9:
+YY_RULE_SETUP
+#line 75 "prom_lex.l"
+{ upval(IQN); }
+       YY_BREAK
+case 10:
+YY_RULE_SETUP
+#line 76 "prom_lex.l"
+{ upval(BOOTDEV); }
+       YY_BREAK
+case 11:
+YY_RULE_SETUP
+#line 77 "prom_lex.l"
+{ upval(OBPPARM); }
+       YY_BREAK
+case 12:
+YY_RULE_SETUP
+#line 78 "prom_lex.l"
+{ upval(HEX4); }
+       YY_BREAK
+case 13:
+YY_RULE_SETUP
+#line 79 "prom_lex.l"
+{ upval(HEX16); }
+       YY_BREAK
+case 14:
+YY_RULE_SETUP
+#line 80 "prom_lex.l"
+{ upval(FILENAME); }
+       YY_BREAK
+case 15:
+/* rule 15 can match eol */
+YY_RULE_SETUP
+#line 81 "prom_lex.l"
+{                  /* eat all whitespace. */
+       yylloc.first_column = yylloc.last_column;
+       yylloc.last_column += yyleng;
+}
+       YY_BREAK
+case 16:
+YY_RULE_SETUP
+#line 85 "prom_lex.l"
+{                      /* any other single char. */
+       dbg("??");
+       yylloc.first_column = yylloc.last_column;
+       yylloc.last_column += yyleng;
+       return *yytext;
+}
+       YY_BREAK
+case YY_STATE_EOF(INITIAL):
+#line 92 "prom_lex.l"
+yyterminate();
+       YY_BREAK
+case 17:
+YY_RULE_SETUP
+#line 93 "prom_lex.l"
+ECHO;
+       YY_BREAK
+#line 1340 "<stdout>"
+
+       case YY_END_OF_BUFFER:
+               {
+               /* Amount of text matched not including the EOB char. */
+               int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1;
+
+               /* Undo the effects of YY_DO_BEFORE_ACTION. */
+               *yy_cp = (yy_hold_char);
+               YY_RESTORE_YY_MORE_OFFSET
+
+               if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
+                       {
+                       /* We're scanning a new file or input source.  It's
+                        * possible that this happened because the user
+                        * just pointed yyin at a new source and called
+                        * yylex().  If so, then we have to assure
+                        * consistency between YY_CURRENT_BUFFER and our
+                        * globals.  Here is the right place to do so, because
+                        * this is the first action (other than possibly a
+                        * back-up) that will match for the new input source.
+                        */
+                       (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+                       YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin;
+                       YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
+                       }
+
+               /* Note that here we test for yy_c_buf_p "<=" to the position
+                * of the first EOB in the buffer, since yy_c_buf_p will
+                * already have been incremented past the NUL character
+                * (since all states make transitions on EOB to the
+                * end-of-buffer state).  Contrast this with the test
+                * in input().
+                */
+               if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+                       { /* This was really a NUL. */
+                       yy_state_type yy_next_state;
+
+                       (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text;
+
+                       yy_current_state = yy_get_previous_state(  );
+
+                       /* Okay, we're now positioned to make the NUL
+                        * transition.  We couldn't have
+                        * yy_get_previous_state() go ahead and do it
+                        * for us because it doesn't know how to deal
+                        * with the possibility of jamming (and we don't
+                        * want to build jamming into it because then it
+                        * will run more slowly).
+                        */
+
+                       yy_next_state = yy_try_NUL_trans( yy_current_state );
+
+                       yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+
+                       if ( yy_next_state )
+                               {
+                               /* Consume the NUL. */
+                               yy_cp = ++(yy_c_buf_p);
+                               yy_current_state = yy_next_state;
+                               goto yy_match;
+                               }
+
+                       else
+                               {
+                               yy_cp = (yy_last_accepting_cpos);
+                               yy_current_state = (yy_last_accepting_state);
+                               goto yy_find_action;
+                               }
+                       }
+
+               else switch ( yy_get_next_buffer(  ) )
+                       {
+                       case EOB_ACT_END_OF_FILE:
+                               {
+                               (yy_did_buffer_switch_on_eof) = 0;
+
+                               if ( yywrap( ) )
+                                       {
+                                       /* Note: because we've taken care in
+                                        * yy_get_next_buffer() to have set up
+                                        * yytext, we can now set up
+                                        * yy_c_buf_p so that if some total
+                                        * hoser (like flex itself) wants to
+                                        * call the scanner after we return the
+                                        * YY_NULL, it'll still work - another
+                                        * YY_NULL will get returned.
+                                        */
+                                       (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ;
+
+                                       yy_act = YY_STATE_EOF(YY_START);
+                                       goto do_action;
+                                       }
+
+                               else
+                                       {
+                                       if ( ! (yy_did_buffer_switch_on_eof) )
+                                               YY_NEW_FILE;
+                                       }
+                               break;
+                               }
+
+                       case EOB_ACT_CONTINUE_SCAN:
+                               (yy_c_buf_p) =
+                                       (yytext_ptr) + yy_amount_of_matched_text;
+
+                               yy_current_state = yy_get_previous_state(  );
+
+                               yy_cp = (yy_c_buf_p);
+                               yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+                               goto yy_match;
+
+                       case EOB_ACT_LAST_MATCH:
+                               (yy_c_buf_p) =
+                               &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)];
+
+                               yy_current_state = yy_get_previous_state(  );
+
+                               yy_cp = (yy_c_buf_p);
+                               yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+                               goto yy_find_action;
+                       }
+               break;
+               }
+
+       default:
+               YY_FATAL_ERROR(
+                       "fatal flex scanner internal error--no action found" );
+       } /* end of action switch */
+               } /* end of scanning one token */
+} /* end of yylex */
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ *     EOB_ACT_LAST_MATCH -
+ *     EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ *     EOB_ACT_END_OF_FILE - end of file
+ */
+static int yy_get_next_buffer (void)
+{
+       register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+       register char *source = (yytext_ptr);
+       register int number_to_move, i;
+       int ret_val;
+
+       if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] )
+               YY_FATAL_ERROR(
+               "fatal flex scanner internal error--end of buffer missed" );
+
+       if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
+               { /* Don't try to fill the buffer, so this is an EOF. */
+               if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 )
+                       {
+                       /* We matched a single character, the EOB, so
+                        * treat this as a final EOF.
+                        */
+                       return EOB_ACT_END_OF_FILE;
+                       }
+
+               else
+                       {
+                       /* We matched some text prior to the EOB, first
+                        * process it.
+                        */
+                       return EOB_ACT_LAST_MATCH;
+                       }
+               }
+
+       /* Try to read more data. */
+
+       /* First move last chars to start of buffer. */
+       number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1;
+
+       for ( i = 0; i < number_to_move; ++i )
+               *(dest++) = *(source++);
+
+       if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+               /* don't do the read, it's not guaranteed to return an EOF,
+                * just force an EOF
+                */
+               YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0;
+
+       else
+               {
+                       int num_to_read =
+                       YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+               while ( num_to_read <= 0 )
+                       { /* Not enough room in the buffer - grow it. */
+
+                       /* just a shorter name for the current buffer */
+                       YY_BUFFER_STATE b = YY_CURRENT_BUFFER;
+
+                       int yy_c_buf_p_offset =
+                               (int) ((yy_c_buf_p) - b->yy_ch_buf);
+
+                       if ( b->yy_is_our_buffer )
+                               {
+                               int new_size = b->yy_buf_size * 2;
+
+                               if ( new_size <= 0 )
+                                       b->yy_buf_size += b->yy_buf_size / 8;
+                               else
+                                       b->yy_buf_size *= 2;
+
+                               b->yy_ch_buf = (char *)
+                                       /* Include room in for 2 EOB chars. */
+                                       yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2  );
+                               }
+                       else
+                               /* Can't grow it, we don't own it. */
+                               b->yy_ch_buf = 0;
+
+                       if ( ! b->yy_ch_buf )
+                               YY_FATAL_ERROR(
+                               "fatal error - scanner input buffer overflow" );
+
+                       (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+                       num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
+                                               number_to_move - 1;
+
+                       }
+
+               if ( num_to_read > YY_READ_BUF_SIZE )
+                       num_to_read = YY_READ_BUF_SIZE;
+
+               /* Read in more data. */
+               YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+                       (yy_n_chars), (size_t) num_to_read );
+
+               YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+               }
+
+       if ( (yy_n_chars) == 0 )
+               {
+               if ( number_to_move == YY_MORE_ADJ )
+                       {
+                       ret_val = EOB_ACT_END_OF_FILE;
+                       yyrestart(yyin  );
+                       }
+
+               else
+                       {
+                       ret_val = EOB_ACT_LAST_MATCH;
+                       YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
+                               YY_BUFFER_EOF_PENDING;
+                       }
+               }
+
+       else
+               ret_val = EOB_ACT_CONTINUE_SCAN;
+
+       if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+               /* Extend the array by 50%, plus the number we really need. */
+               yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1);
+               YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size  );
+               if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+                       YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
+       }
+
+       (yy_n_chars) += number_to_move;
+       YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR;
+       YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR;
+
+       (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
+
+       return ret_val;
+}
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+    static yy_state_type yy_get_previous_state (void)
+{
+       register yy_state_type yy_current_state;
+       register char *yy_cp;
+    
+       yy_current_state = (yy_start);
+
+       for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp )
+               {
+               register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+               if ( yy_accept[yy_current_state] )
+                       {
+                       (yy_last_accepting_state) = yy_current_state;
+                       (yy_last_accepting_cpos) = yy_cp;
+                       }
+               while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+                       {
+                       yy_current_state = (int) yy_def[yy_current_state];
+                       if ( yy_current_state >= 444 )
+                               yy_c = yy_meta[(unsigned int) yy_c];
+                       }
+               yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+               }
+
+       return yy_current_state;
+}
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ *     next_state = yy_try_NUL_trans( current_state );
+ */
+    static yy_state_type yy_try_NUL_trans  (yy_state_type yy_current_state )
+{
+       register int yy_is_jam;
+       register char *yy_cp = (yy_c_buf_p);
+
+       register YY_CHAR yy_c = 1;
+       if ( yy_accept[yy_current_state] )
+               {
+               (yy_last_accepting_state) = yy_current_state;
+               (yy_last_accepting_cpos) = yy_cp;
+               }
+       while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+               {
+               yy_current_state = (int) yy_def[yy_current_state];
+               if ( yy_current_state >= 444 )
+                       yy_c = yy_meta[(unsigned int) yy_c];
+               }
+       yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+       yy_is_jam = (yy_current_state == 443);
+
+       return yy_is_jam ? 0 : yy_current_state;
+}
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+    static int yyinput (void)
+#else
+    static int input  (void)
+#endif
+
+{
+       int c;
+    
+       *(yy_c_buf_p) = (yy_hold_char);
+
+       if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR )
+               {
+               /* yy_c_buf_p now points to the character we want to return.
+                * If this occurs *before* the EOB characters, then it's a
+                * valid NUL; if not, then we've hit the end of the buffer.
+                */
+               if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+                       /* This was really a NUL. */
+                       *(yy_c_buf_p) = '\0';
+
+               else
+                       { /* need more input */
+                       int offset = (yy_c_buf_p) - (yytext_ptr);
+                       ++(yy_c_buf_p);
+
+                       switch ( yy_get_next_buffer(  ) )
+                               {
+                               case EOB_ACT_LAST_MATCH:
+                                       /* This happens because yy_g_n_b()
+                                        * sees that we've accumulated a
+                                        * token and flags that we need to
+                                        * try matching the token before
+                                        * proceeding.  But for input(),
+                                        * there's no matching to consider.
+                                        * So convert the EOB_ACT_LAST_MATCH
+                                        * to EOB_ACT_END_OF_FILE.
+                                        */
+
+                                       /* Reset buffer status. */
+                                       yyrestart(yyin );
+
+                                       /*FALLTHROUGH*/
+
+                               case EOB_ACT_END_OF_FILE:
+                                       {
+                                       if ( yywrap( ) )
+                                               return EOF;
+
+                                       if ( ! (yy_did_buffer_switch_on_eof) )
+                                               YY_NEW_FILE;
+#ifdef __cplusplus
+                                       return yyinput();
+#else
+                                       return input();
+#endif
+                                       }
+
+                               case EOB_ACT_CONTINUE_SCAN:
+                                       (yy_c_buf_p) = (yytext_ptr) + offset;
+                                       break;
+                               }
+                       }
+               }
+
+       c = *(unsigned char *) (yy_c_buf_p);    /* cast for 8-bit char's */
+       *(yy_c_buf_p) = '\0';   /* preserve yytext */
+       (yy_hold_char) = *++(yy_c_buf_p);
+
+       return c;
+}
+#endif /* ifndef YY_NO_INPUT */
+
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ * 
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+    void yyrestart  (FILE * input_file )
+{
+    
+       if ( ! YY_CURRENT_BUFFER ){
+        yyensure_buffer_stack ();
+               YY_CURRENT_BUFFER_LVALUE =
+            yy_create_buffer(yyin,YY_BUF_SIZE );
+       }
+
+       yy_init_buffer(YY_CURRENT_BUFFER,input_file );
+       yy_load_buffer_state( );
+}
+
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ * 
+ */
+    void yy_switch_to_buffer  (YY_BUFFER_STATE  new_buffer )
+{
+    
+       /* TODO. We should be able to replace this entire function body
+        * with
+        *              yypop_buffer_state();
+        *              yypush_buffer_state(new_buffer);
+     */
+       yyensure_buffer_stack ();
+       if ( YY_CURRENT_BUFFER == new_buffer )
+               return;
+
+       if ( YY_CURRENT_BUFFER )
+               {
+               /* Flush out information for old buffer. */
+               *(yy_c_buf_p) = (yy_hold_char);
+               YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+               YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+               }
+
+       YY_CURRENT_BUFFER_LVALUE = new_buffer;
+       yy_load_buffer_state( );
+
+       /* We don't actually know whether we did this switch during
+        * EOF (yywrap()) processing, but the only time this flag
+        * is looked at is after yywrap() is called, so it's safe
+        * to go ahead and always set it.
+        */
+       (yy_did_buffer_switch_on_eof) = 1;
+}
+
+static void yy_load_buffer_state  (void)
+{
+       (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+       (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+       yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+       (yy_hold_char) = *(yy_c_buf_p);
+}
+
+/** Allocate and initialize an input buffer state.
+ * @param file A readable stream.
+ * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
+ * 
+ * @return the allocated buffer state.
+ */
+    YY_BUFFER_STATE yy_create_buffer  (FILE * file, int  size )
+{
+       YY_BUFFER_STATE b;
+    
+       b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state )  );
+       if ( ! b )
+               YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+       b->yy_buf_size = size;
+
+       /* yy_ch_buf has to be 2 characters longer than the size given because
+        * we need to put in 2 end-of-buffer characters.
+        */
+       b->yy_ch_buf = (char *) yyalloc(b->yy_buf_size + 2  );
+       if ( ! b->yy_ch_buf )
+               YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+       b->yy_is_our_buffer = 1;
+
+       yy_init_buffer(b,file );
+
+       return b;
+}
+
+/** Destroy the buffer.
+ * @param b a buffer created with yy_create_buffer()
+ * 
+ */
+    void yy_delete_buffer (YY_BUFFER_STATE  b )
+{
+    
+       if ( ! b )
+               return;
+
+       if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
+               YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
+
+       if ( b->yy_is_our_buffer )
+               yyfree((void *) b->yy_ch_buf  );
+
+       yyfree((void *) b  );
+}
+
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a yyrestart() or at EOF.
+ */
+    static void yy_init_buffer  (YY_BUFFER_STATE  b, FILE * file )
+
+{
+       int oerrno = errno;
+    
+       yy_flush_buffer(b );
+
+       b->yy_input_file = file;
+       b->yy_fill_buffer = 1;
+
+    /* If b is the current buffer, then yy_init_buffer was _probably_
+     * called from yyrestart() or through yy_get_next_buffer.
+     * In that case, we don't want to reset the lineno or column.
+     */
+    if (b != YY_CURRENT_BUFFER){
+        b->yy_bs_lineno = 1;
+        b->yy_bs_column = 0;
+    }
+
+        b->yy_is_interactive = 0;
+    
+       errno = oerrno;
+}
+
+/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
+ * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
+ * 
+ */
+    void yy_flush_buffer (YY_BUFFER_STATE  b )
+{
+       if ( ! b )
+               return;
+
+       b->yy_n_chars = 0;
+
+       /* We always need two end-of-buffer characters.  The first causes
+        * a transition to the end-of-buffer state.  The second causes
+        * a jam in that state.
+        */
+       b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+       b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+       b->yy_buf_pos = &b->yy_ch_buf[0];
+
+       b->yy_at_bol = 1;
+       b->yy_buffer_status = YY_BUFFER_NEW;
+
+       if ( b == YY_CURRENT_BUFFER )
+               yy_load_buffer_state( );
+}
+
+/** Pushes the new state onto the stack. The new state becomes
+ *  the current state. This function will allocate the stack
+ *  if necessary.
+ *  @param new_buffer The new state.
+ *  
+ */
+void yypush_buffer_state (YY_BUFFER_STATE new_buffer )
+{
+       if (new_buffer == NULL)
+               return;
+
+       yyensure_buffer_stack();
+
+       /* This block is copied from yy_switch_to_buffer. */
+       if ( YY_CURRENT_BUFFER )
+               {
+               /* Flush out information for old buffer. */
+               *(yy_c_buf_p) = (yy_hold_char);
+               YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+               YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+               }
+
+       /* Only push if top exists. Otherwise, replace top. */
+       if (YY_CURRENT_BUFFER)
+               (yy_buffer_stack_top)++;
+       YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+       /* copied from yy_switch_to_buffer. */
+       yy_load_buffer_state( );
+       (yy_did_buffer_switch_on_eof) = 1;
+}
+
+/** Removes and deletes the top of the stack, if present.
+ *  The next element becomes the new top.
+ *  
+ */
+void yypop_buffer_state (void)
+{
+       if (!YY_CURRENT_BUFFER)
+               return;
+
+       yy_delete_buffer(YY_CURRENT_BUFFER );
+       YY_CURRENT_BUFFER_LVALUE = NULL;
+       if ((yy_buffer_stack_top) > 0)
+               --(yy_buffer_stack_top);
+
+       if (YY_CURRENT_BUFFER) {
+               yy_load_buffer_state( );
+               (yy_did_buffer_switch_on_eof) = 1;
+       }
+}
+
+/* Allocates the stack if it does not exist.
+ *  Guarantees space for at least one push.
+ */
+static void yyensure_buffer_stack (void)
+{
+       int num_to_alloc;
+    
+       if (!(yy_buffer_stack)) {
+
+               /* First allocation is just for 2 elements, since we don't know if this
+                * scanner will even need a stack. We use 2 instead of 1 to avoid an
+                * immediate realloc on the next call.
+         */
+               num_to_alloc = 1;
+               (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc
+                                                               (num_to_alloc * sizeof(struct yy_buffer_state*)
+                                                               );
+               if ( ! (yy_buffer_stack) )
+                       YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
+
+               memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+                               
+               (yy_buffer_stack_max) = num_to_alloc;
+               (yy_buffer_stack_top) = 0;
+               return;
+       }
+
+       if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){
+
+               /* Increase the buffer to prepare for a possible push. */
+               int grow_size = 8 /* arbitrary grow size */;
+
+               num_to_alloc = (yy_buffer_stack_max) + grow_size;
+               (yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc
+                                                               ((yy_buffer_stack),
+                                                               num_to_alloc * sizeof(struct yy_buffer_state*)
+                                                               );
+               if ( ! (yy_buffer_stack) )
+                       YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
+
+               /* zero only the new slots.*/
+               memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*));
+               (yy_buffer_stack_max) = num_to_alloc;
+       }
+}
+
+/** Setup the input buffer state to scan directly from a user-specified character buffer.
+ * @param base the character buffer
+ * @param size the size in bytes of the character buffer
+ * 
+ * @return the newly allocated buffer state object. 
+ */
+YY_BUFFER_STATE yy_scan_buffer  (char * base, yy_size_t  size )
+{
+       YY_BUFFER_STATE b;
+    
+       if ( size < 2 ||
+            base[size-2] != YY_END_OF_BUFFER_CHAR ||
+            base[size-1] != YY_END_OF_BUFFER_CHAR )
+               /* They forgot to leave room for the EOB's. */
+               return 0;
+
+       b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state )  );
+       if ( ! b )
+               YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
+
+       b->yy_buf_size = size - 2;      /* "- 2" to take care of EOB's */
+       b->yy_buf_pos = b->yy_ch_buf = base;
+       b->yy_is_our_buffer = 0;
+       b->yy_input_file = 0;
+       b->yy_n_chars = b->yy_buf_size;
+       b->yy_is_interactive = 0;
+       b->yy_at_bol = 1;
+       b->yy_fill_buffer = 0;
+       b->yy_buffer_status = YY_BUFFER_NEW;
+
+       yy_switch_to_buffer(b  );
+
+       return b;
+}
+
+/** Setup the input buffer state to scan a string. The next call to yylex() will
+ * scan from a @e copy of @a str.
+ * @param yystr a NUL-terminated string to scan
+ * 
+ * @return the newly allocated buffer state object.
+ * @note If you want to scan bytes that may contain NUL values, then use
+ *       yy_scan_bytes() instead.
+ */
+YY_BUFFER_STATE yy_scan_string (yyconst char * yystr )
+{
+    
+       return yy_scan_bytes(yystr,strlen(yystr) );
+}
+
+/** Setup the input buffer state to scan the given bytes. The next call to yylex() will
+ * scan from a @e copy of @a bytes.
+ * @param yybytes the byte buffer to scan
+ * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes.
+ * 
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE yy_scan_bytes  (yyconst char * yybytes, int  _yybytes_len )
+{
+       YY_BUFFER_STATE b;
+       char *buf;
+       yy_size_t n;
+       int i;
+    
+       /* Get memory for full buffer, including space for trailing EOB's. */
+       n = _yybytes_len + 2;
+       buf = (char *) yyalloc(n  );
+       if ( ! buf )
+               YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
+
+       for ( i = 0; i < _yybytes_len; ++i )
+               buf[i] = yybytes[i];
+
+       buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
+
+       b = yy_scan_buffer(buf,n );
+       if ( ! b )
+               YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );
+
+       /* It's okay to grow etc. this buffer, and we should throw it
+        * away when we're done.
+        */
+       b->yy_is_our_buffer = 1;
+
+       return b;
+}
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+static void yy_fatal_error (yyconst char* msg )
+{
+       (void) fprintf( stderr, "%s\n", msg );
+       exit( YY_EXIT_FAILURE );
+}
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+       do \
+               { \
+               /* Undo effects of setting up yytext. */ \
+        int yyless_macro_arg = (n); \
+        YY_LESS_LINENO(yyless_macro_arg);\
+               yytext[yyleng] = (yy_hold_char); \
+               (yy_c_buf_p) = yytext + yyless_macro_arg; \
+               (yy_hold_char) = *(yy_c_buf_p); \
+               *(yy_c_buf_p) = '\0'; \
+               yyleng = yyless_macro_arg; \
+               } \
+       while ( 0 )
+
+/* Accessor  methods (get/set functions) to struct members. */
+
+/** Get the current line number.
+ * 
+ */
+int yyget_lineno  (void)
+{
+        
+    return yylineno;
+}
+
+/** Get the input stream.
+ * 
+ */
+FILE *yyget_in  (void)
+{
+        return yyin;
+}
+
+/** Get the output stream.
+ * 
+ */
+FILE *yyget_out  (void)
+{
+        return yyout;
+}
+
+/** Get the length of the current token.
+ * 
+ */
+int yyget_leng  (void)
+{
+        return yyleng;
+}
+
+/** Get the current token.
+ * 
+ */
+
+char *yyget_text  (void)
+{
+        return yytext;
+}
+
+/** Set the current line number.
+ * @param line_number
+ * 
+ */
+void yyset_lineno (int  line_number )
+{
+    
+    yylineno = line_number;
+}
+
+/** Set the input stream. This does not discard the current
+ * input buffer.
+ * @param in_str A readable stream.
+ * 
+ * @see yy_switch_to_buffer
+ */
+void yyset_in (FILE *  in_str )
+{
+        yyin = in_str ;
+}
+
+void yyset_out (FILE *  out_str )
+{
+        yyout = out_str ;
+}
+
+int yyget_debug  (void)
+{
+        return yy_flex_debug;
+}
+
+void yyset_debug (int  bdebug )
+{
+        yy_flex_debug = bdebug ;
+}
+
+static int yy_init_globals (void)
+{
+        /* Initialization is the same as for the non-reentrant scanner.
+     * This function is called from yylex_destroy(), so don't allocate here.
+     */
+
+    (yy_buffer_stack) = 0;
+    (yy_buffer_stack_top) = 0;
+    (yy_buffer_stack_max) = 0;
+    (yy_c_buf_p) = (char *) 0;
+    (yy_init) = 0;
+    (yy_start) = 0;
+
+/* Defined in main.c */
+#ifdef YY_STDINIT
+    yyin = stdin;
+    yyout = stdout;
+#else
+    yyin = (FILE *) 0;
+    yyout = (FILE *) 0;
+#endif
+
+    /* For future reference: Set errno on error, since we are called by
+     * yylex_init()
+     */
+    return 0;
+}
+
+/* yylex_destroy is for both reentrant and non-reentrant scanners. */
+int yylex_destroy  (void)
+{
+    
+    /* Pop the buffer stack, destroying each element. */
+       while(YY_CURRENT_BUFFER){
+               yy_delete_buffer(YY_CURRENT_BUFFER  );
+               YY_CURRENT_BUFFER_LVALUE = NULL;
+               yypop_buffer_state();
+       }
+
+       /* Destroy the stack itself. */
+       yyfree((yy_buffer_stack) );
+       (yy_buffer_stack) = NULL;
+
+    /* Reset the globals. This is important in a non-reentrant scanner so the next time
+     * yylex() is called, initialization will occur. */
+    yy_init_globals( );
+
+    return 0;
+}
+
+/*
+ * Internal utility routines.
+ */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char* s1, yyconst char * s2, int n )
+{
+       register int i;
+       for ( i = 0; i < n; ++i )
+               s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * s )
+{
+       register int n;
+       for ( n = 0; s[n]; ++n )
+               ;
+
+       return n;
+}
+#endif
+
+void *yyalloc (yy_size_t  size )
+{
+       return (void *) malloc( size );
+}
+
+void *yyrealloc  (void * ptr, yy_size_t  size )
+{
+       /* The cast to (char *) in the following accommodates both
+        * implementations that use char* generic pointers, and those
+        * that use void* generic pointers.  It works with the latter
+        * because both ANSI C and C++ allow castless assignment from
+        * any pointer type to void*, and deal with argument conversions
+        * as though doing an assignment.
+        */
+       return (void *) realloc( (char *) ptr, size );
+}
+
+void yyfree (void * ptr )
+{
+       free( (char *) ptr );   /* see yyrealloc() for (char *) cast */
+}
+
+#define YYTABLES_NAME "yytables"
+
+#line 93 "prom_lex.l"
+
+
+
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/fwparam_ibft/prom_lex.l b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/fwparam_ibft/prom_lex.l
new file mode 100644 (file)
index 0000000..e70c790
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) IBM Corporation. 2007
+ * Author: Doug Maxey <dwm@austin.ibm.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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* definitions */
+%option array
+
+%{
+#include "prom_parse.h"
+
+#undef LEXDEBUG
+#ifdef LEXDEBUG
+#define dbg(a) dbgprint((a))
+#else
+#define dbg(a) do {} while (0)
+#endif  /* LEXDEBUG */
+
+#define upval(d)                               \
+    dbg(#d);                                   \
+    yylval.str[0] = 0;                          \
+    strcat(yylval.str, yytext);                        \
+    yylloc.first_column = yylloc.last_column;  \
+    yylloc.last_column += yyleng;              \
+    return d
+
+void dbgprint(const char *item) { fprintf(stderr, "%s: \"%s\" len=%d ", item, yytext, yyleng);}
+
+%}
+
+%option noyywrap
+%option never-interactive
+%option nounput
+%option noinput
+
+VDEVICE     vdevice
+VDEVINST    gscsi
+VDEVDEV     dev
+VDEVRAW     rawio
+                                /* CHOSEN uses only boot related paths. */
+CHOSEN      bootpath|bootargs|iscsi-bootargs|nas-bootdevice
+BUSNAME     ata|i2c|ide|pci|sata|scsi|usb|lhea
+BOOTDEV     cdrom|disk|ethernet|iscsi-(disk[0-9]|toe)|sd
+HEX4        [[:xdigit:]]{1,4}
+HEX16       [[:xdigit:]]{5,16}
+IPV4        [0-9]{1,3}(\.[0-9]{1,3}){3}
+IQN         iqn\.[-[:alnum:]:.]{1,219}
+OBPQUAL     bootp|ipv6|iscsi|dhcpv6
+OBPPARM     blksize|bootp-retries|chapid|chappw|ciaddr|dhcp|filename|giaddr|ichapid|ichappw|ilun|iname|iport|isid|isns|itname|siaddr|slp|subnet-mask|tftp-retries
+FILENAME    \\[-[:alnum:]\\\.]{1,}
+
+%% /* rules */
+
+{CHOSEN}      { upval(CHOSEN); }
+{VDEVICE}     { upval(VDEVICE); }
+{VDEVINST}    { upval(VDEVINST); }
+{VDEVDEV}     { upval(VDEVDEV); }
+{VDEVRAW}     { upval(VDEVRAW); }
+{OBPQUAL}     { upval(OBPQUAL); }
+{BUSNAME}     { upval(BUSNAME); }
+{IPV4}        { upval(IPV4); }
+{IQN}         { upval(IQN); }
+{BOOTDEV}     { upval(BOOTDEV); }
+{OBPPARM}     { upval(OBPPARM); }
+{HEX4}        { upval(HEX4); }
+{HEX16}       { upval(HEX16); }
+{FILENAME}    { upval(FILENAME); }
+[ \t\n]+      {                  /* eat all whitespace. */
+       yylloc.first_column = yylloc.last_column;
+       yylloc.last_column += yyleng;
+}
+.             {                        /* any other single char. */
+       dbg("??");
+       yylloc.first_column = yylloc.last_column;
+       yylloc.last_column += yyleng;
+       return *yytext;
+}
+
+<<EOF>> yyterminate();
+%% /* user code */
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/fwparam_ibft/prom_parse.h b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/fwparam_ibft/prom_parse.h
new file mode 100644 (file)
index 0000000..00cffff
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) IBM Corporation. 2007
+ * Author: Doug Maxey <dwm@austin.ibm.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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef PROM_PARSE_H_
+#define PROM_PARSE_H_
+
+#include <stdlib.h>
+#include <string.h>
+#include "iscsi_obp.h"
+
+struct ofw_dev;
+void yyerror(struct ofw_dev *ofwdev, const char *msg);
+extern int yyleng;
+extern int yydebug;
+#include <stdio.h>
+extern FILE *yyin;
+extern char yytext[];
+int yylex(void);
+
+#define YY_NO_UNPUT 1 /* match this with %option never-interactive. */
+#include "prom_parse.tab.h"
+
+
+#endif /* PROM_PARSE_H_ */
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/fwparam_ibft/prom_parse.tab.c b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/fwparam_ibft/prom_parse.tab.c
new file mode 100644 (file)
index 0000000..6275961
--- /dev/null
@@ -0,0 +1,2063 @@
+/* A Bison parser, made by GNU Bison 3.0.4.  */
+
+/* Bison implementation for Yacc-like parsers in C
+
+   Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc.
+
+   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 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* As a special exception, you may create a larger work that contains
+   part or all of the Bison parser skeleton and distribute that work
+   under terms of your choice, so long as that work isn't itself a
+   parser generator using the skeleton or a modified version thereof
+   as a parser skeleton.  Alternatively, if you modify or redistribute
+   the parser skeleton itself, you may (at your option) remove this
+   special exception, which will cause the skeleton and the resulting
+   Bison output files to be licensed under the GNU General Public
+   License without this special exception.
+
+   This special exception was added by the Free Software Foundation in
+   version 2.2 of Bison.  */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+   simplifying the original so-called "semantic" parser.  */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+   infringing on user name space.  This should be done even for local
+   variables, as they might otherwise be expanded by user macros.
+   There are some unavoidable exceptions within include files to
+   define necessary library symbols; they are noted "INFRINGES ON
+   USER NAME SPACE" below.  */
+
+/* Identify Bison output.  */
+#define YYBISON 1
+
+/* Bison version.  */
+#define YYBISON_VERSION "3.0.4"
+
+/* Skeleton name.  */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers.  */
+#define YYPURE 0
+
+/* Push parsers.  */
+#define YYPUSH 0
+
+/* Pull parsers.  */
+#define YYPULL 1
+
+
+
+
+/* Copy the first part of user declarations.  */
+#line 21 "prom_parse.y" /* yacc.c:339  */
+
+       /* literal block. include lines, decls, defns. */
+//#define YYDEBUG 1
+#if YYDEBUG
+#define DPRINT(fmt,...) printf(fmt,__VA_ARGS__)
+#else
+#define DPRINT(fmt,...) do {} while(0)
+#endif
+#include "prom_parse.h"
+#include "iscsi_obp.h"
+
+
+
+#line 80 "prom_parse.tab.c" /* yacc.c:339  */
+
+# ifndef YY_NULLPTR
+#  if defined __cplusplus && 201103L <= __cplusplus
+#   define YY_NULLPTR nullptr
+#  else
+#   define YY_NULLPTR 0
+#  endif
+# endif
+
+/* Enabling verbose error messages.  */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+/* In a future release of Bison, this section will be replaced
+   by #include "prom_parse.tab.h".  */
+#ifndef YY_YY_PROM_PARSE_TAB_H_INCLUDED
+# define YY_YY_PROM_PARSE_TAB_H_INCLUDED
+/* Debug traces.  */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+#if YYDEBUG
+extern int yydebug;
+#endif
+
+/* Token type.  */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+  enum yytokentype
+  {
+    BUSNAME = 258,
+    BOOTDEV = 259,
+    IPV4 = 260,
+    IQN = 261,
+    OBPPARM = 262,
+    OBPQUAL = 263,
+    HEX4 = 264,
+    HEX16 = 265,
+    VDEVICE = 266,
+    VDEVINST = 267,
+    VDEVDEV = 268,
+    VDEVRAW = 269,
+    CHOSEN = 270,
+    FILENAME = 271
+  };
+#endif
+
+/* Value type.  */
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+
+union YYSTYPE
+{
+#line 34 "prom_parse.y" /* yacc.c:355  */
+
+#define        STR_LEN         16384
+               char str[STR_LEN];
+
+#line 142 "prom_parse.tab.c" /* yacc.c:355  */
+};
+
+typedef union YYSTYPE YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+/* Location type.  */
+#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED
+typedef struct YYLTYPE YYLTYPE;
+struct YYLTYPE
+{
+  int first_line;
+  int first_column;
+  int last_line;
+  int last_column;
+};
+# define YYLTYPE_IS_DECLARED 1
+# define YYLTYPE_IS_TRIVIAL 1
+#endif
+
+
+extern YYSTYPE yylval;
+extern YYLTYPE yylloc;
+int yyparse (struct ofw_dev *ofwdev);
+
+#endif /* !YY_YY_PROM_PARSE_TAB_H_INCLUDED  */
+
+/* Copy the second part of user declarations.  */
+
+#line 173 "prom_parse.tab.c" /* yacc.c:358  */
+
+#ifdef short
+# undef short
+#endif
+
+#ifdef YYTYPE_UINT8
+typedef YYTYPE_UINT8 yytype_uint8;
+#else
+typedef unsigned char yytype_uint8;
+#endif
+
+#ifdef YYTYPE_INT8
+typedef YYTYPE_INT8 yytype_int8;
+#else
+typedef signed char yytype_int8;
+#endif
+
+#ifdef YYTYPE_UINT16
+typedef YYTYPE_UINT16 yytype_uint16;
+#else
+typedef unsigned short int yytype_uint16;
+#endif
+
+#ifdef YYTYPE_INT16
+typedef YYTYPE_INT16 yytype_int16;
+#else
+typedef short int yytype_int16;
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+#  define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+#  define YYSIZE_T size_t
+# elif ! defined YYSIZE_T
+#  include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYSIZE_T size_t
+# else
+#  define YYSIZE_T unsigned int
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
+
+#ifndef YY_
+# if defined YYENABLE_NLS && YYENABLE_NLS
+#  if ENABLE_NLS
+#   include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+#   define YY_(Msgid) dgettext ("bison-runtime", Msgid)
+#  endif
+# endif
+# ifndef YY_
+#  define YY_(Msgid) Msgid
+# endif
+#endif
+
+#ifndef YY_ATTRIBUTE
+# if (defined __GNUC__                                               \
+      && (2 < __GNUC__ || (__GNUC__ == 2 && 96 <= __GNUC_MINOR__)))  \
+     || defined __SUNPRO_C && 0x5110 <= __SUNPRO_C
+#  define YY_ATTRIBUTE(Spec) __attribute__(Spec)
+# else
+#  define YY_ATTRIBUTE(Spec) /* empty */
+# endif
+#endif
+
+#ifndef YY_ATTRIBUTE_PURE
+# define YY_ATTRIBUTE_PURE   YY_ATTRIBUTE ((__pure__))
+#endif
+
+#ifndef YY_ATTRIBUTE_UNUSED
+# define YY_ATTRIBUTE_UNUSED YY_ATTRIBUTE ((__unused__))
+#endif
+
+#if !defined _Noreturn \
+     && (!defined __STDC_VERSION__ || __STDC_VERSION__ < 201112)
+# if defined _MSC_VER && 1200 <= _MSC_VER
+#  define _Noreturn __declspec (noreturn)
+# else
+#  define _Noreturn YY_ATTRIBUTE ((__noreturn__))
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E.  */
+#if ! defined lint || defined __GNUC__
+# define YYUSE(E) ((void) (E))
+#else
+# define YYUSE(E) /* empty */
+#endif
+
+#if defined __GNUC__ && 407 <= __GNUC__ * 100 + __GNUC_MINOR__
+/* Suppress an incorrect diagnostic about yylval being uninitialized.  */
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \
+    _Pragma ("GCC diagnostic push") \
+    _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")\
+    _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"")
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END \
+    _Pragma ("GCC diagnostic pop")
+#else
+# define YY_INITIAL_VALUE(Value) Value
+#endif
+#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END
+#endif
+#ifndef YY_INITIAL_VALUE
+# define YY_INITIAL_VALUE(Value) /* Nothing. */
+#endif
+
+
+#if ! defined yyoverflow || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols.  */
+
+# ifdef YYSTACK_USE_ALLOCA
+#  if YYSTACK_USE_ALLOCA
+#   ifdef __GNUC__
+#    define YYSTACK_ALLOC __builtin_alloca
+#   elif defined __BUILTIN_VA_ARG_INCR
+#    include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+#   elif defined _AIX
+#    define YYSTACK_ALLOC __alloca
+#   elif defined _MSC_VER
+#    include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+#    define alloca _alloca
+#   else
+#    define YYSTACK_ALLOC alloca
+#    if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS
+#     include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+      /* Use EXIT_SUCCESS as a witness for stdlib.h.  */
+#     ifndef EXIT_SUCCESS
+#      define EXIT_SUCCESS 0
+#     endif
+#    endif
+#   endif
+#  endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+   /* Pacify GCC's 'empty if-body' warning.  */
+#  define YYSTACK_FREE(Ptr) do { /* empty */; } while (0)
+#  ifndef YYSTACK_ALLOC_MAXIMUM
+    /* The OS might guarantee only one guard page at the bottom of the stack,
+       and a page size can be as small as 4096 bytes.  So we cannot safely
+       invoke alloca (N) if N exceeds 4096.  Use a slightly smaller number
+       to allow for a few compiler-allocated temporary stack slots.  */
+#   define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+#  endif
+# else
+#  define YYSTACK_ALLOC YYMALLOC
+#  define YYSTACK_FREE YYFREE
+#  ifndef YYSTACK_ALLOC_MAXIMUM
+#   define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+#  endif
+#  if (defined __cplusplus && ! defined EXIT_SUCCESS \
+       && ! ((defined YYMALLOC || defined malloc) \
+             && (defined YYFREE || defined free)))
+#   include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+#   ifndef EXIT_SUCCESS
+#    define EXIT_SUCCESS 0
+#   endif
+#  endif
+#  ifndef YYMALLOC
+#   define YYMALLOC malloc
+#   if ! defined malloc && ! defined EXIT_SUCCESS
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+#   endif
+#  endif
+#  ifndef YYFREE
+#   define YYFREE free
+#   if ! defined free && ! defined EXIT_SUCCESS
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+#   endif
+#  endif
+# endif
+#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
+
+
+#if (! defined yyoverflow \
+     && (! defined __cplusplus \
+         || (defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL \
+             && defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member.  */
+union yyalloc
+{
+  yytype_int16 yyss_alloc;
+  YYSTYPE yyvs_alloc;
+  YYLTYPE yyls_alloc;
+};
+
+/* The size of the maximum gap between one aligned stack and the next.  */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+   N elements.  */
+# define YYSTACK_BYTES(N) \
+     ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE) + sizeof (YYLTYPE)) \
+      + 2 * YYSTACK_GAP_MAXIMUM)
+
+# define YYCOPY_NEEDED 1
+
+/* Relocate STACK from its old location to the new one.  The
+   local variables YYSIZE and YYSTACKSIZE give the old and new number of
+   elements in the stack, and YYPTR gives the new location of the
+   stack.  Advance YYPTR to a properly aligned location for the next
+   stack.  */
+# define YYSTACK_RELOCATE(Stack_alloc, Stack)                           \
+    do                                                                  \
+      {                                                                 \
+        YYSIZE_T yynewbytes;                                            \
+        YYCOPY (&yyptr->Stack_alloc, Stack, yysize);                    \
+        Stack = &yyptr->Stack_alloc;                                    \
+        yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+        yyptr += yynewbytes / sizeof (*yyptr);                          \
+      }                                                                 \
+    while (0)
+
+#endif
+
+#if defined YYCOPY_NEEDED && YYCOPY_NEEDED
+/* Copy COUNT objects from SRC to DST.  The source and destination do
+   not overlap.  */
+# ifndef YYCOPY
+#  if defined __GNUC__ && 1 < __GNUC__
+#   define YYCOPY(Dst, Src, Count) \
+      __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src)))
+#  else
+#   define YYCOPY(Dst, Src, Count)              \
+      do                                        \
+        {                                       \
+          YYSIZE_T yyi;                         \
+          for (yyi = 0; yyi < (Count); yyi++)   \
+            (Dst)[yyi] = (Src)[yyi];            \
+        }                                       \
+      while (0)
+#  endif
+# endif
+#endif /* !YYCOPY_NEEDED */
+
+/* YYFINAL -- State number of the termination state.  */
+#define YYFINAL  8
+/* YYLAST -- Last index in YYTABLE.  */
+#define YYLAST   103
+
+/* YYNTOKENS -- Number of terminals.  */
+#define YYNTOKENS  24
+/* YYNNTS -- Number of nonterminals.  */
+#define YYNNTS  19
+/* YYNRULES -- Number of rules.  */
+#define YYNRULES  51
+/* YYNSTATES -- Number of states.  */
+#define YYNSTATES  93
+
+/* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned
+   by yylex, with out-of-bounds checking.  */
+#define YYUNDEFTOK  2
+#define YYMAXUTOK   273
+
+#define YYTRANSLATE(YYX)                                                \
+  ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM
+   as returned by yylex, without out-of-bounds checking.  */
+static const yytype_uint8 yytranslate[] =
+{
+       0,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,    19,     2,     2,    17,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,    20,     2,
+       2,    21,     2,     2,    18,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     1,     2,     3,     4,
+       5,     6,     7,     8,     9,    10,    11,    12,    13,    14,
+      15,    16,    22,    23
+};
+
+#if YYDEBUG
+  /* YYRLINE[YYN] -- Source line where rule number YYN was defined.  */
+static const yytype_uint16 yyrline[] =
+{
+       0,    60,    60,    63,    66,    74,    82,    89,    96,    99,
+     104,   107,   110,   113,   116,   122,   125,   128,   133,   138,
+     141,   144,   149,   154,   157,   160,   165,   168,   173,   177,
+     181,   185,   191,   194,   199,   202,   207,   210,   215,   220,
+     223,   228,   231,   234,   237,   242,   245,   250,   253,   256,
+     261,   264
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE || 0
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+   First, the terminals, then, starting at YYNTOKENS, nonterminals.  */
+static const char *const yytname[] =
+{
+  "$end", "error", "$undefined", "BUSNAME", "BOOTDEV", "IPV4", "IQN",
+  "OBPPARM", "OBPQUAL", "HEX4", "HEX16", "VDEVICE", "VDEVINST", "VDEVDEV",
+  "VDEVRAW", "CHOSEN", "FILENAME", "'/'", "'@'", "','", "':'", "'='",
+  "\"::\"", "\":\"", "$accept", "devpath", "busses", "bus", "bootdev",
+  "vdevice", "vdev_parms", "vdev_parm", "obp_params", "obp_param",
+  "obp_quals", "obp_qual", "ipaddr", "ipv4", "ipv6", "hexpart", "hexseq",
+  "disklabel", "diskpart", YY_NULLPTR
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[NUM] -- (External) token number corresponding to the
+   (internal) symbol number NUM (which must be that of a token).  */
+static const yytype_uint16 yytoknum[] =
+{
+       0,   256,   257,   258,   259,   260,   261,   262,   263,   264,
+     265,   266,   267,   268,   269,   270,   271,    47,    64,    44,
+      58,    61,   272,   273
+};
+# endif
+
+#define YYPACT_NINF -73
+
+#define yypact_value_is_default(Yystate) \
+  (!!((Yystate) == (-73)))
+
+#define YYTABLE_NINF -46
+
+#define yytable_value_is_error(Yytable_value) \
+  0
+
+  /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+     STATE-NUM.  */
+static const yytype_int8 yypact[] =
+{
+     -15,    19,    13,    20,    18,    23,   -73,    25,   -73,    39,
+      51,    50,    49,    16,    46,    43,    42,   -73,    47,   -73,
+      -9,   -73,   -73,    44,    45,    58,    59,   -73,    52,   -73,
+     -73,   -73,    56,    24,    61,    62,    64,   -73,   -73,    60,
+      55,    57,    38,     8,   -73,    41,    52,   -73,   -73,    37,
+     -73,    68,    63,    65,   -73,   -73,   -73,     3,   -73,   -73,
+     -73,     8,    69,   -73,    44,   -73,    -2,    44,   -73,   -73,
+     -73,    67,   -73,   -73,   -73,    36,   -73,   -73,    71,   -73,
+     -73,   -73,    11,    66,   -73,   -73,    66,    76,    71,    73,
+     -73,    66,   -73
+};
+
+  /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM.
+     Performed when YYTABLE does not specify something else to do.  Zero
+     means the default is an error.  */
+static const yytype_uint8 yydefact[] =
+{
+       0,     2,     0,    10,     0,     0,     8,     0,     1,     0,
+       0,     0,     0,     3,     0,     0,    11,    13,     0,    18,
+       0,     9,    34,     0,     0,     0,     0,    35,     0,    32,
+       4,    47,     0,     0,     0,     0,     0,    15,    48,     0,
+       0,    50,     0,     5,    19,     0,     0,    12,    14,     0,
+      22,     0,     0,     0,    26,    23,    33,     0,     6,    21,
+      20,     0,     0,    16,     0,    51,     0,    26,    24,    25,
+       7,     0,    49,    38,    29,    30,    27,    31,     0,    28,
+      36,    37,    39,    41,    17,    45,    44,     0,    42,     0,
+      40,    43,    46
+};
+
+  /* YYPGOTO[NTERM-NUM].  */
+static const yytype_int8 yypgoto[] =
+{
+     -73,   -73,   -73,    72,    78,   -73,   -73,   -27,    48,    26,
+      70,    53,   -73,     1,   -73,   -73,   -72,   -42,   -23
+};
+
+  /* YYDEFGOTO[NTERM-NUM].  */
+static const yytype_int8 yydefgoto[] =
+{
+      -1,     2,     5,     6,    13,     7,    33,    27,    43,    55,
+      28,    29,    79,    80,    81,    82,    83,    30,    31
+};
+
+  /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM.  If
+     positive, shift that token.  If negative, reduce the rule whose
+     number is the opposite.  If YYTABLE_NINF, syntax error.  */
+static const yytype_int8 yytable[] =
+{
+      38,    58,     1,    73,    74,    44,    86,    75,    76,    36,
+      53,    37,    67,     8,    77,    69,    91,    23,    60,    70,
+      78,    25,     3,    26,    22,    23,    25,    57,    26,    24,
+       4,    87,    22,    88,    25,    11,    26,    24,     9,    10,
+      12,    72,    14,    45,    38,    53,    22,    54,    16,    17,
+      20,    24,     3,    20,    24,    59,    62,    63,   -45,   -45,
+      18,    34,    19,    32,    26,    35,    39,    40,    41,    24,
+      47,    42,    48,    49,    51,    50,    52,    64,    71,    65,
+      85,    73,    92,    68,    21,    15,    66,    84,    90,    89,
+       0,     0,     0,     0,    61,    56,     0,     0,     0,     0,
+       0,     0,     0,    46
+};
+
+static const yytype_int8 yycheck[] =
+{
+      23,    43,    17,     5,     6,    32,    78,     9,    10,    18,
+       7,    20,     9,     0,    16,    57,    88,     9,    45,    61,
+      22,    18,     3,    20,     8,     9,    18,    19,    20,    13,
+      11,    20,     8,    22,    18,    17,    20,    13,    18,    19,
+      17,    64,    17,    19,    67,     7,     8,     9,     9,    10,
+       4,    13,     3,     4,    13,    14,    19,    20,    22,    23,
+       9,    19,    12,    20,    20,    18,    21,     9,     9,    13,
+       9,    19,    10,     9,    19,    15,    19,     9,     9,    16,
+       9,     5,     9,    57,    12,     7,    21,    20,    87,    23,
+      -1,    -1,    -1,    -1,    46,    42,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    33
+};
+
+  /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+     symbol of state STATE-NUM.  */
+static const yytype_uint8 yystos[] =
+{
+       0,    17,    25,     3,    11,    26,    27,    29,     0,    18,
+      19,    17,    17,    28,    17,    28,     9,    10,     9,    12,
+       4,    27,     8,     9,    13,    18,    20,    31,    34,    35,
+      41,    42,    20,    30,    19,    18,    18,    20,    42,    21,
+       9,     9,    19,    32,    31,    19,    34,     9,    10,     9,
+      15,    19,    19,     7,     9,    33,    35,    19,    41,    14,
+      31,    32,    19,    20,     9,    16,    21,     9,    33,    41,
+      41,     9,    42,     5,     6,     9,    10,    16,    22,    36,
+      37,    38,    39,    40,    20,     9,    40,    20,    22,    23,
+      37,    40,     9
+};
+
+  /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
+static const yytype_uint8 yyr1[] =
+{
+       0,    24,    25,    25,    25,    25,    25,    25,    26,    26,
+      27,    27,    27,    27,    27,    28,    28,    28,    29,    30,
+      30,    30,    31,    32,    32,    32,    33,    33,    33,    33,
+      33,    33,    34,    34,    35,    35,    36,    36,    37,    38,
+      38,    39,    39,    39,    39,    40,    40,    41,    41,    41,
+      42,    42
+};
+
+  /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN.  */
+static const yytype_uint8 yyr2[] =
+{
+       0,     2,     1,     3,     4,     5,     6,     7,     1,     3,
+       1,     3,     5,     3,     5,     3,     5,     7,     3,     2,
+       3,     3,     3,     2,     3,     3,     1,     3,     3,     3,
+       3,     3,     1,     3,     1,     1,     1,     1,     1,     1,
+       3,     1,     2,     3,     2,     1,     3,     1,     2,     5,
+       2,     4
+};
+
+
+#define yyerrok         (yyerrstatus = 0)
+#define yyclearin       (yychar = YYEMPTY)
+#define YYEMPTY         (-2)
+#define YYEOF           0
+
+#define YYACCEPT        goto yyacceptlab
+#define YYABORT         goto yyabortlab
+#define YYERROR         goto yyerrorlab
+
+
+#define YYRECOVERING()  (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value)                                  \
+do                                                              \
+  if (yychar == YYEMPTY)                                        \
+    {                                                           \
+      yychar = (Token);                                         \
+      yylval = (Value);                                         \
+      YYPOPSTACK (yylen);                                       \
+      yystate = *yyssp;                                         \
+      goto yybackup;                                            \
+    }                                                           \
+  else                                                          \
+    {                                                           \
+      yyerror (ofwdev, YY_("syntax error: cannot back up")); \
+      YYERROR;                                                  \
+    }                                                           \
+while (0)
+
+/* Error token number */
+#define YYTERROR        1
+#define YYERRCODE       256
+
+
+/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
+   If N is 0, then set CURRENT to the empty location which ends
+   the previous symbol: RHS[0] (always defined).  */
+
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N)                                \
+    do                                                                  \
+      if (N)                                                            \
+        {                                                               \
+          (Current).first_line   = YYRHSLOC (Rhs, 1).first_line;        \
+          (Current).first_column = YYRHSLOC (Rhs, 1).first_column;      \
+          (Current).last_line    = YYRHSLOC (Rhs, N).last_line;         \
+          (Current).last_column  = YYRHSLOC (Rhs, N).last_column;       \
+        }                                                               \
+      else                                                              \
+        {                                                               \
+          (Current).first_line   = (Current).last_line   =              \
+            YYRHSLOC (Rhs, 0).last_line;                                \
+          (Current).first_column = (Current).last_column =              \
+            YYRHSLOC (Rhs, 0).last_column;                              \
+        }                                                               \
+    while (0)
+#endif
+
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
+
+
+/* Enable debugging if requested.  */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+#  include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args)                        \
+do {                                            \
+  if (yydebug)                                  \
+    YYFPRINTF Args;                             \
+} while (0)
+
+
+/* YY_LOCATION_PRINT -- Print the location on the stream.
+   This macro was not mandated originally: define only if we know
+   we won't break user code: when these are the locations we know.  */
+
+#ifndef YY_LOCATION_PRINT
+# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
+
+/* Print *YYLOCP on YYO.  Private, do not rely on its existence. */
+
+YY_ATTRIBUTE_UNUSED
+static unsigned
+yy_location_print_ (FILE *yyo, YYLTYPE const * const yylocp)
+{
+  unsigned res = 0;
+  int end_col = 0 != yylocp->last_column ? yylocp->last_column - 1 : 0;
+  if (0 <= yylocp->first_line)
+    {
+      res += YYFPRINTF (yyo, "%d", yylocp->first_line);
+      if (0 <= yylocp->first_column)
+        res += YYFPRINTF (yyo, ".%d", yylocp->first_column);
+    }
+  if (0 <= yylocp->last_line)
+    {
+      if (yylocp->first_line < yylocp->last_line)
+        {
+          res += YYFPRINTF (yyo, "-%d", yylocp->last_line);
+          if (0 <= end_col)
+            res += YYFPRINTF (yyo, ".%d", end_col);
+        }
+      else if (0 <= end_col && yylocp->first_column < end_col)
+        res += YYFPRINTF (yyo, "-%d", end_col);
+    }
+  return res;
+ }
+
+#  define YY_LOCATION_PRINT(File, Loc)          \
+  yy_location_print_ (File, &(Loc))
+
+# else
+#  define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
+#endif
+
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)                    \
+do {                                                                      \
+  if (yydebug)                                                            \
+    {                                                                     \
+      YYFPRINTF (stderr, "%s ", Title);                                   \
+      yy_symbol_print (stderr,                                            \
+                  Type, Value, Location, ofwdev); \
+      YYFPRINTF (stderr, "\n");                                           \
+    }                                                                     \
+} while (0)
+
+
+/*----------------------------------------.
+| Print this symbol's value on YYOUTPUT.  |
+`----------------------------------------*/
+
+static void
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, struct ofw_dev *ofwdev)
+{
+  FILE *yyo = yyoutput;
+  YYUSE (yyo);
+  YYUSE (yylocationp);
+  YYUSE (ofwdev);
+  if (!yyvaluep)
+    return;
+# ifdef YYPRINT
+  if (yytype < YYNTOKENS)
+    YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# endif
+  YYUSE (yytype);
+}
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT.  |
+`--------------------------------*/
+
+static void
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, struct ofw_dev *ofwdev)
+{
+  YYFPRINTF (yyoutput, "%s %s (",
+             yytype < YYNTOKENS ? "token" : "nterm", yytname[yytype]);
+
+  YY_LOCATION_PRINT (yyoutput, *yylocationp);
+  YYFPRINTF (yyoutput, ": ");
+  yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp, ofwdev);
+  YYFPRINTF (yyoutput, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included).                                                   |
+`------------------------------------------------------------------*/
+
+static void
+yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
+{
+  YYFPRINTF (stderr, "Stack now");
+  for (; yybottom <= yytop; yybottom++)
+    {
+      int yybot = *yybottom;
+      YYFPRINTF (stderr, " %d", yybot);
+    }
+  YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top)                            \
+do {                                                            \
+  if (yydebug)                                                  \
+    yy_stack_print ((Bottom), (Top));                           \
+} while (0)
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced.  |
+`------------------------------------------------*/
+
+static void
+yy_reduce_print (yytype_int16 *yyssp, YYSTYPE *yyvsp, YYLTYPE *yylsp, int yyrule, struct ofw_dev *ofwdev)
+{
+  unsigned long int yylno = yyrline[yyrule];
+  int yynrhs = yyr2[yyrule];
+  int yyi;
+  YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+             yyrule - 1, yylno);
+  /* The symbols being reduced.  */
+  for (yyi = 0; yyi < yynrhs; yyi++)
+    {
+      YYFPRINTF (stderr, "   $%d = ", yyi + 1);
+      yy_symbol_print (stderr,
+                       yystos[yyssp[yyi + 1 - yynrhs]],
+                       &(yyvsp[(yyi + 1) - (yynrhs)])
+                       , &(yylsp[(yyi + 1) - (yynrhs)])                       , ofwdev);
+      YYFPRINTF (stderr, "\n");
+    }
+}
+
+# define YY_REDUCE_PRINT(Rule)          \
+do {                                    \
+  if (yydebug)                          \
+    yy_reduce_print (yyssp, yyvsp, yylsp, Rule, ofwdev); \
+} while (0)
+
+/* Nonzero means print parse trace.  It is left uninitialized so that
+   multiple parsers can coexist.  */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks.  */
+#ifndef YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+   if the built-in stack extension method is used).
+
+   Do not make this value too large; the results are undefined if
+   YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+   evaluated with infinite-precision integer arithmetic.  */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+#  if defined __GLIBC__ && defined _STRING_H
+#   define yystrlen strlen
+#  else
+/* Return the length of YYSTR.  */
+static YYSIZE_T
+yystrlen (const char *yystr)
+{
+  YYSIZE_T yylen;
+  for (yylen = 0; yystr[yylen]; yylen++)
+    continue;
+  return yylen;
+}
+#  endif
+# endif
+
+# ifndef yystpcpy
+#  if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+#   define yystpcpy stpcpy
+#  else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+   YYDEST.  */
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+{
+  char *yyd = yydest;
+  const char *yys = yysrc;
+
+  while ((*yyd++ = *yys++) != '\0')
+    continue;
+
+  return yyd - 1;
+}
+#  endif
+# endif
+
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+   quotes and backslashes, so that it's suitable for yyerror.  The
+   heuristic is that double-quoting is unnecessary unless the string
+   contains an apostrophe, a comma, or backslash (other than
+   backslash-backslash).  YYSTR is taken from yytname.  If YYRES is
+   null, do not copy; instead, return the length of what the result
+   would have been.  */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+  if (*yystr == '"')
+    {
+      YYSIZE_T yyn = 0;
+      char const *yyp = yystr;
+
+      for (;;)
+        switch (*++yyp)
+          {
+          case '\'':
+          case ',':
+            goto do_not_strip_quotes;
+
+          case '\\':
+            if (*++yyp != '\\')
+              goto do_not_strip_quotes;
+            /* Fall through.  */
+          default:
+            if (yyres)
+              yyres[yyn] = *yyp;
+            yyn++;
+            break;
+
+          case '"':
+            if (yyres)
+              yyres[yyn] = '\0';
+            return yyn;
+          }
+    do_not_strip_quotes: ;
+    }
+
+  if (! yyres)
+    return yystrlen (yystr);
+
+  return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
+
+/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message
+   about the unexpected token YYTOKEN for the state stack whose top is
+   YYSSP.
+
+   Return 0 if *YYMSG was successfully written.  Return 1 if *YYMSG is
+   not large enough to hold the message.  In that case, also set
+   *YYMSG_ALLOC to the required number of bytes.  Return 2 if the
+   required number of bytes is too large to store.  */
+static int
+yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
+                yytype_int16 *yyssp, int yytoken)
+{
+  YYSIZE_T yysize0 = yytnamerr (YY_NULLPTR, yytname[yytoken]);
+  YYSIZE_T yysize = yysize0;
+  enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+  /* Internationalized format string. */
+  const char *yyformat = YY_NULLPTR;
+  /* Arguments of yyformat. */
+  char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+  /* Number of reported tokens (one for the "unexpected", one per
+     "expected"). */
+  int yycount = 0;
+
+  /* There are many possibilities here to consider:
+     - If this state is a consistent state with a default action, then
+       the only way this function was invoked is if the default action
+       is an error action.  In that case, don't check for expected
+       tokens because there are none.
+     - The only way there can be no lookahead present (in yychar) is if
+       this state is a consistent state with a default action.  Thus,
+       detecting the absence of a lookahead is sufficient to determine
+       that there is no unexpected or expected token to report.  In that
+       case, just report a simple "syntax error".
+     - Don't assume there isn't a lookahead just because this state is a
+       consistent state with a default action.  There might have been a
+       previous inconsistent state, consistent state with a non-default
+       action, or user semantic action that manipulated yychar.
+     - Of course, the expected token list depends on states to have
+       correct lookahead information, and it depends on the parser not
+       to perform extra reductions after fetching a lookahead from the
+       scanner and before detecting a syntax error.  Thus, state merging
+       (from LALR or IELR) and default reductions corrupt the expected
+       token list.  However, the list is correct for canonical LR with
+       one exception: it will still contain any token that will not be
+       accepted due to an error action in a later state.
+  */
+  if (yytoken != YYEMPTY)
+    {
+      int yyn = yypact[*yyssp];
+      yyarg[yycount++] = yytname[yytoken];
+      if (!yypact_value_is_default (yyn))
+        {
+          /* Start YYX at -YYN if negative to avoid negative indexes in
+             YYCHECK.  In other words, skip the first -YYN actions for
+             this state because they are default actions.  */
+          int yyxbegin = yyn < 0 ? -yyn : 0;
+          /* Stay within bounds of both yycheck and yytname.  */
+          int yychecklim = YYLAST - yyn + 1;
+          int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+          int yyx;
+
+          for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+            if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR
+                && !yytable_value_is_error (yytable[yyx + yyn]))
+              {
+                if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+                  {
+                    yycount = 1;
+                    yysize = yysize0;
+                    break;
+                  }
+                yyarg[yycount++] = yytname[yyx];
+                {
+                  YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULLPTR, yytname[yyx]);
+                  if (! (yysize <= yysize1
+                         && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+                    return 2;
+                  yysize = yysize1;
+                }
+              }
+        }
+    }
+
+  switch (yycount)
+    {
+# define YYCASE_(N, S)                      \
+      case N:                               \
+        yyformat = S;                       \
+      break
+      YYCASE_(0, YY_("syntax error"));
+      YYCASE_(1, YY_("syntax error, unexpected %s"));
+      YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s"));
+      YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s"));
+      YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s"));
+      YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"));
+# undef YYCASE_
+    }
+
+  {
+    YYSIZE_T yysize1 = yysize + yystrlen (yyformat);
+    if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+      return 2;
+    yysize = yysize1;
+  }
+
+  if (*yymsg_alloc < yysize)
+    {
+      *yymsg_alloc = 2 * yysize;
+      if (! (yysize <= *yymsg_alloc
+             && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM))
+        *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM;
+      return 1;
+    }
+
+  /* Avoid sprintf, as that infringes on the user's name space.
+     Don't have undefined behavior even if the translation
+     produced a string with the wrong number of "%s"s.  */
+  {
+    char *yyp = *yymsg;
+    int yyi = 0;
+    while ((*yyp = *yyformat) != '\0')
+      if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount)
+        {
+          yyp += yytnamerr (yyp, yyarg[yyi++]);
+          yyformat += 2;
+        }
+      else
+        {
+          yyp++;
+          yyformat++;
+        }
+  }
+  return 0;
+}
+#endif /* YYERROR_VERBOSE */
+
+/*-----------------------------------------------.
+| Release the memory associated to this symbol.  |
+`-----------------------------------------------*/
+
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, YYLTYPE *yylocationp, struct ofw_dev *ofwdev)
+{
+  YYUSE (yyvaluep);
+  YYUSE (yylocationp);
+  YYUSE (ofwdev);
+  if (!yymsg)
+    yymsg = "Deleting";
+  YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+  YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+  YYUSE (yytype);
+  YY_IGNORE_MAYBE_UNINITIALIZED_END
+}
+
+
+
+
+/* The lookahead symbol.  */
+int yychar;
+
+/* The semantic value of the lookahead symbol.  */
+YYSTYPE yylval;
+/* Location data for the lookahead symbol.  */
+YYLTYPE yylloc
+# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
+  = { 1, 1, 1, 1 }
+# endif
+;
+/* Number of syntax errors so far.  */
+int yynerrs;
+
+
+/*----------.
+| yyparse.  |
+`----------*/
+
+int
+yyparse (struct ofw_dev *ofwdev)
+{
+    int yystate;
+    /* Number of tokens to shift before error messages enabled.  */
+    int yyerrstatus;
+
+    /* The stacks and their tools:
+       'yyss': related to states.
+       'yyvs': related to semantic values.
+       'yyls': related to locations.
+
+       Refer to the stacks through separate pointers, to allow yyoverflow
+       to reallocate them elsewhere.  */
+
+    /* The state stack.  */
+    yytype_int16 yyssa[YYINITDEPTH];
+    yytype_int16 *yyss;
+    yytype_int16 *yyssp;
+
+    /* The semantic value stack.  */
+    YYSTYPE yyvsa[YYINITDEPTH];
+    YYSTYPE *yyvs;
+    YYSTYPE *yyvsp;
+
+    /* The location stack.  */
+    YYLTYPE yylsa[YYINITDEPTH];
+    YYLTYPE *yyls;
+    YYLTYPE *yylsp;
+
+    /* The locations where the error started and ended.  */
+    YYLTYPE yyerror_range[3];
+
+    YYSIZE_T yystacksize;
+
+  int yyn;
+  int yyresult;
+  /* Lookahead token as an internal (translated) token number.  */
+  int yytoken = 0;
+  /* The variables used to return semantic value and location from the
+     action routines.  */
+  YYSTYPE yyval;
+  YYLTYPE yyloc;
+
+#if YYERROR_VERBOSE
+  /* Buffer for error messages, and its allocated size.  */
+  char yymsgbuf[128];
+  char *yymsg = yymsgbuf;
+  YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
+#endif
+
+#define YYPOPSTACK(N)   (yyvsp -= (N), yyssp -= (N), yylsp -= (N))
+
+  /* The number of symbols on the RHS of the reduced rule.
+     Keep to zero when no symbol should be popped.  */
+  int yylen = 0;
+
+  yyssp = yyss = yyssa;
+  yyvsp = yyvs = yyvsa;
+  yylsp = yyls = yylsa;
+  yystacksize = YYINITDEPTH;
+
+  YYDPRINTF ((stderr, "Starting parse\n"));
+
+  yystate = 0;
+  yyerrstatus = 0;
+  yynerrs = 0;
+  yychar = YYEMPTY; /* Cause a token to be read.  */
+  yylsp[0] = yylloc;
+  goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate.  |
+`------------------------------------------------------------*/
+ yynewstate:
+  /* In all cases, when you get here, the value and location stacks
+     have just been pushed.  So pushing a state here evens the stacks.  */
+  yyssp++;
+
+ yysetstate:
+  *yyssp = yystate;
+
+  if (yyss + yystacksize - 1 <= yyssp)
+    {
+      /* Get the current used size of the three stacks, in elements.  */
+      YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+      {
+        /* Give user a chance to reallocate the stack.  Use copies of
+           these so that the &'s don't force the real ones into
+           memory.  */
+        YYSTYPE *yyvs1 = yyvs;
+        yytype_int16 *yyss1 = yyss;
+        YYLTYPE *yyls1 = yyls;
+
+        /* Each stack pointer address is followed by the size of the
+           data in use in that stack, in bytes.  This used to be a
+           conditional around just the two extra args, but that might
+           be undefined if yyoverflow is a macro.  */
+        yyoverflow (YY_("memory exhausted"),
+                    &yyss1, yysize * sizeof (*yyssp),
+                    &yyvs1, yysize * sizeof (*yyvsp),
+                    &yyls1, yysize * sizeof (*yylsp),
+                    &yystacksize);
+
+        yyls = yyls1;
+        yyss = yyss1;
+        yyvs = yyvs1;
+      }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+      goto yyexhaustedlab;
+# else
+      /* Extend the stack our own way.  */
+      if (YYMAXDEPTH <= yystacksize)
+        goto yyexhaustedlab;
+      yystacksize *= 2;
+      if (YYMAXDEPTH < yystacksize)
+        yystacksize = YYMAXDEPTH;
+
+      {
+        yytype_int16 *yyss1 = yyss;
+        union yyalloc *yyptr =
+          (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+        if (! yyptr)
+          goto yyexhaustedlab;
+        YYSTACK_RELOCATE (yyss_alloc, yyss);
+        YYSTACK_RELOCATE (yyvs_alloc, yyvs);
+        YYSTACK_RELOCATE (yyls_alloc, yyls);
+#  undef YYSTACK_RELOCATE
+        if (yyss1 != yyssa)
+          YYSTACK_FREE (yyss1);
+      }
+# endif
+#endif /* no yyoverflow */
+
+      yyssp = yyss + yysize - 1;
+      yyvsp = yyvs + yysize - 1;
+      yylsp = yyls + yysize - 1;
+
+      YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+                  (unsigned long int) yystacksize));
+
+      if (yyss + yystacksize - 1 <= yyssp)
+        YYABORT;
+    }
+
+  YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+  if (yystate == YYFINAL)
+    YYACCEPT;
+
+  goto yybackup;
+
+/*-----------.
+| yybackup.  |
+`-----------*/
+yybackup:
+
+  /* Do appropriate processing given the current state.  Read a
+     lookahead token if we need one and don't already have one.  */
+
+  /* First try to decide what to do without reference to lookahead token.  */
+  yyn = yypact[yystate];
+  if (yypact_value_is_default (yyn))
+    goto yydefault;
+
+  /* Not known => get a lookahead token if don't already have one.  */
+
+  /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol.  */
+  if (yychar == YYEMPTY)
+    {
+      YYDPRINTF ((stderr, "Reading a token: "));
+      yychar = yylex ();
+    }
+
+  if (yychar <= YYEOF)
+    {
+      yychar = yytoken = YYEOF;
+      YYDPRINTF ((stderr, "Now at end of input.\n"));
+    }
+  else
+    {
+      yytoken = YYTRANSLATE (yychar);
+      YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+    }
+
+  /* If the proper action on seeing token YYTOKEN is to reduce or to
+     detect an error, take that action.  */
+  yyn += yytoken;
+  if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+    goto yydefault;
+  yyn = yytable[yyn];
+  if (yyn <= 0)
+    {
+      if (yytable_value_is_error (yyn))
+        goto yyerrlab;
+      yyn = -yyn;
+      goto yyreduce;
+    }
+
+  /* Count tokens shifted since error; after three, turn off error
+     status.  */
+  if (yyerrstatus)
+    yyerrstatus--;
+
+  /* Shift the lookahead token.  */
+  YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+  /* Discard the shifted token.  */
+  yychar = YYEMPTY;
+
+  yystate = yyn;
+  YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+  *++yyvsp = yylval;
+  YY_IGNORE_MAYBE_UNINITIALIZED_END
+  *++yylsp = yylloc;
+  goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state.  |
+`-----------------------------------------------------------*/
+yydefault:
+  yyn = yydefact[yystate];
+  if (yyn == 0)
+    goto yyerrlab;
+  goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction.  |
+`-----------------------------*/
+yyreduce:
+  /* yyn is the number of a rule to reduce with.  */
+  yylen = yyr2[yyn];
+
+  /* If YYLEN is nonzero, implement the default value of the action:
+     '$$ = $1'.
+
+     Otherwise, the following line sets YYVAL to garbage.
+     This behavior is undocumented and Bison
+     users should not rely upon it.  Assigning to YYVAL
+     unconditionally makes the parser a bit smaller, and it avoids a
+     GCC warning that YYVAL may be used uninitialized.  */
+  yyval = yyvsp[1-yylen];
+
+  /* Default location.  */
+  YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen);
+  YY_REDUCE_PRINT (yyn);
+  switch (yyn)
+    {
+        case 2:
+#line 60 "prom_parse.y" /* yacc.c:1646  */
+    {
+                       DPRINT("****rootonly: \"%s\"\n", "/");
+               }
+#line 1410 "prom_parse.tab.c" /* yacc.c:1646  */
+    break;
+
+  case 3:
+#line 63 "prom_parse.y" /* yacc.c:1646  */
+    {
+                       DPRINT("****devpath busses:\n/%s/%s\n", (yyvsp[-1].str), (yyvsp[0].str));
+               }
+#line 1418 "prom_parse.tab.c" /* yacc.c:1646  */
+    break;
+
+  case 4:
+#line 66 "prom_parse.y" /* yacc.c:1646  */
+    {
+                       ofwdev->dev_path = malloc(strlen((yyvsp[-2].str)) +
+                                      strlen((yyvsp[-1].str)) + 3);
+                       sprintf(ofwdev->dev_path, "/%s%s", (yyvsp[-2].str), (yyvsp[-1].str));
+                       DPRINT("****devpath busses bootdev "
+                   "disklabel:\n/%s/%s%s\n",
+                                  (yyvsp[-2].str), (yyvsp[-1].str), (yyvsp[0].str));
+               }
+#line 1431 "prom_parse.tab.c" /* yacc.c:1646  */
+    break;
+
+  case 5:
+#line 74 "prom_parse.y" /* yacc.c:1646  */
+    {
+                       ofwdev->dev_path = malloc(strlen((yyvsp[-3].str)) +
+                                      strlen((yyvsp[-2].str)) + 3);
+                       sprintf(ofwdev->dev_path, "/%s%s", (yyvsp[-3].str), (yyvsp[-2].str));
+                       DPRINT("****busses bootdev obp_quals obp_parms:\n"
+                   "/%s/%s:%s%s\n",
+                                  (yyvsp[-3].str), (yyvsp[-2].str), (yyvsp[-1].str), (yyvsp[0].str));
+               }
+#line 1444 "prom_parse.tab.c" /* yacc.c:1646  */
+    break;
+
+  case 6:
+#line 82 "prom_parse.y" /* yacc.c:1646  */
+    {
+                       ofwdev->dev_path = malloc(strlen((yyvsp[-4].str)) +
+                                      strlen((yyvsp[-3].str)) + 3);
+                       sprintf(ofwdev->dev_path, "/%s%s", (yyvsp[-4].str), (yyvsp[-3].str));
+                       DPRINT("****busses bootdev obp_quals obp_parms "
+                   "disklabel:\n/%s:%s%s%s\n", (yyvsp[-4].str), (yyvsp[-2].str), (yyvsp[-1].str), (yyvsp[0].str));
+               }
+#line 1456 "prom_parse.tab.c" /* yacc.c:1646  */
+    break;
+
+  case 7:
+#line 89 "prom_parse.y" /* yacc.c:1646  */
+    {
+                       DPRINT("****vdevice bootdev obp_parms "
+                   "disklabel:\n/%s:%s%s%s%s\n",
+                                  (yyvsp[-5].str), (yyvsp[-3].str), (yyvsp[-2].str), (yyvsp[-1].str), (yyvsp[0].str));
+               }
+#line 1466 "prom_parse.tab.c" /* yacc.c:1646  */
+    break;
+
+  case 8:
+#line 96 "prom_parse.y" /* yacc.c:1646  */
+    {
+                       strcpy((yyval.str), (yyvsp[0].str));
+               }
+#line 1474 "prom_parse.tab.c" /* yacc.c:1646  */
+    break;
+
+  case 9:
+#line 99 "prom_parse.y" /* yacc.c:1646  */
+    {
+                       snprintf((yyval.str), STR_LEN, "%s/%s", (yyvsp[-2].str), (yyvsp[0].str));
+               }
+#line 1482 "prom_parse.tab.c" /* yacc.c:1646  */
+    break;
+
+  case 10:
+#line 104 "prom_parse.y" /* yacc.c:1646  */
+    {
+                       strcpy((yyval.str), (yyvsp[0].str));
+               }
+#line 1490 "prom_parse.tab.c" /* yacc.c:1646  */
+    break;
+
+  case 11:
+#line 107 "prom_parse.y" /* yacc.c:1646  */
+    {
+                       snprintf((yyval.str), STR_LEN, "%s@%s", (yyvsp[-2].str), (yyvsp[0].str));
+               }
+#line 1498 "prom_parse.tab.c" /* yacc.c:1646  */
+    break;
+
+  case 12:
+#line 110 "prom_parse.y" /* yacc.c:1646  */
+    {
+                       snprintf((yyval.str), STR_LEN, "%s@%s,%s", (yyvsp[-4].str), (yyvsp[-2].str), (yyvsp[0].str));
+               }
+#line 1506 "prom_parse.tab.c" /* yacc.c:1646  */
+    break;
+
+  case 13:
+#line 113 "prom_parse.y" /* yacc.c:1646  */
+    {
+                       snprintf((yyval.str), STR_LEN, "%s@%s", (yyvsp[-2].str), (yyvsp[0].str));
+               }
+#line 1514 "prom_parse.tab.c" /* yacc.c:1646  */
+    break;
+
+  case 14:
+#line 116 "prom_parse.y" /* yacc.c:1646  */
+    {
+                       snprintf((yyval.str), STR_LEN, "%s,%s@%s", (yyvsp[-4].str), (yyvsp[-2].str), (yyvsp[0].str));
+               }
+#line 1522 "prom_parse.tab.c" /* yacc.c:1646  */
+    break;
+
+  case 15:
+#line 122 "prom_parse.y" /* yacc.c:1646  */
+    {
+                       snprintf((yyval.str), STR_LEN, "/%s", (yyvsp[-1].str));
+               }
+#line 1530 "prom_parse.tab.c" /* yacc.c:1646  */
+    break;
+
+  case 16:
+#line 125 "prom_parse.y" /* yacc.c:1646  */
+    {
+                       snprintf((yyval.str), STR_LEN, "/%s@%s", (yyvsp[-3].str), (yyvsp[-1].str));
+               }
+#line 1538 "prom_parse.tab.c" /* yacc.c:1646  */
+    break;
+
+  case 17:
+#line 128 "prom_parse.y" /* yacc.c:1646  */
+    {
+                       snprintf((yyval.str), STR_LEN, "/%s@%s,%s", (yyvsp[-5].str), (yyvsp[-3].str), (yyvsp[-1].str));
+               }
+#line 1546 "prom_parse.tab.c" /* yacc.c:1646  */
+    break;
+
+  case 18:
+#line 133 "prom_parse.y" /* yacc.c:1646  */
+    {
+                       snprintf((yyval.str), STR_LEN, "%s/%s", (yyvsp[-2].str), (yyvsp[0].str));
+               }
+#line 1554 "prom_parse.tab.c" /* yacc.c:1646  */
+    break;
+
+  case 19:
+#line 138 "prom_parse.y" /* yacc.c:1646  */
+    {
+                       snprintf((yyval.str), STR_LEN, ":%s", (yyvsp[0].str));
+               }
+#line 1562 "prom_parse.tab.c" /* yacc.c:1646  */
+    break;
+
+  case 20:
+#line 141 "prom_parse.y" /* yacc.c:1646  */
+    {
+                       snprintf((yyval.str), STR_LEN, "%s,%s", (yyvsp[-2].str), (yyvsp[0].str));
+               }
+#line 1570 "prom_parse.tab.c" /* yacc.c:1646  */
+    break;
+
+  case 21:
+#line 144 "prom_parse.y" /* yacc.c:1646  */
+    {
+                       snprintf((yyval.str), STR_LEN, "%s,%s", (yyvsp[-2].str), (yyvsp[0].str));
+               }
+#line 1578 "prom_parse.tab.c" /* yacc.c:1646  */
+    break;
+
+  case 22:
+#line 149 "prom_parse.y" /* yacc.c:1646  */
+    {
+                       snprintf((yyval.str), STR_LEN, "%s=%s", (yyvsp[-2].str), (yyvsp[0].str));
+               }
+#line 1586 "prom_parse.tab.c" /* yacc.c:1646  */
+    break;
+
+  case 23:
+#line 154 "prom_parse.y" /* yacc.c:1646  */
+    {
+                       snprintf((yyval.str), STR_LEN, ",%s", (yyvsp[0].str));
+               }
+#line 1594 "prom_parse.tab.c" /* yacc.c:1646  */
+    break;
+
+  case 24:
+#line 157 "prom_parse.y" /* yacc.c:1646  */
+    {
+                       snprintf((yyval.str), STR_LEN, "%s,%s", (yyvsp[-2].str), (yyvsp[0].str));
+               }
+#line 1602 "prom_parse.tab.c" /* yacc.c:1646  */
+    break;
+
+  case 25:
+#line 160 "prom_parse.y" /* yacc.c:1646  */
+    {
+                       snprintf((yyval.str), STR_LEN, "%s,%s", (yyvsp[-2].str), (yyvsp[0].str));
+               }
+#line 1610 "prom_parse.tab.c" /* yacc.c:1646  */
+    break;
+
+  case 26:
+#line 165 "prom_parse.y" /* yacc.c:1646  */
+    {
+                       snprintf((yyval.str), STR_LEN, "%s", (yyvsp[0].str));
+               }
+#line 1618 "prom_parse.tab.c" /* yacc.c:1646  */
+    break;
+
+  case 27:
+#line 168 "prom_parse.y" /* yacc.c:1646  */
+    {
+                       /* luns > 0 are the SAM-3+ hex representation. */
+                       obp_parm_hexnum(ofwdev, (yyvsp[-2].str), (yyvsp[0].str));
+                       snprintf((yyval.str), STR_LEN, "%s=%s", (yyvsp[-2].str), (yyvsp[0].str));
+               }
+#line 1628 "prom_parse.tab.c" /* yacc.c:1646  */
+    break;
+
+  case 28:
+#line 173 "prom_parse.y" /* yacc.c:1646  */
+    {
+                       obp_parm_addr(ofwdev, (yyvsp[-2].str), (yyvsp[0].str));
+                       snprintf((yyval.str), STR_LEN, "%s=%s", (yyvsp[-2].str), (yyvsp[0].str));
+               }
+#line 1637 "prom_parse.tab.c" /* yacc.c:1646  */
+    break;
+
+  case 29:
+#line 177 "prom_parse.y" /* yacc.c:1646  */
+    {
+                       obp_parm_iqn(ofwdev, (yyvsp[-2].str), (yyvsp[0].str));
+                       snprintf((yyval.str), STR_LEN, "%s=%s", (yyvsp[-2].str), (yyvsp[0].str));
+               }
+#line 1646 "prom_parse.tab.c" /* yacc.c:1646  */
+    break;
+
+  case 30:
+#line 181 "prom_parse.y" /* yacc.c:1646  */
+    {
+                       obp_parm_hexnum(ofwdev, (yyvsp[-2].str), (yyvsp[0].str));
+                       snprintf((yyval.str), STR_LEN, "%s=%s", (yyvsp[-2].str), (yyvsp[0].str));
+               }
+#line 1655 "prom_parse.tab.c" /* yacc.c:1646  */
+    break;
+
+  case 31:
+#line 185 "prom_parse.y" /* yacc.c:1646  */
+    {
+                       obp_parm_str(ofwdev, (yyvsp[-2].str), (yyvsp[0].str));
+                       snprintf((yyval.str), STR_LEN, "%s=%s", (yyvsp[-2].str), (yyvsp[0].str));
+               }
+#line 1664 "prom_parse.tab.c" /* yacc.c:1646  */
+    break;
+
+  case 32:
+#line 191 "prom_parse.y" /* yacc.c:1646  */
+    {
+                       snprintf((yyval.str), STR_LEN, "%s", (yyvsp[0].str));
+               }
+#line 1672 "prom_parse.tab.c" /* yacc.c:1646  */
+    break;
+
+  case 33:
+#line 194 "prom_parse.y" /* yacc.c:1646  */
+    {
+                       snprintf((yyval.str), STR_LEN, "%s,%s", (yyvsp[-2].str), (yyvsp[0].str));
+               }
+#line 1680 "prom_parse.tab.c" /* yacc.c:1646  */
+    break;
+
+  case 34:
+#line 199 "prom_parse.y" /* yacc.c:1646  */
+    {
+                       snprintf((yyval.str), STR_LEN, "%s", obp_qual_set(ofwdev, (yyvsp[0].str)));
+               }
+#line 1688 "prom_parse.tab.c" /* yacc.c:1646  */
+    break;
+
+  case 35:
+#line 202 "prom_parse.y" /* yacc.c:1646  */
+    {
+                       snprintf((yyval.str), STR_LEN, "%s", (yyvsp[0].str));
+               }
+#line 1696 "prom_parse.tab.c" /* yacc.c:1646  */
+    break;
+
+  case 36:
+#line 207 "prom_parse.y" /* yacc.c:1646  */
+    {
+                       snprintf((yyval.str), STR_LEN, "%s", (yyvsp[0].str));
+               }
+#line 1704 "prom_parse.tab.c" /* yacc.c:1646  */
+    break;
+
+  case 37:
+#line 210 "prom_parse.y" /* yacc.c:1646  */
+    {
+                       snprintf((yyval.str), STR_LEN, "%s", (yyvsp[0].str));
+               }
+#line 1712 "prom_parse.tab.c" /* yacc.c:1646  */
+    break;
+
+  case 38:
+#line 215 "prom_parse.y" /* yacc.c:1646  */
+    {
+                       snprintf((yyval.str), STR_LEN, "%s", (yyvsp[0].str));
+               }
+#line 1720 "prom_parse.tab.c" /* yacc.c:1646  */
+    break;
+
+  case 39:
+#line 220 "prom_parse.y" /* yacc.c:1646  */
+    {
+                       snprintf((yyval.str), STR_LEN, "%s", (yyvsp[0].str));
+               }
+#line 1728 "prom_parse.tab.c" /* yacc.c:1646  */
+    break;
+
+  case 40:
+#line 223 "prom_parse.y" /* yacc.c:1646  */
+    {
+                       snprintf((yyval.str), STR_LEN, "%s:%s", (yyvsp[-2].str), (yyvsp[0].str));
+               }
+#line 1736 "prom_parse.tab.c" /* yacc.c:1646  */
+    break;
+
+  case 41:
+#line 228 "prom_parse.y" /* yacc.c:1646  */
+    {
+                       snprintf((yyval.str), STR_LEN, "%s", (yyvsp[0].str));
+               }
+#line 1744 "prom_parse.tab.c" /* yacc.c:1646  */
+    break;
+
+  case 42:
+#line 231 "prom_parse.y" /* yacc.c:1646  */
+    {
+                       snprintf((yyval.str), STR_LEN, "%s::", (yyvsp[-1].str));
+               }
+#line 1752 "prom_parse.tab.c" /* yacc.c:1646  */
+    break;
+
+  case 43:
+#line 234 "prom_parse.y" /* yacc.c:1646  */
+    {
+                       snprintf((yyval.str), STR_LEN, "%s::%s", (yyvsp[-2].str), (yyvsp[0].str));
+               }
+#line 1760 "prom_parse.tab.c" /* yacc.c:1646  */
+    break;
+
+  case 44:
+#line 237 "prom_parse.y" /* yacc.c:1646  */
+    {
+                       snprintf((yyval.str), STR_LEN, "::%s", (yyvsp[0].str));
+               }
+#line 1768 "prom_parse.tab.c" /* yacc.c:1646  */
+    break;
+
+  case 45:
+#line 242 "prom_parse.y" /* yacc.c:1646  */
+    {
+            snprintf((yyval.str), STR_LEN, "%s", (yyvsp[0].str));
+        }
+#line 1776 "prom_parse.tab.c" /* yacc.c:1646  */
+    break;
+
+  case 46:
+#line 245 "prom_parse.y" /* yacc.c:1646  */
+    {
+            snprintf((yyval.str), STR_LEN, "%s:%s", (yyvsp[-2].str), (yyvsp[0].str));
+        }
+#line 1784 "prom_parse.tab.c" /* yacc.c:1646  */
+    break;
+
+  case 47:
+#line 250 "prom_parse.y" /* yacc.c:1646  */
+    {
+            snprintf((yyval.str), STR_LEN, "%s", (yyvsp[0].str));
+        }
+#line 1792 "prom_parse.tab.c" /* yacc.c:1646  */
+    break;
+
+  case 48:
+#line 253 "prom_parse.y" /* yacc.c:1646  */
+    {
+            snprintf((yyval.str), STR_LEN, "%s%s", (yyvsp[-1].str), (yyvsp[0].str));
+        }
+#line 1800 "prom_parse.tab.c" /* yacc.c:1646  */
+    break;
+
+  case 49:
+#line 256 "prom_parse.y" /* yacc.c:1646  */
+    {
+            snprintf((yyval.str), STR_LEN, "@%s,%s%s", (yyvsp[-3].str), (yyvsp[-1].str), (yyvsp[0].str));
+        }
+#line 1808 "prom_parse.tab.c" /* yacc.c:1646  */
+    break;
+
+  case 50:
+#line 261 "prom_parse.y" /* yacc.c:1646  */
+    {
+            snprintf((yyval.str), STR_LEN, ":%s", (yyvsp[0].str));
+        }
+#line 1816 "prom_parse.tab.c" /* yacc.c:1646  */
+    break;
+
+  case 51:
+#line 264 "prom_parse.y" /* yacc.c:1646  */
+    {
+            snprintf((yyval.str), STR_LEN, ":%s,%s", (yyvsp[-2].str), (yyvsp[0].str));
+        }
+#line 1824 "prom_parse.tab.c" /* yacc.c:1646  */
+    break;
+
+
+#line 1828 "prom_parse.tab.c" /* yacc.c:1646  */
+      default: break;
+    }
+  /* User semantic actions sometimes alter yychar, and that requires
+     that yytoken be updated with the new translation.  We take the
+     approach of translating immediately before every use of yytoken.
+     One alternative is translating here after every semantic action,
+     but that translation would be missed if the semantic action invokes
+     YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or
+     if it invokes YYBACKUP.  In the case of YYABORT or YYACCEPT, an
+     incorrect destructor might then be invoked immediately.  In the
+     case of YYERROR or YYBACKUP, subsequent parser actions might lead
+     to an incorrect destructor call or verbose syntax error message
+     before the lookahead is translated.  */
+  YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
+
+  YYPOPSTACK (yylen);
+  yylen = 0;
+  YY_STACK_PRINT (yyss, yyssp);
+
+  *++yyvsp = yyval;
+  *++yylsp = yyloc;
+
+  /* Now 'shift' the result of the reduction.  Determine what state
+     that goes to, based on the state we popped back to and the rule
+     number reduced by.  */
+
+  yyn = yyr1[yyn];
+
+  yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+  if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+    yystate = yytable[yystate];
+  else
+    yystate = yydefgoto[yyn - YYNTOKENS];
+
+  goto yynewstate;
+
+
+/*--------------------------------------.
+| yyerrlab -- here on detecting error.  |
+`--------------------------------------*/
+yyerrlab:
+  /* Make sure we have latest lookahead translation.  See comments at
+     user semantic actions for why this is necessary.  */
+  yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar);
+
+  /* If not already recovering from an error, report this error.  */
+  if (!yyerrstatus)
+    {
+      ++yynerrs;
+#if ! YYERROR_VERBOSE
+      yyerror (ofwdev, YY_("syntax error"));
+#else
+# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \
+                                        yyssp, yytoken)
+      {
+        char const *yymsgp = YY_("syntax error");
+        int yysyntax_error_status;
+        yysyntax_error_status = YYSYNTAX_ERROR;
+        if (yysyntax_error_status == 0)
+          yymsgp = yymsg;
+        else if (yysyntax_error_status == 1)
+          {
+            if (yymsg != yymsgbuf)
+              YYSTACK_FREE (yymsg);
+            yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc);
+            if (!yymsg)
+              {
+                yymsg = yymsgbuf;
+                yymsg_alloc = sizeof yymsgbuf;
+                yysyntax_error_status = 2;
+              }
+            else
+              {
+                yysyntax_error_status = YYSYNTAX_ERROR;
+                yymsgp = yymsg;
+              }
+          }
+        yyerror (ofwdev, yymsgp);
+        if (yysyntax_error_status == 2)
+          goto yyexhaustedlab;
+      }
+# undef YYSYNTAX_ERROR
+#endif
+    }
+
+  yyerror_range[1] = yylloc;
+
+  if (yyerrstatus == 3)
+    {
+      /* If just tried and failed to reuse lookahead token after an
+         error, discard it.  */
+
+      if (yychar <= YYEOF)
+        {
+          /* Return failure if at end of input.  */
+          if (yychar == YYEOF)
+            YYABORT;
+        }
+      else
+        {
+          yydestruct ("Error: discarding",
+                      yytoken, &yylval, &yylloc, ofwdev);
+          yychar = YYEMPTY;
+        }
+    }
+
+  /* Else will try to reuse lookahead token after shifting the error
+     token.  */
+  goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR.  |
+`---------------------------------------------------*/
+yyerrorlab:
+
+  /* Pacify compilers like GCC when the user code never invokes
+     YYERROR and the label yyerrorlab therefore never appears in user
+     code.  */
+  if (/*CONSTCOND*/ 0)
+     goto yyerrorlab;
+
+  yyerror_range[1] = yylsp[1-yylen];
+  /* Do not reclaim the symbols of the rule whose action triggered
+     this YYERROR.  */
+  YYPOPSTACK (yylen);
+  yylen = 0;
+  YY_STACK_PRINT (yyss, yyssp);
+  yystate = *yyssp;
+  goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR.  |
+`-------------------------------------------------------------*/
+yyerrlab1:
+  yyerrstatus = 3;      /* Each real token shifted decrements this.  */
+
+  for (;;)
+    {
+      yyn = yypact[yystate];
+      if (!yypact_value_is_default (yyn))
+        {
+          yyn += YYTERROR;
+          if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+            {
+              yyn = yytable[yyn];
+              if (0 < yyn)
+                break;
+            }
+        }
+
+      /* Pop the current state because it cannot handle the error token.  */
+      if (yyssp == yyss)
+        YYABORT;
+
+      yyerror_range[1] = *yylsp;
+      yydestruct ("Error: popping",
+                  yystos[yystate], yyvsp, yylsp, ofwdev);
+      YYPOPSTACK (1);
+      yystate = *yyssp;
+      YY_STACK_PRINT (yyss, yyssp);
+    }
+
+  YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+  *++yyvsp = yylval;
+  YY_IGNORE_MAYBE_UNINITIALIZED_END
+
+  yyerror_range[2] = yylloc;
+  /* Using YYLLOC is tempting, but would change the location of
+     the lookahead.  YYLOC is available though.  */
+  YYLLOC_DEFAULT (yyloc, yyerror_range, 2);
+  *++yylsp = yyloc;
+
+  /* Shift the error token.  */
+  YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
+  yystate = yyn;
+  goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here.  |
+`-------------------------------------*/
+yyacceptlab:
+  yyresult = 0;
+  goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here.  |
+`-----------------------------------*/
+yyabortlab:
+  yyresult = 1;
+  goto yyreturn;
+
+#if !defined yyoverflow || YYERROR_VERBOSE
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here.  |
+`-------------------------------------------------*/
+yyexhaustedlab:
+  yyerror (ofwdev, YY_("memory exhausted"));
+  yyresult = 2;
+  /* Fall through.  */
+#endif
+
+yyreturn:
+  if (yychar != YYEMPTY)
+    {
+      /* Make sure we have latest lookahead translation.  See comments at
+         user semantic actions for why this is necessary.  */
+      yytoken = YYTRANSLATE (yychar);
+      yydestruct ("Cleanup: discarding lookahead",
+                  yytoken, &yylval, &yylloc, ofwdev);
+    }
+  /* Do not reclaim the symbols of the rule whose action triggered
+     this YYABORT or YYACCEPT.  */
+  YYPOPSTACK (yylen);
+  YY_STACK_PRINT (yyss, yyssp);
+  while (yyssp != yyss)
+    {
+      yydestruct ("Cleanup: popping",
+                  yystos[*yyssp], yyvsp, yylsp, ofwdev);
+      YYPOPSTACK (1);
+    }
+#ifndef yyoverflow
+  if (yyss != yyssa)
+    YYSTACK_FREE (yyss);
+#endif
+#if YYERROR_VERBOSE
+  if (yymsg != yymsgbuf)
+    YYSTACK_FREE (yymsg);
+#endif
+  return yyresult;
+}
+#line 269 "prom_parse.y" /* yacc.c:1906  */
+
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/fwparam_ibft/prom_parse.tab.h b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/fwparam_ibft/prom_parse.tab.h
new file mode 100644 (file)
index 0000000..4897b23
--- /dev/null
@@ -0,0 +1,102 @@
+/* A Bison parser, made by GNU Bison 3.0.4.  */
+
+/* Bison interface for Yacc-like parsers in C
+
+   Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc.
+
+   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 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* As a special exception, you may create a larger work that contains
+   part or all of the Bison parser skeleton and distribute that work
+   under terms of your choice, so long as that work isn't itself a
+   parser generator using the skeleton or a modified version thereof
+   as a parser skeleton.  Alternatively, if you modify or redistribute
+   the parser skeleton itself, you may (at your option) remove this
+   special exception, which will cause the skeleton and the resulting
+   Bison output files to be licensed under the GNU General Public
+   License without this special exception.
+
+   This special exception was added by the Free Software Foundation in
+   version 2.2 of Bison.  */
+
+#ifndef YY_YY_PROM_PARSE_TAB_H_INCLUDED
+# define YY_YY_PROM_PARSE_TAB_H_INCLUDED
+/* Debug traces.  */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+#if YYDEBUG
+extern int yydebug;
+#endif
+
+/* Token type.  */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+  enum yytokentype
+  {
+    BUSNAME = 258,
+    BOOTDEV = 259,
+    IPV4 = 260,
+    IQN = 261,
+    OBPPARM = 262,
+    OBPQUAL = 263,
+    HEX4 = 264,
+    HEX16 = 265,
+    VDEVICE = 266,
+    VDEVINST = 267,
+    VDEVDEV = 268,
+    VDEVRAW = 269,
+    CHOSEN = 270,
+    FILENAME = 271
+  };
+#endif
+
+/* Value type.  */
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+
+union YYSTYPE
+{
+#line 34 "prom_parse.y" /* yacc.c:1909  */
+
+#define        STR_LEN         16384
+               char str[STR_LEN];
+
+#line 76 "prom_parse.tab.h" /* yacc.c:1909  */
+};
+
+typedef union YYSTYPE YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+/* Location type.  */
+#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED
+typedef struct YYLTYPE YYLTYPE;
+struct YYLTYPE
+{
+  int first_line;
+  int first_column;
+  int last_line;
+  int last_column;
+};
+# define YYLTYPE_IS_DECLARED 1
+# define YYLTYPE_IS_TRIVIAL 1
+#endif
+
+
+extern YYSTYPE yylval;
+extern YYLTYPE yylloc;
+int yyparse (struct ofw_dev *ofwdev);
+
+#endif /* !YY_YY_PROM_PARSE_TAB_H_INCLUDED  */
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/fwparam_ibft/prom_parse.y b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/fwparam_ibft/prom_parse.y
new file mode 100644 (file)
index 0000000..efe1578
--- /dev/null
@@ -0,0 +1,269 @@
+/*
+ * Copyright (C) IBM Corporation. 2007
+ * Author: Doug Maxey <dwm@austin.ibm.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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* - DEFINITION section. */
+
+%{
+       /* literal block. include lines, decls, defns. */
+//#define YYDEBUG 1
+#if YYDEBUG
+#define DPRINT(fmt,...) printf(fmt,__VA_ARGS__)
+#else
+#define DPRINT(fmt,...) do {} while(0)
+#endif
+#include "prom_parse.h"
+#include "iscsi_obp.h"
+
+
+%}
+%union {
+#define        STR_LEN         16384
+               char str[STR_LEN];
+}
+
+/* definitions. */
+%token <str> BUSNAME BOOTDEV
+%token <str> IPV4 IQN
+%token <str> OBPPARM OBPQUAL
+%token <str> HEX4 HEX16
+%token <str> VDEVICE VDEVINST VDEVDEV VDEVRAW
+%token <str> CHOSEN
+%token <str> FILENAME
+
+%type <str> devpath busses bus bootdev
+%type <str> disklabel diskpart
+%type <str> vdevice vdev_parms vdev_parm
+%type <str> obp_quals obp_qual obp_params obp_param
+%type <str> ipaddr ipv4 ipv6
+%type <str> hexpart hexseq
+
+%locations
+%parse-param {struct ofw_dev *ofwdev}
+
+%%
+
+devpath: '/'   {
+                       DPRINT("****rootonly: \"%s\"\n", "/");
+               }
+       | '/' busses  bootdev  {
+                       DPRINT("****devpath busses:\n/%s/%s\n", $2, $3);
+               }
+       | '/' busses  bootdev disklabel {
+                       ofwdev->dev_path = malloc(strlen($<str>2) +
+                                      strlen($<str>3) + 3);
+                       sprintf(ofwdev->dev_path, "/%s%s", $<str>2, $<str>3);
+                       DPRINT("****devpath busses bootdev "
+                   "disklabel:\n/%s/%s%s\n",
+                                  $2, $3, $4);
+               }
+       | '/' busses  bootdev obp_quals obp_params {
+                       ofwdev->dev_path = malloc(strlen($<str>2) +
+                                      strlen($<str>3) + 3);
+                       sprintf(ofwdev->dev_path, "/%s%s", $<str>2, $<str>3);
+                       DPRINT("****busses bootdev obp_quals obp_parms:\n"
+                   "/%s/%s:%s%s\n",
+                                  $2, $3, $4, $5);
+               }
+       | '/' busses  bootdev obp_quals obp_params disklabel {
+                       ofwdev->dev_path = malloc(strlen($<str>2) +
+                                      strlen($<str>3) + 3);
+                       sprintf(ofwdev->dev_path, "/%s%s", $<str>2, $<str>3);
+                       DPRINT("****busses bootdev obp_quals obp_parms "
+                   "disklabel:\n/%s:%s%s%s\n", $2, $4, $5, $6);
+               }
+       | '/' vdevice bootdev vdev_parms obp_quals obp_params disklabel {
+                       DPRINT("****vdevice bootdev obp_parms "
+                   "disklabel:\n/%s:%s%s%s%s\n",
+                                  $2, $4, $5, $6, $7);
+               }
+       ;
+
+busses:           bus  {
+                       strcpy($$, $1);
+               }
+       | busses '/' bus {
+                       snprintf($$, STR_LEN, "%s/%s", $<str>1, $<str>3);
+               }
+       ;
+
+bus:   BUSNAME {
+                       strcpy($$, $1);
+               }
+       | BUSNAME '@' HEX4 {
+                       snprintf($$, STR_LEN, "%s@%s", $<str>1, $<str>3);
+               }
+       | BUSNAME '@' HEX4 ',' HEX4 {
+                       snprintf($$, STR_LEN, "%s@%s,%s", $<str>1, $<str>3, $<str>5);
+               }
+       | BUSNAME '@' HEX16 {
+                       snprintf($$, STR_LEN, "%s@%s", $<str>1, $<str>3);
+               }
+       | BUSNAME ',' HEX4 '@' HEX16  {
+                       snprintf($$, STR_LEN, "%s,%s@%s", $<str>1, $<str>3, $<str>5);
+               }
+       ;
+
+
+bootdev:  '/' BOOTDEV ':' {
+                       snprintf($$, STR_LEN, "/%s", $<str>2);
+               }
+       | '/' BOOTDEV '@' HEX4 ':' {
+                       snprintf($$, STR_LEN, "/%s@%s", $<str>2, $<str>4);
+               }
+       | '/' BOOTDEV '@' HEX4 ',' HEX4 ':' {
+                       snprintf($$, STR_LEN, "/%s@%s,%s", $<str>2, $<str>4, $<str>6);
+               }
+       ;
+
+vdevice: VDEVICE '/' VDEVINST {
+                       snprintf($$, STR_LEN, "%s/%s", $<str>1, $<str>3);
+               }
+       ;
+
+vdev_parms: ':' vdev_parm {
+                       snprintf($$, STR_LEN, ":%s", $<str>2);
+               }
+       | vdev_parms ',' vdev_parm {
+                       snprintf($$, STR_LEN, "%s,%s", $<str>1, $<str>3);
+               }
+       | vdev_parms ',' VDEVRAW {
+                       snprintf($$, STR_LEN, "%s,%s", $<str>1, $<str>3);
+               }
+       ;
+
+vdev_parm: VDEVDEV '=' CHOSEN {
+                       snprintf($$, STR_LEN, "%s=%s", $<str>1, $<str>3);
+               }
+       ;
+
+obp_params: ',' obp_param      {
+                       snprintf($$, STR_LEN, ",%s", $2);
+               }
+       | obp_params ',' obp_param {
+                       snprintf($$, STR_LEN, "%s,%s", $<str>1, $<str>3);
+               }
+       | obp_params ',' disklabel {
+                       snprintf($$, STR_LEN, "%s,%s", $<str>1, $<str>3);
+               }
+       ;
+
+obp_param: HEX4 {
+                       snprintf($$, STR_LEN, "%s", $1);
+               }
+       | OBPPARM '=' HEX16 {
+                       /* luns > 0 are the SAM-3+ hex representation. */
+                       obp_parm_hexnum(ofwdev, $<str>1, $<str>3);
+                       snprintf($$, STR_LEN, "%s=%s", $<str>1, $<str>3);
+               }
+       | OBPPARM '=' ipaddr {
+                       obp_parm_addr(ofwdev, $<str>1, $<str>3);
+                       snprintf($$, STR_LEN, "%s=%s", $<str>1, $<str>3);
+               }
+       | OBPPARM '=' IQN {
+                       obp_parm_iqn(ofwdev, $<str>1, $<str>3);
+                       snprintf($$, STR_LEN, "%s=%s", $<str>1, $<str>3);
+               }
+       | OBPPARM '=' HEX4 {
+                       obp_parm_hexnum(ofwdev, $<str>1, $<str>3);
+                       snprintf($$, STR_LEN, "%s=%s", $<str>1, $<str>3);
+               }
+       | OBPPARM '=' FILENAME {
+                       obp_parm_str(ofwdev, $<str>1, $<str>3);
+                       snprintf($$, STR_LEN, "%s=%s", $<str>1, $<str>3);
+               }
+       ;
+
+obp_quals: obp_qual {
+                       snprintf($$, STR_LEN, "%s", $1);
+               }
+       |  obp_quals ',' obp_qual {
+                       snprintf($$, STR_LEN, "%s,%s", $<str>1, $<str>3);
+               }
+       ;
+
+obp_qual: OBPQUAL {
+                       snprintf($$, STR_LEN, "%s", obp_qual_set(ofwdev, $<str>1));
+               }
+       | vdev_parm {
+                       snprintf($$, STR_LEN, "%s", $<str>1);
+               }
+       ;
+
+ipaddr: ipv4 {
+                       snprintf($$, STR_LEN, "%s", $<str>1);
+               }
+       | ipv6 {
+                       snprintf($$, STR_LEN, "%s", $<str>1);
+               }
+       ;
+
+ipv4: IPV4 {
+                       snprintf($$, STR_LEN, "%s", $1);
+               }
+       ;
+
+ipv6: hexpart {
+                       snprintf($$, STR_LEN, "%s", $1);
+               }
+       | hexpart ':' ipv4 {
+                       snprintf($$, STR_LEN, "%s:%s", $1, $3);
+               }
+       ;
+
+hexpart: hexseq {
+                       snprintf($$, STR_LEN, "%s", $1);
+               }
+       | hexpart "::"  {
+                       snprintf($$, STR_LEN, "%s::", $<str>1);
+               }
+       | hexpart "::" hexseq {
+                       snprintf($$, STR_LEN, "%s::%s", $<str>1, $<str>3);
+               }
+       | "::" hexseq {
+                       snprintf($$, STR_LEN, "::%s", $<str>2);
+               }
+       ;
+
+hexseq:        HEX4 {
+            snprintf($$, STR_LEN, "%s", $1);
+        }
+    | hexseq ":" HEX4 {
+            snprintf($$, STR_LEN, "%s:%s", $<str>1, $<str>3);
+        }
+    ;
+
+disklabel:   diskpart {
+            snprintf($$, STR_LEN, "%s", $<str>1);
+        }
+    | HEX4 diskpart {
+            snprintf($$, STR_LEN, "%s%s", $<str>1, $<str>2);
+        }
+    | '@' HEX4 ',' HEX4 diskpart {
+            snprintf($$, STR_LEN, "@%s,%s%s", $<str>2, $<str>4, $<str>5);
+        }
+    ;
+
+diskpart: ':' HEX4 {
+            snprintf($$, STR_LEN, ":%s", $<str>2);
+        }
+    | ':' HEX4 ',' FILENAME {
+            snprintf($$, STR_LEN, ":%s,%s", $<str>2, $<str>4);
+        }
+    ;
+
+%%
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/host.c b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/host.c
new file mode 100644 (file)
index 0000000..a12577c
--- /dev/null
@@ -0,0 +1,453 @@
+/*
+ * iSCSI host helpers
+ *
+ * Copyright (C) 2008 Mike Christie
+ * Copyright (C) 2008 Red Hat, Inc. All rights reserved.
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include "list.h"
+#include "iscsi_util.h"
+#include "log.h"
+#include "iscsi_sysfs.h"
+#include "version.h"
+#include "iscsi_settings.h"
+#include "mgmt_ipc.h"
+#include "host.h"
+#include "session_info.h"
+#include "transport.h"
+#include "initiator.h"
+#include "iface.h"
+#include "iscsi_err.h"
+#include "iscsi_netlink.h"
+
+struct _host_info_print_tree_arg {
+       unsigned int flags;
+       struct iscsi_session **ses;
+       uint32_t se_count;
+};
+
+static int match_host_to_session(uint32_t host_no, struct iscsi_session *se)
+{
+       uint32_t sid = 0;
+       uint32_t info_host_no;
+       int rc;
+
+       sid = iscsi_session_sid_get(se);
+
+       info_host_no = iscsi_sysfs_get_host_no_from_sid(sid, &rc);
+       if (rc) {
+               log_error("could not get host_no for session%d err %d.",
+                         sid, rc);
+               return 0;
+       }
+
+       return host_no == info_host_no;
+}
+
+static void print_host_info(struct iface_rec *iface, char *prefix)
+{
+       if (strlen(iface->transport_name))
+               printf("%sTransport: %s\n", prefix,
+                     iface->transport_name);
+       else
+               printf("%sTransport: %s\n", prefix, UNKNOWN_VALUE);
+
+       if (strlen(iface->iname))
+               printf("%sInitiatorname: %s\n", prefix,
+                     iface->iname);
+       else
+               printf("%sInitiatorname: %s\n", prefix, UNKNOWN_VALUE);
+
+       if (!strlen(iface->ipaddress))
+               printf("%sIPaddress: %s\n", prefix, UNKNOWN_VALUE);
+       else if (strchr(iface->ipaddress, '.'))
+               printf("%sIPaddress: %s\n", prefix, iface->ipaddress);
+       else
+               printf("%sIPaddress: [%s]\n", prefix, iface->ipaddress);
+
+       if (strlen(iface->hwaddress))
+               printf("%sHWaddress: %s\n", prefix, iface->hwaddress);
+       else
+               printf("%sHWaddress: %s\n", prefix, UNKNOWN_VALUE);
+
+       if (strlen(iface->netdev))
+               printf("%sNetdev: %s\n", prefix, iface->netdev);
+       else
+               printf("%sNetdev: %s\n", prefix, UNKNOWN_VALUE);
+}
+
+static int host_info_print_flat(__attribute__((unused))void *data,
+                               struct host_info *hinfo)
+{
+       struct iface_rec *iface = &hinfo->iface;
+
+       if (strlen(iface->transport_name))
+               printf("%s: ", iface->transport_name);
+       else
+               printf("%s: ", UNKNOWN_VALUE);
+
+       printf("[%u] ", hinfo->host_no);
+
+       if (!strlen(iface->ipaddress))
+               printf("%s,", UNKNOWN_VALUE);
+       else if (strchr(iface->ipaddress, '.'))
+               printf("%s,", iface->ipaddress);
+       else
+               printf("[%s],", iface->ipaddress);
+
+       if (strlen(iface->hwaddress))
+               printf("[%s],", iface->hwaddress);
+       else
+               printf("[%s],", UNKNOWN_VALUE);
+
+       if (strlen(iface->netdev))
+               printf("%s ", iface->netdev);
+       else
+               printf("%s ", UNKNOWN_VALUE);
+
+       if (strlen(iface->iname))
+               printf("%s\n", iface->iname);
+       else
+               printf("%s\n", UNKNOWN_VALUE);
+       return 0;
+}
+
+static int print_host_iface(void *data, struct iface_rec *iface)
+{
+       char *prefix = data;
+
+       printf("%s**********\n", prefix);
+       printf("%sInterface:\n", prefix);
+       printf("%s**********\n", prefix);
+
+       printf("%sKernel Name: %s\n", prefix, iface->name);
+
+       if (!strlen(iface->ipaddress))
+               printf("%sIPaddress: %s\n", prefix, UNKNOWN_VALUE);
+       else if (strchr(iface->ipaddress, '.')) {
+               printf("%sIPaddress: %s\n", prefix, iface->ipaddress);
+
+               if (!strlen(iface->gateway))
+                       printf("%sGateway: %s\n", prefix, UNKNOWN_VALUE);
+               else
+                       printf("%sGateway: %s\n", prefix, iface->gateway);
+               if (!strlen(iface->subnet_mask))
+                       printf("%sSubnet: %s\n", prefix, UNKNOWN_VALUE);
+               else
+                       printf("%sSubnet: %s\n", prefix, iface->subnet_mask);
+               if (!strlen(iface->bootproto))
+                       printf("%sBootProto: %s\n", prefix, UNKNOWN_VALUE);
+               else
+                       printf("%sBootProto: %s\n", prefix, iface->bootproto);
+       } else {
+               printf("%sIPaddress: [%s]\n", prefix, iface->ipaddress);
+
+               if (!strlen(iface->ipv6_autocfg))
+                       printf("%sIPaddress Autocfg: %s\n", prefix,
+                              UNKNOWN_VALUE);
+               else
+                       printf("%sIPaddress Autocfg: %s\n", prefix,
+                              iface->ipv6_autocfg);
+               if (!strlen(iface->ipv6_linklocal))
+                       printf("%sLink Local Address: %s\n", prefix,
+                              UNKNOWN_VALUE);
+               else
+                       printf("%sLink Local Address: [%s]\n", prefix,
+                              iface->ipv6_linklocal);
+               if (!strlen(iface->linklocal_autocfg))
+                       printf("%sLink Local Autocfg: %s\n", prefix,
+                              UNKNOWN_VALUE);
+               else
+                       printf("%sLink Local Autocfg: %s\n", prefix,
+                              iface->linklocal_autocfg);
+               if (!strlen(iface->ipv6_router))
+                       printf("%sRouter Address: %s\n", prefix,
+                             UNKNOWN_VALUE);
+               else
+                       printf("%sRouter Address: [%s]\n", prefix,
+                              iface->ipv6_router);
+       }
+
+       if (!strlen(iface->port_state))
+               printf("%sPort State: %s\n", prefix, UNKNOWN_VALUE);
+       else
+               printf("%sPort State: %s\n", prefix, iface->port_state);
+
+       if (!strlen(iface->port_speed))
+               printf("%sPort Speed: %s\n", prefix, UNKNOWN_VALUE);
+       else
+               printf("%sPort Speed: %s\n", prefix, iface->port_speed);
+
+       if (!iface->port)
+               printf("%sPort: %s\n", prefix, UNKNOWN_VALUE);
+       else
+               printf("%sPort: %u\n", prefix, iface->port);
+
+       if (!iface->mtu)
+               printf("%sMTU: %s\n", prefix, UNKNOWN_VALUE);
+       else
+               printf("%sMTU: %u\n", prefix, iface->mtu);
+
+       if (iface->vlan_id == UINT16_MAX)
+               printf("%sVLAN ID: %s\n", prefix, UNKNOWN_VALUE);
+       else
+               printf("%sVLAN ID: %u\n", prefix, iface->vlan_id);
+
+       if (iface->vlan_priority == UINT8_MAX)
+               printf("%sVLAN priority: %s\n", prefix, UNKNOWN_VALUE);
+       else
+               printf("%sVLAN priority: %u\n", prefix, iface->vlan_priority);
+       return 0;
+}
+
+static void print_host_ifaces(struct host_info *hinfo, char *prefix)
+{
+       int nr_found = 0;
+
+       iscsi_sysfs_for_each_iface_on_host(prefix, hinfo->host_no, &nr_found,
+                                          print_host_iface);
+}
+
+static int host_info_print_tree(void *data, struct host_info *hinfo)
+{
+       unsigned int session_info_flags = 0;
+       struct _host_info_print_tree_arg *arg = data;
+       struct iscsi_session **ses = NULL;
+       struct iscsi_session **matched_ses = NULL;
+       uint32_t se_count = 0;
+       uint32_t matched_se_count = 0;
+       uint32_t i = 0;
+       char state[SCSI_MAX_STATE_VALUE];
+
+       if (arg == NULL)
+               return -EINVAL;
+
+       session_info_flags = arg->flags;
+       ses = arg->ses;
+       se_count = arg->se_count;
+
+       printf("Host Number: %u\n", hinfo->host_no);
+       if (!iscsi_sysfs_get_host_state(state, hinfo->host_no))
+               printf("\tState: %s\n", state);
+       else
+               printf("\tState: Unknown\n");
+       print_host_info(&hinfo->iface, "\t");
+
+       print_host_ifaces(hinfo, "\t");
+
+       if ((!session_info_flags) || (!se_count))
+               return 0;
+
+       matched_ses = calloc(se_count, sizeof(struct iscsi_session *));
+       if (matched_ses == NULL)
+               return -ENOMEM;
+
+       for (i = 0; i < se_count; ++i)
+               if (match_host_to_session(hinfo->host_no, ses[i]))
+                       matched_ses[matched_se_count++] = ses[i];
+
+       if (!matched_se_count)
+               goto out;
+
+       printf("\t*********\n");
+       printf("\tSessions:\n");
+       printf("\t*********\n");
+       session_info_print_tree(matched_ses, matched_se_count, "\t",
+                               session_info_flags, 0/* don't show password */);
+out:
+       free(matched_ses);
+       return 0;
+}
+
+int host_info_print(int info_level, uint32_t host_no,
+                   struct iscsi_session **ses, uint32_t se_count)
+
+{
+       int num_found = 0, err = 0;
+       char *version;
+       unsigned int flags = 0;
+       struct _host_info_print_tree_arg arg;
+
+       switch (info_level) {
+       case 0:
+       case -1:
+               err = iscsi_sysfs_for_each_host(NULL, &num_found,
+                                               host_info_print_flat);
+               break;
+       case 4:
+               version = iscsi_sysfs_get_iscsi_kernel_version();
+               if (version) {
+                       printf("iSCSI Transport Class version %s\n",
+                              version);
+                       printf("version %s\n", ISCSI_VERSION_STR);
+                       free(version);
+               }
+
+               flags |= SESSION_INFO_SCSI_DEVS;
+               /* fall through */
+       case 3:
+               flags |= SESSION_INFO_ISCSI_PARAMS;
+               /* fall through */
+       case 2:
+               flags |= SESSION_INFO_ISCSI_STATE | SESSION_INFO_IFACE;
+               /* fall through */
+       case 1:
+               arg.flags = flags;
+               arg.ses = ses;
+               arg.se_count = se_count;
+               /* set host_no if not yet done */
+               if (host_no > MAX_HOST_NO) {
+                       struct host_info hinfo;
+
+                       memset(&hinfo, 0, sizeof(struct host_info));
+                       hinfo.host_no = host_no;
+                       iscsi_sysfs_get_hostinfo_by_host_no(&hinfo);
+                       host_info_print_tree(&arg, &hinfo);
+                       num_found = 1;
+                       break;
+               }
+
+               transport_probe_for_offload();
+               err = iscsi_sysfs_for_each_host(&arg, &num_found,
+                                               host_info_print_tree);
+               break;
+       default:
+               log_error("Invalid info level %d. Try 0 - 4.", info_level);
+               return ISCSI_ERR_INVAL;
+       }
+
+       if (err) {
+               log_error("Can not get list of iSCSI hosts: %s",
+                         iscsi_err_to_str(err));
+               return err;
+       } else if (!num_found) {
+               log_error("No iSCSI hosts.");
+               return ISCSI_ERR_NO_OBJS_FOUND;
+       }
+       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/pkgs/open-iscsi/open-iscsi-2.1.8/usr/host.h b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/host.h
new file mode 100644 (file)
index 0000000..88be442
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef ISCSI_HOST_H
+#define ISCSI_HOST_H
+#include <sys/types.h>
+
+#include <libopeniscsiusr/libopeniscsiusr.h>
+
+#include "types.h"
+#include "config.h"
+
+#define MAX_HOST_NO UINT32_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))
+
+struct host_info {
+        struct iface_rec iface;
+        uint32_t host_no;
+};
+
+extern int host_info_print(int info_level, uint32_t host_no,
+                          struct iscsi_session **ses, uint32_t se_count);
+extern int chap_build_config(struct iscsi_chap_rec *crec, struct iovec *iovs);
+
+#endif
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/idbm.c b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/idbm.c
new file mode 100644 (file)
index 0000000..90bc142
--- /dev/null
@@ -0,0 +1,3234 @@
+/*
+ * iSCSI Discovery Database Library
+ *
+ * Copyright (C) 2004 Dmitry Yusupov, Alex Aizman
+ * Copyright (C) 2006 Mike Christie
+ * Copyright (C) 2006 Red Hat, Inc. All rights reserved.
+ * maintained by open-iscsi@@googlegroups.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * See the file COPYING included with this distribution for more details.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <dirent.h>
+#include <limits.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <inttypes.h>
+
+#include "idbm.h"
+#include "idbm_fields.h"
+#include "log.h"
+#include "iscsi_util.h"
+#include "iscsi_settings.h"
+#include "transport.h"
+#include "iscsi_sysfs.h"
+#include "iface.h"
+#include "sysdeps.h"
+#include "fw_context.h"
+#include "iscsi_err.h"
+
+#define IDBM_HIDE      0    /* Hide parameter when print. */
+#define IDBM_SHOW      1    /* Show parameter when print. */
+#define IDBM_MASKED    2    /* Show "stars" instead of real value when print */
+
+static struct idbm *db;
+
+#define ARRAY_LEN(x) ( sizeof(x) / sizeof((x)[0]) )
+
+#define __recinfo_str(_key, _info, _rec, _name, _show, _n, _mod) do { \
+       _info[_n].type = TYPE_STR; \
+       strlcpy(_info[_n].name, _key, NAME_MAXVAL); \
+       if (strlen((char*)_rec->_name)) \
+               strlcpy((char*)_info[_n].value, (char*)_rec->_name, \
+                       VALUE_MAXVAL); \
+       _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(_key, _info, _rec, _name, _show, _n, _mod) do { \
+       _info[_n].type = TYPE_INT; \
+       strlcpy(_info[_n].name, _key, NAME_MAXVAL); \
+       snprintf(_info[_n].value, VALUE_MAXVAL, "%" PRIi32, _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_uint8(_key, _info, _rec, _name, _show, _n, _mod) do { \
+       _info[_n].type = TYPE_UINT8; \
+       strlcpy(_info[_n].name, _key, NAME_MAXVAL); \
+       snprintf(_info[_n].value, VALUE_MAXVAL, "%" PRIu8, _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_uint16(_key, _info, _rec, _name, _show, _n, _mod) do { \
+       _info[_n].type = TYPE_UINT16; \
+       strlcpy(_info[_n].name, _key, NAME_MAXVAL); \
+       snprintf(_info[_n].value, VALUE_MAXVAL, "%" PRIu16, _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_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, "%" PRIu32, _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); \
+       if (_rec->_name == 0) strlcpy(_info[_n].value, _op0, VALUE_MAXVAL); \
+       if (_rec->_name == 1) strlcpy(_info[_n].value, _op1, VALUE_MAXVAL); \
+       _info[_n].data = &_rec->_name; \
+       _info[_n].data_len = sizeof(_rec->_name); \
+       _info[_n].visible = _show; \
+       _info[_n].opts[0] = _op0; \
+       _info[_n].opts[1] = _op1; \
+       _info[_n].numopts = 2; \
+       _info[_n].can_modify = _mod; \
+       _n++; \
+} while(0)
+
+#define __recinfo_int_o3(_key,_info,_rec,_name,_show,_op0,_op1,_op2,_n,        \
+                        _mod) do { \
+       __recinfo_int_o2(_key,_info,_rec,_name,_show,_op0,_op1,_n, _mod); \
+       _n--; \
+       if (_rec->_name == 2) strlcpy(_info[_n].value, _op2, VALUE_MAXVAL);\
+       _info[_n].opts[2] = _op2; \
+       _info[_n].numopts = 3; \
+       _n++; \
+} while(0)
+
+#define __recinfo_int_o4(_key,_info,_rec,_name,_show,_op0,_op1,_op2,_op3,_n, \
+                        _mod) do { \
+       __recinfo_int_o3(_key,_info,_rec,_name,_show,_op0,_op1,_op2,_n, _mod); \
+       _n--; \
+       if (_rec->_name == 3) strlcpy(_info[_n].value, _op3, VALUE_MAXVAL); \
+       _info[_n].opts[3] = _op3; \
+       _info[_n].numopts = 4; \
+       _n++; \
+} while(0)
+
+#define __recinfo_int_o5(_key,_info,_rec,_name,_show,_op0,_op1,_op2,_op3, \
+                        _op4,_n, _mod) do { \
+       __recinfo_int_o4(_key,_info,_rec,_name,_show,_op0,_op1,_op2,_op3, \
+                         _n,_mod); \
+       _n--; \
+       if (_rec->_name == 4) strlcpy(_info[_n].value, _op4, VALUE_MAXVAL); \
+       _info[_n].opts[4] = _op4; \
+       _info[_n].numopts = 5; \
+       _n++; \
+} while(0)
+
+#define __recinfo_int_o6(_key,_info,_rec,_name,_show,_op0,_op1,_op2, \
+                        _op3,_op4,_op5,_n,_mod) do { \
+       __recinfo_int_o5(_key,_info,_rec,_name,_show,_op0,_op1,_op2,_op3, \
+                        _op4,_n,_mod); \
+       _n--; \
+       if (_rec->_name == 5) strlcpy(_info[_n].value, _op5, VALUE_MAXVAL); \
+       _info[_n].opts[5] = _op5; \
+       _info[_n].numopts = 6; \
+       _n++; \
+} while(0)
+
+#define __recinfo_int_list(_key,_info,_rec,_name,_show,_tbl,_n,_mod) do { \
+       _info[_n].type = TYPE_INT_LIST; \
+       strlcpy(_info[_n].name, _key, NAME_MAXVAL); \
+       _info[_n].value[0] = '\0'; \
+       for (unsigned long _i = 0; _i < ARRAY_LEN(_rec->_name); _i++) { \
+               if (_rec->_name[_i] != (unsigned)~0) {                  \
+                       for (unsigned long _j = 0; _j < ARRAY_LEN(_tbl); _j++) {        \
+                               if (_tbl[_j].value == (int)_rec->_name[_i]) { \
+                                       strcat(_info[_n].value, _tbl[_j].name); \
+                                       strcat(_info[_n].value, ","); \
+                                       break; \
+                               } \
+                       } \
+               } \
+       } \
+       /* delete trailing ',' */ \
+       if (strrchr(_info[_n].value, ',')) \
+               *strrchr(_info[_n].value, ',') = '\0'; \
+       _info[_n].data = &_rec->_name; \
+       _info[_n].data_len = sizeof(_rec->_name); \
+       _info[_n].visible = _show; \
+       _info[_n].opts[0] = (void *)&_tbl; \
+       _info[_n].numopts = ARRAY_LEN(_tbl); \
+       _info[_n].can_modify = _mod; \
+       _n++; \
+} while (0)
+
+static struct int_list_tbl {
+       const char *name;
+       int value;
+} chap_algs [] = {
+       { "MD5", AUTH_CHAP_ALG_MD5 },
+       { "SHA1", AUTH_CHAP_ALG_SHA1 },
+       { "SHA256", AUTH_CHAP_ALG_SHA256 },
+       { "SHA3-256", AUTH_CHAP_ALG_SHA3_256 },
+};
+
+static void
+idbm_recinfo_discovery(discovery_rec_t *r, recinfo_t *ri)
+{
+       int num = 0;
+
+       __recinfo_int_o2(DISC_STARTUP, ri, r, startup, IDBM_SHOW,
+                       "manual", "automatic", num, 1);
+       __recinfo_int_o6(DISC_TYPE, ri, r, type, IDBM_SHOW,
+                       "sendtargets", "isns", "offload_send_targets", "slp",
+                       "static", "fw", num, 0);
+       switch (r->type) {
+       case DISCOVERY_TYPE_SENDTARGETS:
+               __recinfo_str(DISC_ST_ADDR, ri, r,
+                       address, IDBM_SHOW, num, 0);
+               __recinfo_int(DISC_ST_PORT, ri, r,
+                       port, IDBM_SHOW, num, 0);
+               __recinfo_int_o2(DISC_ST_AUTH_METHOD, ri, r,
+                       u.sendtargets.auth.authmethod,
+                       IDBM_SHOW, "None", "CHAP", num, 1);
+               __recinfo_str(DISC_ST_USERNAME, ri, r,
+                       u.sendtargets.auth.username, IDBM_SHOW, num, 1);
+               __recinfo_str(DISC_ST_PASSWORD, ri, r,
+                       u.sendtargets.auth.password, IDBM_MASKED, num, 1);
+               __recinfo_int(DISC_ST_PASSWORD_LEN, ri, r,
+                       u.sendtargets.auth.password_length, IDBM_HIDE, num, 1);
+               __recinfo_str(DISC_ST_USERNAME_IN, ri, r,
+                       u.sendtargets.auth.username_in, IDBM_SHOW, num, 1);
+               __recinfo_str(DISC_ST_PASSWORD_IN, ri, r,
+                       u.sendtargets.auth.password_in, IDBM_MASKED, num, 1);
+               __recinfo_int(DISC_ST_PASSWORD_IN_LEN, ri, r,
+                       u.sendtargets.auth.password_in_length, IDBM_HIDE,
+                       num, 1);
+               /* reusing SESSION_CHAP_ALGS */
+               __recinfo_int_list(SESSION_CHAP_ALGS, ri, r,
+                                  u.sendtargets.auth.chap_algs,
+                                  IDBM_SHOW, chap_algs, num, 1);
+               __recinfo_int(DISC_ST_LOGIN_TMO, ri, r,
+                       u.sendtargets.conn_timeo.login_timeout,
+                       IDBM_SHOW, num, 1);
+               __recinfo_int_o2(DISC_ST_USE_DISC_DAEMON, ri, r,
+                       u.sendtargets.use_discoveryd,
+                       IDBM_SHOW, "No", "Yes", num, 1);
+               __recinfo_int(DISC_ST_DISC_DAEMON_POLL_INVAL, ri, r,
+                       u.sendtargets.discoveryd_poll_inval,
+                       IDBM_SHOW, num, 1);
+               __recinfo_int(DISC_ST_REOPEN_MAX, ri, r,
+                       u.sendtargets.reopen_max,
+                       IDBM_SHOW, num, 1);
+               __recinfo_int(DISC_ST_AUTH_TMO, ri, r,
+                       u.sendtargets.conn_timeo.auth_timeout,
+                       IDBM_SHOW, num, 1);
+               __recinfo_int(DISC_ST_ACTIVE_TMO, ri, r,
+                             u.sendtargets.conn_timeo.active_timeout,
+                             IDBM_SHOW, num, 1);
+               __recinfo_int(DISC_ST_MAX_RECV_DLEN, ri, r,
+                             u.sendtargets.conn_conf.MaxRecvDataSegmentLength,
+                             IDBM_SHOW, num, 1);
+               break;
+       case DISCOVERY_TYPE_ISNS:
+               __recinfo_str(DISC_ISNS_ADDR, ri, r,
+                       address, IDBM_SHOW, num, 0);
+               __recinfo_int(DISC_ISNS_PORT, ri, r,
+                       port, IDBM_SHOW, num, 0);
+               __recinfo_int_o2(DISC_ISNS_USE_DISC_DAEMON, ri, r,
+                       u.isns.use_discoveryd,
+                       IDBM_SHOW, "No", "Yes", num, 1);
+               __recinfo_int(DISC_ISNS_DISC_DAEMON_POLL_INVAL, ri, r,
+                       u.isns.discoveryd_poll_inval,
+                       IDBM_SHOW, num, 1);
+               break;
+       default:
+               break;
+       }
+}
+
+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);
+       __recinfo_int_o3(NODE_STARTUP, ri, r, startup,
+                       IDBM_SHOW, "manual", "automatic", "onboot", num, 1);
+       __recinfo_int_o2(NODE_LEADING_LOGIN, ri, r, leading_login, IDBM_SHOW,
+                        "No", "Yes", num, 1);
+       /*
+        * Note: because we do not add the iface.iscsi_ifacename to
+        * sysfs iscsiadm does some weird matching. We can change the iface
+        * values if a session is not running, but node record ifaces values
+        * have to be changed and so do the iface record ones.
+        *
+        * Users should nornmally not want to change the iface ones
+        * in the node record directly and instead do it through
+        * the iface mode which will do the right thing (although that
+        * needs some locking).
+        */
+       __recinfo_str(IFACE_HWADDR, ri, r, iface.hwaddress, IDBM_SHOW, num, 1);
+       __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);
+       __recinfo_uint8(IFACE_PREFIX_LEN, ri, r, iface.prefix_len,
+                       IDBM_SHOW, num, 1);
+       /*
+        * svn 780 compat: older versions used node.transport_name and
+        * rec->transport_name
+        */
+       __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_STATE, ri, r, iface.state, IDBM_SHOW, num, 1);
+       __recinfo_uint16(IFACE_VLAN_ID, ri, r, iface.vlan_id, IDBM_SHOW, num,
+                        1);
+       __recinfo_uint8(IFACE_VLAN_PRIORITY, ri, r, iface.vlan_priority,
+                       IDBM_SHOW, num, 1);
+       __recinfo_str(IFACE_VLAN_STATE, ri, r, iface.vlan_state, IDBM_SHOW,
+                     num, 1);
+       __recinfo_int(IFACE_NUM, ri, r, iface.iface_num, IDBM_SHOW, num, 1);
+       __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,
+                     num, 0);
+       __recinfo_int_o6(NODE_DISC_TYPE, ri, r, disc_type, IDBM_SHOW,
+                        "send_targets", "isns", "offload_send_targets", "slp",
+                        "static", "fw", num, 0);
+       __recinfo_int(SESSION_INIT_CMDSN, ri, r,
+                     session.initial_cmdsn, IDBM_SHOW, num, 1);
+       __recinfo_int(SESSION_INIT_LOGIN_RETRY, ri, r,
+                     session.initial_login_retry_max, IDBM_SHOW, num, 1);
+       __recinfo_int(SESSION_XMIT_THREAD_PRIORITY, ri, r,
+                     session.xmit_thread_priority, IDBM_SHOW, num, 1);
+       __recinfo_int(SESSION_CMDS_MAX, ri, r,
+                     session.cmds_max, IDBM_SHOW, num, 1);
+       __recinfo_int(SESSION_QDEPTH, ri, r,
+                      session.queue_depth, IDBM_SHOW, num, 1);
+       __recinfo_int(SESSION_NR_SESSIONS, ri, r,
+                      session.nr_sessions, IDBM_SHOW, num, 1);
+       __recinfo_int_o2(SESSION_AUTH_METHOD, ri, r, session.auth.authmethod,
+                        IDBM_SHOW, "None", "CHAP", num, 1);
+       __recinfo_str(SESSION_USERNAME, ri, r,
+                     session.auth.username, IDBM_SHOW, num, 1);
+       __recinfo_str(SESSION_PASSWORD, ri, r,
+                     session.auth.password, IDBM_MASKED, num, 1);
+       __recinfo_int(SESSION_PASSWORD_LEN, ri, r,
+                     session.auth.password_length, IDBM_HIDE, num, 1);
+       __recinfo_str(SESSION_USERNAME_IN, ri, r,
+                     session.auth.username_in, IDBM_SHOW, num, 1);
+       __recinfo_str(SESSION_PASSWORD_IN, ri, r,
+                     session.auth.password_in, IDBM_MASKED, num, 1);
+       __recinfo_int(SESSION_PASSWORD_IN_LEN, ri, r,
+                     session.auth.password_in_length, IDBM_HIDE, num, 1);
+       __recinfo_int_list(SESSION_CHAP_ALGS, ri, r,
+                          session.auth.chap_algs, IDBM_SHOW, chap_algs, num, 1);
+       __recinfo_int(SESSION_REPLACEMENT_TMO, ri, r,
+                     session.timeo.replacement_timeout,
+                     IDBM_SHOW, num, 1);
+       __recinfo_int(SESSION_ABORT_TMO, ri, r,
+                     session.err_timeo.abort_timeout,
+                     IDBM_SHOW, num, 1);
+       __recinfo_int(SESSION_LU_RESET_TMO, ri, r,
+                     session.err_timeo.lu_reset_timeout,
+                     IDBM_SHOW, num, 1);
+       __recinfo_int(SESSION_TGT_RESET_TMO, ri, r,
+                     session.err_timeo.tgt_reset_timeout,
+                     IDBM_SHOW, num, 1);
+       __recinfo_int(SESSION_HOST_RESET_TMO, ri, r,
+                     session.err_timeo.host_reset_timeout,
+                     IDBM_SHOW, num, 1);
+       __recinfo_int_o2(SESSION_FAST_ABORT, ri, r,
+                        session.iscsi.FastAbort, IDBM_SHOW, "No", "Yes",
+                        num, 1);
+       __recinfo_int_o2(SESSION_INITIAL_R2T, ri, r,
+                       session.iscsi.InitialR2T, IDBM_SHOW,
+                       "No", "Yes", num, 1);
+       __recinfo_int_o2(SESSION_IMM_DATA, ri, r,
+                       session.iscsi.ImmediateData,
+                       IDBM_SHOW, "No", "Yes", num, 1);
+       __recinfo_int(SESSION_FIRST_BURST, ri, r,
+                     session.iscsi.FirstBurstLength, IDBM_SHOW, num, 1);
+       __recinfo_int(SESSION_MAX_BURST, ri, r,
+                     session.iscsi.MaxBurstLength, IDBM_SHOW, num, 1);
+       __recinfo_int(SESSION_DEF_TIME2RETAIN, ri, r,
+                     session.iscsi.DefaultTime2Retain, IDBM_SHOW, num, 1);
+       __recinfo_int(SESSION_DEF_TIME2WAIT, ri, r,
+                     session.iscsi.DefaultTime2Wait, IDBM_SHOW, num, 1);
+       __recinfo_int(SESSION_MAX_CONNS, ri, r,
+                     session.iscsi.MaxConnections, IDBM_SHOW, num, 1);
+       __recinfo_int(SESSION_MAX_R2T, ri, r,
+                     session.iscsi.MaxOutstandingR2T, IDBM_SHOW, num, 1);
+       __recinfo_int(SESSION_ERL, ri, r,
+                     session.iscsi.ERL, IDBM_SHOW, num, 1);
+       __recinfo_int_o2(SESSION_SCAN, ri, r,
+                        session.scan, IDBM_SHOW, "manual", "auto",
+                        num, 1);
+       __recinfo_int(SESSION_REOPEN_MAX, ri, r,
+                       session.reopen_max, IDBM_SHOW, num, 1);
+
+       for (i = 0; i < ISCSI_CONN_MAX; i++) {
+               char key[NAME_MAXVAL];
+
+               sprintf(key, CONN_ADDR, i);
+               __recinfo_str(key, ri, r, conn[i].address, IDBM_SHOW, num, 0);
+               sprintf(key, CONN_PORT, i);
+               __recinfo_int(key, ri, r, conn[i].port, IDBM_SHOW, num, 0);
+               sprintf(key, CONN_STARTUP, i);
+               __recinfo_int_o3(key, ri, r, conn[i].startup, IDBM_SHOW,
+                                "manual", "automatic", "onboot", num, 1);
+               sprintf(key, CONN_WINDOW_SIZE, i);
+               __recinfo_int(key, ri, r, conn[i].tcp.window_size,
+                             IDBM_SHOW, num, 1);
+               sprintf(key, CONN_SERVICE_TYPE, i);
+               __recinfo_int(key, ri, r, conn[i].tcp.type_of_service,
+                               IDBM_SHOW, num, 1);
+               sprintf(key, CONN_LOGOUT_TMO, i);
+               __recinfo_int(key, ri, r, conn[i].timeo.logout_timeout,
+                               IDBM_SHOW, num, 1);
+               sprintf(key, CONN_LOGIN_TMO, i);
+               __recinfo_int(key, ri, r, conn[i].timeo.login_timeout,
+                               IDBM_SHOW, num, 1);
+               sprintf(key, CONN_AUTH_TMO, i);
+               __recinfo_int(key, ri, r, conn[i].timeo.auth_timeout,
+                               IDBM_SHOW, num, 1);
+
+               sprintf(key, CONN_NOP_INT, i);
+               __recinfo_int(key, ri, r, conn[i].timeo.noop_out_interval,
+                               IDBM_SHOW, num, 1);
+               sprintf(key, CONN_NOP_TMO, i);
+               __recinfo_int(key, ri, r, conn[i].timeo.noop_out_timeout,
+                               IDBM_SHOW, num, 1);
+
+               sprintf(key, CONN_MAX_XMIT_DLEN, i);
+               __recinfo_int(key, ri, r,
+                       conn[i].iscsi.MaxXmitDataSegmentLength, IDBM_SHOW,
+                       num, 1);
+               sprintf(key, CONN_MAX_RECV_DLEN, i);
+               __recinfo_int(key, ri, r,
+                       conn[i].iscsi.MaxRecvDataSegmentLength, IDBM_SHOW,
+                       num, 1);
+               sprintf(key, CONN_HDR_DIGEST, i);
+               __recinfo_int_o4(key, ri, r, conn[i].iscsi.HeaderDigest,
+                                IDBM_SHOW, "None", "CRC32C", "CRC32C,None",
+                                "None,CRC32C", num, 1);
+               sprintf(key, CONN_DATA_DIGEST, i);
+               __recinfo_int_o4(key, ri, r, conn[i].iscsi.DataDigest, IDBM_SHOW,
+                                "None", "CRC32C", "CRC32C,None",
+                                "None,CRC32C", num, 1);
+               sprintf(key, CONN_IFMARKER, i);
+               __recinfo_int_o2(key, ri, r, conn[i].iscsi.IFMarker, IDBM_SHOW,
+                               "No", "Yes", num, 1);
+               sprintf(key, CONN_OFMARKER, i);
+               __recinfo_int_o2(key, ri, r, conn[i].iscsi.OFMarker, IDBM_SHOW,
+                               "No", "Yes", num, 1);
+       }
+}
+
+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);
+       __recinfo_str(IFACE_IPADDR, ri, r, ipaddress, IDBM_SHOW, num, 1);
+       __recinfo_uint8(IFACE_PREFIX_LEN, ri, r, prefix_len, IDBM_SHOW, num, 1);
+       __recinfo_str(IFACE_HWADDR, ri, r, hwaddress, IDBM_SHOW, num, 1);
+       __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_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,
+                     IDBM_SHOW, num, 1);
+       __recinfo_str(IFACE_VLAN_STATE, ri, r, vlan_state, IDBM_SHOW, num, 1);
+       __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);
+}
+
+void idbm_recinfo_host_chap(struct iscsi_chap_rec *r, recinfo_t *ri)
+{
+       int num = 0;
+
+       __recinfo_uint16(HOST_AUTH_INDEX, ri, r, chap_tbl_idx, IDBM_SHOW,
+                        num, 1);
+
+       if (r->chap_type == CHAP_TYPE_OUT) {
+               __recinfo_str(HOST_AUTH_USERNAME, ri, r, username, IDBM_SHOW,
+                             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, 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,
+                             IDBM_HIDE, num, 1);
+       }
+}
+
+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;
+
+       info = malloc(sizeof(recinfo_t)*max_keys);
+       if (!info)
+               return NULL;
+       memset(info, 0, sizeof(recinfo_t)*max_keys);
+       return info;
+}
+
+void idbm_print(int type, void *rec, int show, FILE *f)
+{
+       int i;
+       recinfo_t *info;
+
+       info = idbm_recinfo_alloc(MAX_KEYS);
+       if (!info)
+               return;
+
+       switch (type) {
+       case IDBM_PRINT_TYPE_DISCOVERY:
+               idbm_recinfo_discovery((discovery_rec_t*)rec, info);
+               break;
+       case IDBM_PRINT_TYPE_NODE:
+               idbm_recinfo_node((node_rec_t*)rec, info);
+               break;
+       case IDBM_PRINT_TYPE_IFACE:
+               idbm_recinfo_iface((struct iface_rec *)rec, info);
+               break;
+       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);
+       for (i = 0; i < MAX_KEYS; i++) {
+               if (!info[i].visible)
+                       continue;
+               if (!show && info[i].visible == IDBM_MASKED) {
+                       if (*(char*)info[i].data) {
+                               fprintf(f, "%s = ********\n", info[i].name);
+                               continue;
+                       }
+                       /* fall through */
+               }
+
+               if (strlen(info[i].value))
+                       fprintf(f, "%s = %s\n", info[i].name, info[i].value);
+               else if (f == stdout)
+                       fprintf(f, "%s = <empty>\n", info[i].name);
+       }
+       fprintf(f, "%s\n", ISCSI_END_REC);
+
+       free(info);
+}
+
+static void
+idbm_setup_session_defaults(struct iscsi_session_operational_config *conf)
+{
+       conf->InitialR2T = 0;
+       conf->ImmediateData = 1;
+       conf->FirstBurstLength = DEF_INI_FIRST_BURST_LEN;
+       conf->MaxBurstLength = DEF_INI_MAX_BURST_LEN;
+       conf->DefaultTime2Wait = ISCSI_DEF_TIME2WAIT;
+       conf->DefaultTime2Retain = 0;
+       conf->MaxConnections = 1;
+       conf->MaxOutstandingR2T = 1;
+       conf->ERL = 0;
+       conf->FastAbort = 1;
+}
+
+static void idbm_setup_conn_defaults(struct iscsi_conn_operational_config *conf)
+{
+       conf->MaxXmitDataSegmentLength = 0;
+       conf->MaxRecvDataSegmentLength = DEF_INI_MAX_RECV_SEG_LEN;
+       conf->HeaderDigest = CONFIG_DIGEST_NEVER;
+       conf->DataDigest = CONFIG_DIGEST_NEVER;
+       conf->IFMarker = 0;
+       conf->OFMarker = 0;
+}
+
+static void
+idbm_discovery_setup_defaults(discovery_rec_t *rec, discovery_type_e type)
+{
+       memset(rec, 0, sizeof(discovery_rec_t));
+
+       rec->startup = ISCSI_STARTUP_MANUAL;
+       rec->type = type;
+       rec->iscsid_req_tmo = -1;
+       switch (type) {
+       case DISCOVERY_TYPE_SENDTARGETS:
+               rec->u.sendtargets.discoveryd_poll_inval = 30;
+               rec->u.sendtargets.use_discoveryd = 0;
+               rec->u.sendtargets.reopen_max = 5;
+               rec->u.sendtargets.auth.authmethod = 0;
+               rec->u.sendtargets.auth.password_length = 0;
+               rec->u.sendtargets.auth.password_in_length = 0;
+               /* TYPE_INT_LIST fields should be initialized to ~0 to indicate unset values */
+               memset(rec->u.sendtargets.auth.chap_algs, ~0, sizeof(rec->u.sendtargets.auth.chap_algs));
+               rec->u.sendtargets.auth.chap_algs[0] = AUTH_CHAP_ALG_MD5;
+               rec->u.sendtargets.conn_timeo.login_timeout=15;
+               rec->u.sendtargets.conn_timeo.auth_timeout = 45;
+               rec->u.sendtargets.conn_timeo.active_timeout=30;
+               idbm_setup_session_defaults(&rec->u.sendtargets.session_conf);
+               idbm_setup_conn_defaults(&rec->u.sendtargets.conn_conf);
+               /* override def setting */
+               rec->u.sendtargets.conn_conf.MaxRecvDataSegmentLength =
+                                               DEF_INI_DISC_MAX_RECV_SEG_LEN;
+               break;
+       case DISCOVERY_TYPE_SLP:
+               rec->u.slp.interfaces = NULL;
+               rec->u.slp.scopes = NULL;
+               rec->u.slp.poll_interval = 5 * 60;      /* 5 minutes */
+               rec->u.slp.auth.authmethod = 0;
+               rec->u.slp.auth.password_length = 0;
+               rec->u.slp.auth.password_in_length = 0;
+               rec->u.slp.auth.password_in_length = 0;
+               break;
+       case DISCOVERY_TYPE_ISNS:
+               rec->u.isns.use_discoveryd = 0;
+               rec->u.isns.discoveryd_poll_inval = -1;
+               break;
+       default:
+               break;
+       }
+}
+
+int idbm_rec_update_param(recinfo_t *info, char *name, char *value,
+                         int line_number)
+{
+       int i;
+       int passwd_done = 0;
+       char passwd_len[8];
+       char *tmp_value, *token, *tmp;
+       bool *found = NULL;
+       int *tmp_data;
+
+setup_passwd_len:
+       for (i=0; i<MAX_KEYS; i++) {
+               if (!strcmp(name, info[i].name)) {
+                       int j,k;
+                       struct int_list_tbl *tbl;
+
+                       log_debug(7, "updated '%s', '%s' => '%s'", name,
+                                 info[i].value, value);
+                       /* parse recinfo by type */
+                       switch (info[i].type) {
+                       case TYPE_INT:
+                               if (!info[i].data)
+                                       continue;
+
+                               *(int*)info[i].data =
+                                       strtoul(value, NULL, 10);
+                               goto updated;
+                       case TYPE_UINT8:
+                               if (!info[i].data)
+                                       continue;
+
+                               *(uint8_t *)info[i].data =
+                                       strtoul(value, NULL, 10);
+                               goto updated;
+                       case TYPE_UINT16:
+                               if (!info[i].data)
+                                       continue;
+
+                               *(uint16_t *)info[i].data =
+                                       strtoul(value, NULL, 10);
+                               goto updated;
+                       case TYPE_UINT32:
+                               if (!info[i].data)
+                                       continue;
+
+                               *(uint32_t *)info[i].data =
+                                       strtoul(value, NULL, 10);
+                               goto updated;
+                       case TYPE_STR:
+                               if (!info[i].data)
+                                       continue;
+
+                               strlcpy((char*)info[i].data,
+                                       value, info[i].data_len);
+                               goto updated;
+                       case TYPE_INT_O:
+                               for (j=0; j<info[i].numopts; j++) {
+                                       if (!strcmp(value, info[i].opts[j])) {
+                                               if (!info[i].data)
+                                                       continue;
+
+                                               *(int*)info[i].data = j;
+                                               goto updated;
+                                       }
+                               }
+                               /* internal error if reached ?? */
+                               break;
+                       case TYPE_INT_LIST:
+                               if (!info[i].data)
+                                       continue;
+                               tbl = (void *)info[i].opts[0];
+                               /*
+                                * strsep is destructive, make a copy to work with
+                                * tmp_value would be modified in strsep() too, so
+                                * here make a copy of tmp_value to tmp
+                                */
+                               tmp_value = strdup(value);
+                               if (!tmp_value)
+                                       return ISCSI_ERR_NOMEM;
+                               tmp = tmp_value;
+
+                               k = 0;
+                               tmp_data = malloc(info[i].data_len);
+                               if (!tmp_data)
+                                       goto free_tmp;
+                               memset(tmp_data, ~0, info[i].data_len);
+
+                               found = calloc(info[i].numopts, sizeof(bool));
+                               if (!found)
+                                       goto free_tmp_data;
+
+next_token:                    while ((token = strsep(&tmp_value, ", \n"))) {
+                                       if (!strlen(token))
+                                               continue;
+                                       if ((k * (int)sizeof(int)) >= (info[i].data_len)) {
+                                               log_warning("Too many values set for '%s'"
+                                                           ", continuing without processing them all",
+                                                           info[i].name);
+                                               break;
+                                       }
+                                       for (j = 0; j < info[i].numopts; j++) {
+                                               if (!strcmp(token, tbl[j].name)) {
+                                                       if ((found[j])) {
+                                                               log_warning("Ignoring repeated "
+                                                                           "value '%s' "
+                                                                           "for '%s'", token,
+                                                                           info[i].name);
+                                                               goto next_token;
+                                                       }
+                                                       ((int*)tmp_data)[k++] = tbl[j].value;
+                                                       found[j] = true;
+                                                       goto next_token;
+                                               }
+                                       }
+                                       log_warning("Ignoring unknown value '%s'"
+                                                   " for '%s'", token, info[i].name);
+                               }
+                               memcpy(info[i].data, tmp_data, info[i].data_len);
+                               free(tmp);
+                               free(tmp_data);
+                               tmp_value = NULL;
+                               tmp_data = NULL;
+                               token = NULL;
+                               goto updated;
+                       }
+                       if (line_number) {
+                               log_warning("config file line %d contains "
+                                           "unknown value format '%s' for "
+                                           "parameter name '%s'",
+                                           line_number, value, name);
+                       } else {
+                               log_error("unknown value format '%s' for "
+                                         "parameter name '%s'", value, name);
+                       }
+                       break;
+               }
+       }
+
+       return ISCSI_ERR_INVAL;
+
+free_tmp_data:
+       free(tmp_data);
+
+free_tmp:
+       free(tmp);
+       return ISCSI_ERR_NOMEM;
+
+updated:
+       strlcpy((char*)info[i].value, value, VALUE_MAXVAL);
+       if (found)
+               free(found);
+
+#define check_password_param(_param) \
+       if (!passwd_done && !strcmp(#_param, name)) { \
+               passwd_done = 1; \
+               name = #_param "_length"; \
+               snprintf(passwd_len, 8, "%.7" PRIi32, (int)strlen(value) & 0xffff); \
+               value = passwd_len; \
+               goto setup_passwd_len; \
+       }
+
+       check_password_param(node.session.auth.password);
+       check_password_param(node.session.auth.password_in);
+       check_password_param(discovery.sendtargets.auth.password);
+       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;
+}
+
+/*
+ * TODO: we can also check for valid values here.
+ */
+int idbm_verify_param(recinfo_t *info, char *name)
+{
+       int i;
+
+       for (i = 0; i < MAX_KEYS; i++) {
+               if (strcmp(name, info[i].name))
+                       continue;
+
+               log_debug(7, "verify %s %d", name, info[i].can_modify);
+               if (info[i].can_modify)
+                       return 0;
+               else {
+                       log_error("Cannot modify %s. It is used to look up "
+                                 "the record and cannot be changed.", name);
+                       return ISCSI_ERR_INVAL;
+               }
+       }
+
+       log_error("Cannot modify %s. Invalid param name.", name);
+       return ISCSI_ERR_INVAL;
+}
+
+void idbm_recinfo_config(recinfo_t *info, FILE *f)
+{
+       char name[NAME_MAXVAL];
+       char value[VALUE_MAXVAL];
+       char *line, *nl, buffer[2048];
+       int line_number = 0;
+       int c = 0, i;
+
+       fseek(f, 0, SEEK_SET);
+
+       /* process the config file */
+       do {
+               line = fgets(buffer, sizeof (buffer), f);
+               line_number++;
+               if (!line)
+                       continue;
+
+               nl = line + strlen(line) - 1;
+               if (*nl != '\n') {
+                       log_warning("Config file line %d too long.",
+                              line_number);
+                       continue;
+               }
+
+               line = strstrip(line);
+               /* process any non-empty, non-comment lines */
+               if (!*line || *line == '\0' || *line ==  '\n' || *line == '#')
+                       continue;
+
+               /* parse name */
+               i=0; nl = line; *name = 0;
+               while (*nl && !isspace(c = *nl) && *nl != '=') {
+                       *(name+i) = *nl; i++; nl++;
+               }
+               if (!*nl) {
+                       log_warning("Config file line %d does not have value",
+                              line_number);
+                       continue;
+               }
+               *(name+i)=0; nl++;
+               /* skip after-name traling spaces */
+               while (*nl && isspace(c = *nl)) nl++;
+               if (*nl && *nl != '=') {
+                       log_warning("Config file line %d does not have '=' separator",
+                              line_number);
+                       continue;
+               }
+               /* skip '=' sepa */
+               nl++;
+               /* skip after-sepa traling spaces */
+               while (*nl && isspace(c = *nl)) nl++;
+               if (!*nl) {
+                       log_warning("Config file line %d does not have value",
+                              line_number);
+                       continue;
+               }
+               /* parse value */
+               i=0; *value = 0;
+               while (*nl) {
+                       *(value+i) = *nl; i++; nl++;
+               }
+               *(value+i) = 0;
+
+               idbm_rec_update_param(info, name, value, line_number);
+       } while (line);
+}
+
+/*
+ * TODO: remove db's copy of nrec and infos
+ */
+static void idbm_sync_config(void)
+{
+       char *config_file;
+       FILE *f;
+
+       /* in case of no configuration file found we just
+        * initialize default node and default discovery records
+        * from hard-coded default values */
+       idbm_node_setup_defaults(&db->nrec);
+       idbm_discovery_setup_defaults(&db->drec_st, DISCOVERY_TYPE_SENDTARGETS);
+       idbm_discovery_setup_defaults(&db->drec_slp, DISCOVERY_TYPE_SLP);
+       idbm_discovery_setup_defaults(&db->drec_isns, DISCOVERY_TYPE_ISNS);
+
+       idbm_recinfo_discovery(&db->drec_st, db->dinfo_st);
+       idbm_recinfo_discovery(&db->drec_slp, db->dinfo_slp);
+       idbm_recinfo_discovery(&db->drec_isns, db->dinfo_isns);
+       idbm_recinfo_node(&db->nrec, db->ninfo);
+
+       if (!db->get_config_file) {
+               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");
+               return;
+       }
+
+       f = fopen(config_file, "r");
+       if (!f) {
+               log_debug(1, "cannot open configuration file %s. "
+                         "Default location is %s.",
+                         config_file, CONFIG_FILE);
+               return;
+       }
+       log_debug(5, "updating defaults from '%s'", config_file);
+
+       idbm_recinfo_config(db->dinfo_st, f);
+       idbm_recinfo_config(db->dinfo_slp, f);
+       idbm_recinfo_config(db->dinfo_isns, f);
+       idbm_recinfo_config(db->ninfo, f);
+       fclose(f);
+
+       /* update password lengths */
+       if (*db->drec_st.u.sendtargets.auth.password)
+               db->drec_st.u.sendtargets.auth.password_length =
+                       strlen((char*)db->drec_st.u.sendtargets.auth.password);
+       if (*db->drec_st.u.sendtargets.auth.password_in)
+               db->drec_st.u.sendtargets.auth.password_in_length =
+                    strlen((char*)db->drec_st.u.sendtargets.auth.password_in);
+       if (*db->drec_slp.u.slp.auth.password)
+               db->drec_slp.u.slp.auth.password_length =
+                       strlen((char*)db->drec_slp.u.slp.auth.password);
+       if (*db->drec_slp.u.slp.auth.password_in)
+               db->drec_slp.u.slp.auth.password_in_length =
+                       strlen((char*)db->drec_slp.u.slp.auth.password_in);
+       if (*db->nrec.session.auth.password)
+               db->nrec.session.auth.password_length =
+                       strlen((char*)db->nrec.session.auth.password);
+       if (*db->nrec.session.auth.password_in)
+               db->nrec.session.auth.password_in_length =
+                       strlen((char*)db->nrec.session.auth.password_in);
+}
+
+void idbm_node_setup_from_conf(node_rec_t *rec)
+{
+       memset(rec, 0, sizeof(*rec));
+       idbm_node_setup_defaults(rec);
+       idbm_sync_config();
+       memcpy(rec, &db->nrec, sizeof(*rec));
+}
+
+int idbm_print_discovery_info(discovery_rec_t *rec, int show)
+{
+       idbm_print(IDBM_PRINT_TYPE_DISCOVERY, rec, show, stdout);
+       return 1;
+}
+
+int idbm_print_node_info(void *data, node_rec_t *rec)
+{
+       int show = *((int *)data);
+
+       idbm_print(IDBM_PRINT_TYPE_NODE, rec, show, stdout);
+       return 0;
+}
+
+int idbm_print_host_chap_info(struct iscsi_chap_rec *chap)
+{
+       /* User only calls this to print chap so always print */
+       idbm_print(IDBM_PRINT_TYPE_HOST_CHAP, chap, 1, stdout);
+       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(__attribute__((unused))void *data, node_rec_t *rec)
+{
+       if (strchr(rec->conn[0].address, '.'))
+               printf("%s:%d,%d %s\n", rec->conn[0].address, rec->conn[0].port,
+                       rec->tpgt, rec->name);
+       else
+               printf("[%s]:%d,%d %s\n", rec->conn[0].address,
+                      rec->conn[0].port, rec->tpgt, rec->name);
+       return 0;
+}
+
+int idbm_print_node_tree(struct node_rec *last_rec, struct node_rec *rec,
+                        char *prefix)
+{
+       if (!last_rec || strcmp(last_rec->name, rec->name)) {
+               printf("%sTarget: %s\n", prefix, rec->name);
+               if (last_rec)
+                       memset(last_rec, 0, sizeof(node_rec_t));
+       }
+
+       if (!last_rec ||
+            ((strcmp(last_rec->conn[0].address, rec->conn[0].address) ||
+            last_rec->conn[0].port != rec->conn[0].port))) {
+               if (strchr(rec->conn[0].address, '.'))
+                       printf("%s\tPortal: %s:%d,%d\n", prefix,
+                              rec->conn[0].address,
+                              rec->conn[0].port, rec->tpgt);
+               else
+                       printf("%s\tPortal: [%s]:%d,%d\n", prefix,
+                              rec->conn[0].address,
+                              rec->conn[0].port, rec->tpgt);
+       }
+
+       if (last_rec)
+               memcpy(last_rec, rec, sizeof(node_rec_t));
+       return 0;
+}
+
+int idbm_print_node_and_iface_tree(void *data, node_rec_t *rec)
+{
+       idbm_print_node_tree(data, rec, "");
+       printf("\t\tIface Name: %s\n", rec->iface.name);
+       return 0;
+}
+
+static int
+get_params_from_disc_link(char *link, char **target, char **tpgt,
+                         char **address, char **port, char **ifaceid)
+{
+       (*target) = link;
+       *address = strchr(*target, ',');
+       if (!(*address))
+               return ISCSI_ERR_INVAL;
+       *(*address)++ = '\0';
+       *port = strchr(*address, ',');
+       if (!(*port))
+               return ISCSI_ERR_INVAL;
+       *(*port)++ = '\0';
+       *tpgt = strchr(*port, ',');
+       if (!(*tpgt))
+               return ISCSI_ERR_INVAL;
+       *(*tpgt)++ = '\0';
+       *ifaceid = strchr(*tpgt, ',');
+       if (!(*ifaceid))
+               return ISCSI_ERR_INVAL;
+       *(*ifaceid)++ = '\0';
+       return 0;
+}
+
+int idbm_lock(void)
+{
+       int fd, i, ret;
+
+       if (db->refs > 0) {
+               db->refs++;
+               return 0;
+       }
+
+       if (access(LOCK_DIR, F_OK) != 0) {
+               if (mkdir(LOCK_DIR, 0770) != 0) {
+                       log_error("Could not open %s: %s", LOCK_DIR,
+                                 strerror(errno));
+                       return ISCSI_ERR_IDBM;
+               }
+       }
+
+       fd = open(LOCK_FILE, O_RDWR | O_CREAT, 0666);
+       if (fd >= 0)
+               close(fd);
+
+       for (i = 0; i < 3000; i++) {
+               ret = link(LOCK_FILE, LOCK_WRITE_FILE);
+               if (ret == 0)
+                       break;
+
+               if (errno != EEXIST) {
+                       log_error("Maybe you are not root?");
+                       log_error("Could not lock discovery DB: %s: %s",
+                                       LOCK_WRITE_FILE, strerror(errno));
+                       return ISCSI_ERR_IDBM;
+               } else if (i == 0)
+                       log_debug(2, "Waiting for discovery DB lock");
+
+               usleep(10000);
+       }
+
+       db->refs = 1;
+       return 0;
+}
+
+void idbm_unlock(void)
+{
+       if (db->refs > 1) {
+               db->refs--;
+               return;
+       }
+
+       db->refs = 0;
+       unlink(LOCK_WRITE_FILE);
+}
+
+/*
+ * Backwards Compat:
+ * If the portal is a file then we are doing the old style default
+ * session behavior (svn pre 780).
+ */
+static FILE *idbm_open_rec_r(char *portal, char *config)
+{
+       struct stat statb;
+
+       log_debug(5, "Looking for config file %s config %s.", portal, config);
+
+       if (stat(portal, &statb)) {
+               log_debug(5, "Could not stat %s err %d.", portal, errno);
+               return NULL;
+       }
+
+       if (S_ISDIR(statb.st_mode)) {
+               strlcat(portal, "/", PATH_MAX);
+               strlcat(portal, config, PATH_MAX);
+       }
+       return fopen(portal, "r");
+}
+
+/*
+ * When the disable_lock param is true, the idbm_lock/idbm_unlock needs
+ * to be holt by the caller, this will avoid overwriting each other in
+ * case of updating(read-modify-write) the recs in parallel.
+ */
+static int __idbm_rec_read(node_rec_t *out_rec, char *conf, bool disable_lock)
+{
+       recinfo_t *info;
+       FILE *f;
+       int rc = 0;
+
+       info = idbm_recinfo_alloc(MAX_KEYS);
+       if (!info)
+               return ISCSI_ERR_NOMEM;
+
+       if (!disable_lock) {
+               rc = idbm_lock();
+               if (rc)
+                       goto free_info;
+       }
+
+       f = fopen(conf, "r");
+       if (!f) {
+               log_debug(5, "Could not open %s err %s", conf,
+                         strerror(errno));
+               rc = ISCSI_ERR_IDBM;
+               goto unlock;
+       }
+
+       memset(out_rec, 0, sizeof(*out_rec));
+       idbm_node_setup_defaults(out_rec);
+       idbm_recinfo_node(out_rec, info);
+       idbm_recinfo_config(info, f);
+       fclose(f);
+
+unlock:
+       if (!disable_lock)
+               idbm_unlock();
+free_info:
+       free(info);
+       return rc;
+}
+
+/*
+ * When the disable_lock param is true, the idbm_lock/idbm_unlock needs
+ * to be holt by the caller, this will avoid overwriting each other in
+ * case of updating(read-modify-write) the recs in parallel.
+ */
+int
+idbm_rec_read(node_rec_t *out_rec, char *targetname, int tpgt,
+             char *ip, int port, struct iface_rec *iface, bool disable_lock)
+{
+       struct stat statb;
+       char *portal;
+       int rc;
+
+       portal = calloc(1, PATH_MAX);
+       if (!portal)
+               return ISCSI_ERR_IDBM;
+
+       /* try old style portal as config */
+       snprintf(portal, PATH_MAX, "%s/%s/%s,%d", NODE_CONFIG_DIR,
+                targetname, ip, port);
+       log_debug(5, "rec read looking for config file %s.", portal);
+       if (!stat(portal, &statb))
+               goto read;
+
+       snprintf(portal, PATH_MAX, "%s/%s/%s,%d,%d/%s", NODE_CONFIG_DIR,
+                targetname, ip, port, tpgt, iface->name);
+       log_debug(5, "rec read looking for config file %s.", portal);
+       if (!strlen(iface->name)) {
+               rc = ISCSI_ERR_INVAL;
+               goto free_portal;
+       }
+
+       if (stat(portal, &statb)) {
+               log_debug(5, "Could not stat %s: %s.", portal, strerror(errno));
+               free(portal);
+               return ISCSI_ERR_IDBM;
+       }
+
+read:
+       rc = __idbm_rec_read(out_rec, portal, disable_lock);
+free_portal:
+       free(portal);
+       return rc;
+}
+
+static int print_discovered_flat(void *data, node_rec_t *rec)
+{
+       struct discovery_rec *drec = data;
+
+       if (rec->disc_type != drec->type)
+               goto no_match;
+
+       if (drec->type == DISCOVERY_TYPE_SENDTARGETS ||
+           drec->type == DISCOVERY_TYPE_ISNS) {
+               if (rec->disc_port != drec->port ||
+                   strcmp(rec->disc_address, drec->address))
+                       goto no_match;
+       }
+
+       idbm_print_node_flat(NULL, rec);
+       return 0;
+no_match:
+       return -1;
+}
+
+struct discovered_tree_info {
+       struct discovery_rec *drec;
+       struct node_rec *last_rec;
+};
+
+static int print_discovered_tree(void *data, node_rec_t *rec)
+{
+       struct discovered_tree_info *tree_info = data;
+       struct discovery_rec *drec = tree_info->drec;
+
+       if (rec->disc_type != drec->type)
+               goto no_match;
+
+       if (strlen(drec->address)) {
+               if (rec->disc_port != drec->port ||
+                   strcmp(rec->disc_address, drec->address))
+                       goto no_match;
+       }
+
+       idbm_print_node_and_iface_tree(tree_info->last_rec, rec);
+       return 0;
+no_match:
+       return -1;
+}
+
+static int idbm_print_discovered(discovery_rec_t *drec, int info_level)
+{
+       int num_found = 0;
+
+       if (info_level < 1)
+               idbm_for_each_rec(&num_found, drec, print_discovered_flat, false);
+       else {
+               struct discovered_tree_info tree_info;
+               struct node_rec last_rec;
+
+               memset(&last_rec, 0, sizeof(struct node_rec));
+
+               tree_info.drec = drec;
+               tree_info.last_rec = &last_rec;
+
+               idbm_for_each_rec(&num_found, &tree_info, print_discovered_tree, false);
+       }
+       return num_found;
+}
+
+static int idbm_for_each_drec(int type, char *config_root, void *data,
+                             idbm_drec_op_fn *fn)
+{
+       DIR *entity_dirfd;
+       struct dirent *entity_dent;
+       int found = 0;
+       discovery_rec_t drec;
+       char *tmp_port;
+
+       entity_dirfd = opendir(config_root);
+       if (!entity_dirfd)
+               return found;
+
+       while ((entity_dent = readdir(entity_dirfd))) {
+               if (!strcmp(entity_dent->d_name, ".") ||
+                   !strcmp(entity_dent->d_name, ".."))
+                       continue;
+
+               log_debug(5, "found %s", entity_dent->d_name);
+
+               tmp_port = strchr(entity_dent->d_name, ',');
+               if (!tmp_port)
+                       continue;
+               /*
+                * pre 872 tools dumped the target portal symlinks in the isns
+                * dir instead of the server. If we find one of those links
+                * (by checking if there is a valid port) we skip it.
+                */
+               if (strchr(tmp_port, ':') || strchr(tmp_port, '.'))
+                       continue;
+               *tmp_port++ = '\0';
+
+               memset(&drec, 0, sizeof(drec));
+               if (idbm_discovery_read(&drec, type, entity_dent->d_name,
+                                       atoi(tmp_port))) {
+                       log_error("Could not read discovery record for "
+                                 "%s:%s.", entity_dent->d_name, tmp_port);
+                       continue;
+               }
+
+               if (!fn(data, &drec))
+                       found++;
+       }
+       closedir(entity_dirfd);
+       return found;
+}
+
+int idbm_for_each_st_drec(void *data, idbm_drec_op_fn *fn)
+{
+       return idbm_for_each_drec(DISCOVERY_TYPE_SENDTARGETS, ST_CONFIG_DIR,
+                                 data, fn);
+}
+
+int idbm_for_each_isns_drec(void *data, idbm_drec_op_fn *fn)
+{
+       return idbm_for_each_drec(DISCOVERY_TYPE_ISNS, ISNS_CONFIG_DIR,
+                                 data, fn);
+}
+
+static int __idbm_print_all_by_drec(void *data, struct discovery_rec *drec)
+{
+       int info_level = *(int *)data;
+
+       if (info_level >= 1) {
+               printf("DiscoveryAddress: %s,%d\n",
+                      drec->address, drec->port);
+               idbm_print_discovered(drec, info_level);
+       } else
+               printf("%s:%d via %s\n", drec->address, drec->port,
+                      drec->type == DISCOVERY_TYPE_ISNS ?
+                      "isns" : "sendtargets");
+       return 0;
+}
+
+static int idbm_print_all_st(int info_level)
+{
+       int rc;
+
+       rc = idbm_for_each_st_drec(&info_level, __idbm_print_all_by_drec);
+       if (rc < 0)
+               return 0;
+       return rc;
+}
+
+static int idbm_print_all_isns(int info_level)
+{
+       int rc;
+
+       rc = idbm_for_each_isns_drec(&info_level, __idbm_print_all_by_drec);
+       if (rc < 0)
+               return 0;
+       return rc;
+}
+
+int idbm_print_all_discovery(int info_level)
+{
+       discovery_rec_t *drec;
+       int found = 0, tmp;
+
+       if (info_level < 1) {
+               found = idbm_print_all_st(info_level);
+               found += idbm_print_all_isns(info_level);
+               return found;
+       }
+
+       drec = calloc(1, sizeof(*drec));
+       if (!drec)
+               return 0;
+
+       tmp = 0;
+       printf("SENDTARGETS:\n");
+       tmp = idbm_print_all_st(info_level);
+       if (!tmp)
+               printf("No targets found.\n");
+       found += tmp;
+       tmp = 0;
+
+       printf("iSNS:\n");
+       tmp = idbm_print_all_isns(info_level);
+       if (!tmp) {
+               /*
+                * pre 872 tools did not store the server ip,port so
+                * we drop down here, to just look for target portals.
+                */
+               drec->type = DISCOVERY_TYPE_ISNS;
+               tmp = idbm_print_discovered(drec, info_level);
+               if (!tmp)
+                       printf("No targets found.\n");
+       }
+       found += tmp;
+       tmp = 0;
+
+       printf("STATIC:\n");
+       drec->type = DISCOVERY_TYPE_STATIC;
+       tmp = idbm_print_discovered(drec, info_level);
+       if (!tmp)
+               printf("No targets found.\n");
+       found += tmp;
+       tmp = 0;
+
+       printf("FIRMWARE:\n");
+       drec->type = DISCOVERY_TYPE_FW;
+       tmp = idbm_print_discovered(drec, info_level);
+       if (!tmp)
+               printf("No targets found.\n");
+       found += tmp;
+
+       free(drec);
+       return found;
+}
+
+/**
+ * idbm_for_each_iface - iterate over bound iface recs
+ * @found: nr of recs found so far
+ * @data: data pointer passed to fn
+ * @fn: iterator function ran over each bound iface rec
+ * @targetname: rec's target name
+ * @tpgt: rec's portal group tag
+ * @ip: rec's ip address
+ * @port: rec's port
+ *
+ * This will run fn over all recs with the {targetname,tpgt,ip,port}
+ * id. It does not iterate over the ifaces setup in the iface DB directory.
+ *
+ * fn should return -1 if it skipped the rec, an ISCSI_ERR error code if
+ * the operation failed or 0 if fn was run successfully.
+ */
+static int idbm_for_each_iface(int *found, void *data, idbm_iface_op_fn *fn,
+                              char *targetname, int tpgt, char *ip, int port,
+                              bool ruw_lock)
+{
+       DIR *iface_dirfd;
+       struct dirent *iface_dent;
+       struct stat statb;
+       node_rec_t rec;
+       int rc = 0;
+       char *portal;
+
+       portal = calloc(1, PATH_MAX);
+       if (!portal)
+               return ISCSI_ERR_NOMEM;
+
+       if (tpgt >= 0)
+               goto read_iface;
+
+       /* old style portal as a config */
+       snprintf(portal, PATH_MAX, "%s/%s/%s,%d", NODE_CONFIG_DIR, targetname,
+                ip, port);
+       if (stat(portal, &statb)) {
+               log_error("iface iter could not stat %s.", portal);
+               rc = ISCSI_ERR_IDBM;
+               goto free_portal;
+       }
+
+       rc = __idbm_rec_read(&rec, portal, ruw_lock);
+       if (rc)
+               goto free_portal;
+
+       rc = fn(data, &rec);
+       if (!rc)
+               (*found)++;
+       else if (rc == -1)
+               rc = 0;
+       goto free_portal;
+
+read_iface:
+       snprintf(portal, PATH_MAX, "%s/%s/%s,%d,%d", NODE_CONFIG_DIR,
+                targetname, ip, port, tpgt);
+
+       iface_dirfd = opendir(portal);
+       if (!iface_dirfd) {
+               log_error("iface iter could not read dir %s.", portal);
+               rc = ISCSI_ERR_IDBM;
+               goto free_portal;
+       }
+
+       while ((iface_dent = readdir(iface_dirfd))) {
+               int curr_rc;
+
+               if (!strcmp(iface_dent->d_name, ".") ||
+                   !strcmp(iface_dent->d_name, ".."))
+                       continue;
+
+               log_debug(5, "iface iter found %s.", iface_dent->d_name);
+               memset(portal, 0, PATH_MAX);
+               snprintf(portal, PATH_MAX, "%s/%s/%s,%d,%d/%s", NODE_CONFIG_DIR,
+                        targetname, ip, port, tpgt, iface_dent->d_name);
+               if (__idbm_rec_read(&rec, portal, ruw_lock))
+                       continue;
+
+               curr_rc = fn(data, &rec);
+               /* less than zero means it was not a match */
+               if (curr_rc > 0 && !rc)
+                       rc = curr_rc;
+               else if (curr_rc == 0)
+                       (*found)++;
+       }
+
+       closedir(iface_dirfd);
+free_portal:
+       free(portal);
+       return rc;
+}
+
+/*
+ * backwards compat
+ * The portal could be a file or dir with interfaces
+ */
+int idbm_for_each_portal(int *found, void *data, idbm_portal_op_fn *fn,
+                        char *targetname, bool ruw_lock)
+{
+       DIR *portal_dirfd;
+       struct dirent *portal_dent;
+       int rc = 0;
+       char *portal;
+
+       portal = calloc(1, PATH_MAX);
+       if (!portal)
+               return ISCSI_ERR_NOMEM;
+
+       snprintf(portal, PATH_MAX, "%s/%s", NODE_CONFIG_DIR, targetname);
+       portal_dirfd = opendir(portal);
+       if (!portal_dirfd) {
+               rc = ISCSI_ERR_IDBM;
+               goto done;
+       }
+
+       while ((portal_dent = readdir(portal_dirfd))) {
+               char *tmp_port, *tmp_tpgt;
+               int curr_rc;
+
+               if (!strcmp(portal_dent->d_name, ".") ||
+                   !strcmp(portal_dent->d_name, ".."))
+                       continue;
+
+               log_debug(5, "found %s", portal_dent->d_name);
+               tmp_port = strchr(portal_dent->d_name, ',');
+               if (!tmp_port)
+                       continue;
+               *tmp_port++ = '\0';
+               tmp_tpgt = strchr(tmp_port, ',');
+               if (tmp_tpgt)
+                       *tmp_tpgt++ = '\0';
+
+               curr_rc = fn(found, data, targetname,
+                       tmp_tpgt ? atoi(tmp_tpgt) : -1,
+                       portal_dent->d_name, atoi(tmp_port),
+                       ruw_lock);
+               /* less than zero means it was not a match */
+               if (curr_rc > 0 && !rc)
+                       rc = curr_rc;
+       }
+       closedir(portal_dirfd);
+done:
+       free(portal);
+       return rc;
+}
+
+int idbm_for_each_node(int *found, void *data, idbm_node_op_fn *fn, bool ruw_lock)
+{
+       DIR *node_dirfd;
+       struct dirent *node_dent;
+       int rc = 0;
+
+       *found = 0;
+
+       node_dirfd = opendir(NODE_CONFIG_DIR);
+       if (!node_dirfd)
+               /* on start up node dir may not be created */
+               return 0;
+
+       while ((node_dent = readdir(node_dirfd))) {
+               int curr_rc;
+
+               if (!strcmp(node_dent->d_name, ".") ||
+                   !strcmp(node_dent->d_name, ".."))
+                       continue;
+
+               log_debug(5, "searching %s", node_dent->d_name);
+               curr_rc = fn(found, data, node_dent->d_name, ruw_lock);
+               /* less than zero means it was not a match */
+               if (curr_rc > 0 && !rc)
+                       rc = curr_rc;
+       }
+
+       closedir(node_dirfd);
+       return rc;
+}
+
+static int iface_fn(void *data, node_rec_t *rec)
+{
+       struct rec_op_data *op_data = data;
+
+       return op_data->fn(op_data->data, rec);
+}
+
+static int portal_fn(int *found, void *data, char *targetname,
+                    int tpgt, char *ip, int port, bool ruw_lock)
+{
+       int rc;
+
+       if (ruw_lock) {
+               rc = idbm_lock();
+               if (rc)
+                       return rc;
+       }
+
+       rc = idbm_for_each_iface(found, data, iface_fn, targetname,
+                                tpgt, ip, port, ruw_lock);
+       if (ruw_lock)
+               idbm_unlock();
+
+       return rc;
+}
+
+static int node_fn(int *found, void *data, char *targetname, bool ruw_lock)
+{
+       return idbm_for_each_portal(found, data, portal_fn, targetname, ruw_lock);
+}
+
+int idbm_for_each_rec(int *found, void *data, idbm_iface_op_fn *fn, bool ruw_lock)
+{
+       struct rec_op_data op_data;
+
+       memset(&op_data, 0, sizeof(struct rec_op_data));
+       op_data.data = data;
+       op_data.fn = fn;
+
+       return idbm_for_each_node(found, &op_data, node_fn, ruw_lock);
+}
+
+static struct {
+       char *config_root;
+       char *config_name;
+} disc_type_to_config_vals[] = {
+       { ST_CONFIG_DIR, ST_CONFIG_NAME },
+       { ISNS_CONFIG_DIR, ISNS_CONFIG_NAME },
+};
+
+int
+idbm_discovery_read(discovery_rec_t *out_rec, int drec_type,
+                   char *addr, int port)
+{
+       recinfo_t *info;
+       char *portal;
+       int rc = 0;
+       FILE *f;
+
+       if (drec_type > 1)
+               return ISCSI_ERR_INVAL;
+
+       memset(out_rec, 0, sizeof(discovery_rec_t));
+       out_rec->iscsid_req_tmo = -1;
+
+       info = idbm_recinfo_alloc(MAX_KEYS);
+       if (!info)
+               return ISCSI_ERR_NOMEM;
+
+       portal = malloc(PATH_MAX);
+       if (!portal) {
+               rc = ISCSI_ERR_NOMEM;
+               goto free_info;
+       }
+
+       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", portal);
+
+       rc = idbm_lock();
+       if (rc)
+               goto free_info;
+
+       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", portal,
+                         strerror(errno));
+               rc = ISCSI_ERR_IDBM;
+               goto unlock;
+       }
+
+       idbm_discovery_setup_defaults(out_rec, drec_type);
+       idbm_recinfo_discovery(out_rec, info);
+       idbm_recinfo_config(info, f);
+       fclose(f);
+
+unlock:
+       idbm_unlock();
+free_info:
+       free(portal);
+       free(info);
+       return rc;
+}
+
+/*
+ * Backwards Compat:
+ * If the portal is a file then we are doing the old style default
+ * session behavior (svn pre 780).
+ */
+static FILE *idbm_open_rec_w(char *portal, char *config)
+{
+       struct stat statb;
+       FILE *f;
+       int err;
+
+       log_debug(5, "Looking for config file %s", portal);
+
+       err = stat(portal, &statb);
+       if (err)
+               goto mkdir_portal;
+
+       if (!S_ISDIR(statb.st_mode)) {
+               /*
+                * Old style portal as a file. Let's update it.
+                */
+               if (unlink(portal)) {
+                       log_error("Could not convert %s to %s/%s. "
+                                "err %d", portal, portal,
+                                 config, errno);
+                       return NULL;
+               }
+
+mkdir_portal:
+               if (mkdir(portal, 0770) != 0) {
+                       log_error("Could not make dir %s err %d",
+                                 portal, errno);
+                       return NULL;
+               }
+       }
+
+       strlcat(portal, "/", PATH_MAX);
+       strlcat(portal, config, PATH_MAX);
+       f = fopen(portal, "w");
+       if (!f)
+               log_error("Could not open %s err %d", portal, errno);
+       return f;
+}
+
+/*
+ * When the disable_lock param is true, the idbm_lock/idbm_unlock needs
+ * to be holt by the caller, this will avoid overwriting each other in
+ * case of updating(read-modify-write) the recs in parallel.
+ */
+static int idbm_rec_write(node_rec_t *rec, bool disable_lock)
+{
+       struct stat statb;
+       FILE *f;
+       char *portal;
+       int rc = 0;
+
+       portal = malloc(PATH_MAX);
+       if (!portal) {
+               log_error("Could not alloc portal");
+               return ISCSI_ERR_NOMEM;
+       }
+
+       snprintf(portal, PATH_MAX, "%s", NODE_CONFIG_DIR);
+       if (access(portal, F_OK) != 0) {
+               if (mkdir(portal, 0770) != 0) {
+                       log_error("Could not make %s: %s", portal,
+                                 strerror(errno));
+                       rc = ISCSI_ERR_IDBM;
+                       goto free_portal;
+               }
+       }
+
+       snprintf(portal, PATH_MAX, "%s/%s", NODE_CONFIG_DIR, rec->name);
+       if (access(portal, F_OK) != 0) {
+               if (mkdir(portal, 0770) != 0) {
+                       log_error("Could not make %s: %s", portal,
+                                 strerror(errno));
+                       rc = ISCSI_ERR_IDBM;
+                       goto free_portal;
+               }
+       }
+
+       snprintf(portal, PATH_MAX, "%s/%s/%s,%d", NODE_CONFIG_DIR,
+                rec->name, rec->conn[0].address, rec->conn[0].port);
+       log_debug(5, "Looking for config file %s", portal);
+
+       if (!disable_lock) {
+               rc = idbm_lock();
+               if (rc)
+                       goto free_portal;
+       }
+
+       rc = stat(portal, &statb);
+       if (rc) {
+               rc = 0;
+               /*
+                * older iscsiadm versions had you create the config then set
+                * set the tgpt. In new versions you must pass all the info in
+                * from the start
+                */
+               if (rec->tpgt == PORTAL_GROUP_TAG_UNKNOWN)
+                       /* drop down to old style portal as config */
+                       goto open_conf;
+               else
+                       goto mkdir_portal;
+       }
+
+       if (!S_ISDIR(statb.st_mode)) {
+               /*
+                * older iscsiadm versions had you create the config then set
+                * set the tgpt. In new versions you must pass all the info in
+                * from the start
+                */
+               if (rec->tpgt == PORTAL_GROUP_TAG_UNKNOWN)
+                       /* drop down to old style portal as config */
+                       goto open_conf;
+               /*
+                * Old style portal as a file, but with tpgt. Let's update it.
+                */
+               if (unlink(portal)) {
+                       log_error("Could not convert %s: %s", portal,
+                                 strerror(errno));
+                       rc = ISCSI_ERR_IDBM;
+                       goto unlock;
+               }
+       } else {
+               rc = ISCSI_ERR_INVAL;
+               goto unlock;
+       }
+
+mkdir_portal:
+       snprintf(portal, PATH_MAX, "%s/%s/%s,%d,%d", NODE_CONFIG_DIR,
+                rec->name, rec->conn[0].address, rec->conn[0].port, rec->tpgt);
+       if (stat(portal, &statb)) {
+               if (mkdir(portal, 0770) != 0) {
+                       log_error("Could not make dir %s: %s",
+                                 portal, strerror(errno));
+                       rc = ISCSI_ERR_IDBM;
+                       goto unlock;
+               }
+       }
+
+       snprintf(portal, PATH_MAX, "%s/%s/%s,%d,%d/%s", NODE_CONFIG_DIR,
+                rec->name, rec->conn[0].address, rec->conn[0].port, rec->tpgt,
+                rec->iface.name);
+open_conf:
+       f = fopen(portal, "w");
+       if (!f) {
+               log_error("Could not open %s: %s", portal, strerror(errno));
+               rc = ISCSI_ERR_IDBM;
+               goto unlock;
+       }
+
+       idbm_print(IDBM_PRINT_TYPE_NODE, rec, 1, f);
+       fclose(f);
+unlock:
+       if (!disable_lock)
+               idbm_unlock();
+free_portal:
+       free(portal);
+       return rc;
+}
+
+static int
+idbm_discovery_write(discovery_rec_t *rec)
+{
+       FILE *f;
+       char *portal;
+       int rc = 0;
+
+       if (rec->type > 1)
+               return ISCSI_ERR_INVAL;
+
+       portal = malloc(PATH_MAX);
+       if (!portal) {
+               log_error("Could not alloc portal");
+               return ISCSI_ERR_NOMEM;
+       }
+
+       rc = idbm_lock();
+       if (rc)
+               goto free_portal;
+
+       snprintf(portal, PATH_MAX, "%s",
+                disc_type_to_config_vals[rec->type].config_root);
+       if (access(portal, F_OK) != 0) {
+               if (mkdir(portal, 0770) != 0) {
+                       log_error("Could not make %s: %s", portal,
+                                 strerror(errno));
+                       rc = ISCSI_ERR_IDBM;
+                       goto unlock;
+               }
+       }
+
+       snprintf(portal, PATH_MAX, "%s/%s,%d",
+                disc_type_to_config_vals[rec->type].config_root,
+                rec->address, rec->port);
+
+       f = idbm_open_rec_w(portal,
+                           disc_type_to_config_vals[rec->type].config_name);
+       if (!f) {
+               log_error("Could not open %s: %s", portal, strerror(errno));
+               rc = ISCSI_ERR_IDBM;
+               goto unlock;
+       }
+
+       idbm_print(IDBM_PRINT_TYPE_DISCOVERY, rec, 1, f);
+       fclose(f);
+unlock:
+       idbm_unlock();
+free_portal:
+       free(portal);
+       return rc;
+}
+
+int idbm_add_discovery(discovery_rec_t *newrec)
+{
+       discovery_rec_t rec;
+
+       if (!idbm_discovery_read(&rec, newrec->type, newrec->address,
+                               newrec->port)) {
+               log_debug(7, "disc rec already exists");
+               /* fall through */
+       } else
+               log_debug(7, "adding new DB record");
+
+       return idbm_discovery_write(newrec);
+}
+
+static int setup_disc_to_node_link(char *disc_portal, node_rec_t *rec)
+{
+       struct stat statb;
+       int rc = 0;
+
+       switch (rec->disc_type) {
+       case DISCOVERY_TYPE_SENDTARGETS:
+               /* st dir setup when we create its discovery node */
+               snprintf(disc_portal, PATH_MAX, "%s/%s,%d/%s,%s,%d,%d,%s",
+                        ST_CONFIG_DIR,
+                        rec->disc_address, rec->disc_port, rec->name,
+                        rec->conn[0].address, rec->conn[0].port, rec->tpgt,
+                        rec->iface.name);
+               break;
+       case DISCOVERY_TYPE_FW:
+               if (access(FW_CONFIG_DIR, F_OK) != 0) {
+                       if (mkdir(FW_CONFIG_DIR, 0770) != 0) {
+                               log_error("Could not make %s: %s",
+                                         FW_CONFIG_DIR, strerror(errno));
+                               rc = ISCSI_ERR_IDBM;
+                       }
+               }
+
+               snprintf(disc_portal, PATH_MAX, "%s/%s,%s,%d,%d,%s",
+                        FW_CONFIG_DIR, rec->name,
+                        rec->conn[0].address, rec->conn[0].port, rec->tpgt,
+                        rec->iface.name);
+               break;
+       case DISCOVERY_TYPE_STATIC:
+               if (access(STATIC_CONFIG_DIR, F_OK) != 0) {
+                       if (mkdir(STATIC_CONFIG_DIR, 0770) != 0) {
+                               log_error("Could not make %s; %s",
+                                         STATIC_CONFIG_DIR, strerror(errno));
+                               rc = ISCSI_ERR_IDBM;
+                       }
+               }
+
+               snprintf(disc_portal, PATH_MAX, "%s/%s,%s,%d,%d,%s",
+                        STATIC_CONFIG_DIR, rec->name,
+                        rec->conn[0].address, rec->conn[0].port, rec->tpgt,
+                        rec->iface.name);
+               break;
+       case DISCOVERY_TYPE_ISNS:
+               if (access(ISNS_CONFIG_DIR, F_OK) != 0) {
+                       if (mkdir(ISNS_CONFIG_DIR, 0770) != 0) {
+                               log_error("Could not make %s: %s",
+                                         ISNS_CONFIG_DIR, strerror(errno));
+                               rc = ISCSI_ERR_IDBM;
+                       }
+               }
+
+               /*
+                * Older tools lumped all portals together in the
+                * isns config dir. In 2.0-872, the isns dir added
+                * a isns server (ddress and port) dir like sendtargets.
+                *
+                * If we found a older style link we return that so it
+                * can be removed. If this function is called for
+                * addition of a rec then the older link should have been
+                * removed and we break down below.
+                */
+               snprintf(disc_portal, PATH_MAX, "%s/%s,%s,%d,%d,%s",
+                        ISNS_CONFIG_DIR,
+                        rec->name, rec->conn[0].address,
+                        rec->conn[0].port, rec->tpgt, rec->iface.name);
+               if (!stat(disc_portal, &statb)) {
+                       log_debug(7, "using old style isns dir %s.",
+                                 disc_portal);
+                       break;
+               }
+
+               snprintf(disc_portal, PATH_MAX, "%s/%s,%d",
+                        ISNS_CONFIG_DIR, rec->disc_address, rec->disc_port);
+               if (!stat(disc_portal, &statb) && S_ISDIR(statb.st_mode)) {
+                       /*
+                        * if there is a dir for this isns server then
+                        * assume we are using the new style links
+                        */
+                       snprintf(disc_portal, PATH_MAX,
+                                "%s/%s,%d/%s,%s,%d,%d,%s",
+                                ISNS_CONFIG_DIR, rec->disc_address,
+                                rec->disc_port, rec->name,
+                                rec->conn[0].address, rec->conn[0].port,
+                                rec->tpgt, rec->iface.name);
+                       break;
+               }
+
+               /* adding a older link */
+               snprintf(disc_portal, PATH_MAX, "%s/%s,%s,%d,%d,%s",
+                        ISNS_CONFIG_DIR, rec->name, rec->conn[0].address,
+                        rec->conn[0].port, rec->tpgt, rec->iface.name);
+               break;
+       case DISCOVERY_TYPE_SLP:
+       default:
+               rc = ISCSI_ERR_INVAL;
+       }
+
+       return rc;
+}
+
+int idbm_add_node(node_rec_t *newrec, discovery_rec_t *drec, int overwrite)
+{
+       node_rec_t rec;
+       char *node_portal = NULL, *disc_portal;
+       int rc;
+
+       rc = idbm_lock();
+       if (rc)
+               return rc;
+
+       if (!idbm_rec_read(&rec, newrec->name, newrec->tpgt,
+                          newrec->conn[0].address, newrec->conn[0].port,
+                          &newrec->iface, true)) {
+               if (!overwrite) {
+                       rc = 0;
+                       goto unlock;
+               }
+
+               rc = idbm_delete_node(&rec);
+               if (rc)
+                       goto unlock;
+
+               if (drec->type == DISCOVERY_TYPE_FW) {
+                       log_debug(8, "setting firmware node 'startup' to 'onboot'");
+                       newrec->startup = ISCSI_STARTUP_ONBOOT;
+                       newrec->conn[0].startup = ISCSI_STARTUP_ONBOOT;
+               }
+               log_debug(7, "overwriting existing record");
+       } else
+               log_debug(7, "adding new DB record");
+
+       if (drec) {
+               newrec->disc_type = drec->type;
+               newrec->disc_port = drec->port;
+               strcpy(newrec->disc_address, drec->address);
+       }
+
+       rc = idbm_rec_write(newrec, true);
+       /*
+        * if a old app passed in a bogus tpgt then we do not create links
+        * since it will set a different tpgt in another iscsiadm call
+        */
+       if (rc || !drec || newrec->tpgt == PORTAL_GROUP_TAG_UNKNOWN)
+               goto unlock;
+
+       node_portal = calloc(2, PATH_MAX);
+       if (!node_portal) {
+               rc = ISCSI_ERR_NOMEM;
+               goto unlock;
+       }
+
+       disc_portal = node_portal + PATH_MAX;
+       snprintf(node_portal, PATH_MAX, "%s/%s/%s,%d,%d", NODE_CONFIG_DIR,
+                newrec->name, newrec->conn[0].address, newrec->conn[0].port,
+                newrec->tpgt);
+       rc = setup_disc_to_node_link(disc_portal, newrec);
+       if (rc)
+               goto unlock;
+
+       log_debug(7, "node addition making link from %s to %s", node_portal,
+                disc_portal);
+
+       if (symlink(node_portal, disc_portal)) {
+               if (errno == EEXIST)
+                       log_debug(7, "link from %s to %s exists", node_portal,
+                                 disc_portal);
+               else {
+                       rc = ISCSI_ERR_IDBM;
+                       log_error("Could not make link from disc source %s to "
+                                "node %s: %s", disc_portal, node_portal,
+                                strerror(errno));
+               }
+       }
+unlock:
+       idbm_unlock();
+       free(node_portal);
+       return rc;
+}
+
+static int idbm_bind_iface_to_nodes(idbm_disc_nodes_fn *disc_node_fn,
+                                   void *data, struct iface_rec *iface,
+                                   struct list_head *bound_recs)
+{
+       struct node_rec *rec, *tmp;
+       struct list_head new_recs;
+       int rc;
+
+       INIT_LIST_HEAD(&new_recs);
+       rc = disc_node_fn(data, iface, &new_recs);
+       if (rc)
+               return rc;
+
+       list_for_each_entry_safe(rec, tmp, &new_recs, list) {
+               list_del_init(&rec->list);
+               list_add_tail(&rec->list, bound_recs);
+               iface_copy(&rec->iface, iface);
+       }
+       return 0;
+}
+
+static int
+discovery_error_fatal(int err)
+{
+       switch (err) {
+       /* No error */
+       case ISCSI_SUCCESS:
+       /* Transport errors or timeouts are not fatal */
+       case ISCSI_ERR_TRANS:
+       case ISCSI_ERR_TRANS_TIMEOUT:
+               return 0;
+       }
+       return 1;
+}
+
+int idbm_bind_ifaces_to_nodes(idbm_disc_nodes_fn *disc_node_fn,
+                             void *data, struct list_head *ifaces,
+                             struct list_head *bound_recs)
+{
+       struct list_head def_ifaces;
+       struct node_rec *rec, *tmp_rec;
+       struct iface_rec *iface, *tmp_iface;
+       struct iscsi_transport *t;
+       int rc = 0, found = 0;
+
+       INIT_LIST_HEAD(&def_ifaces);
+
+       if (!ifaces || list_empty(ifaces)) {
+               iface_link_ifaces(&def_ifaces);
+
+               list_for_each_entry_safe(iface, tmp_iface, &def_ifaces, list) {
+                       list_del(&iface->list);
+                       t = iscsi_sysfs_get_transport_by_name(iface->transport_name);
+                       /*
+                        * only auto bind to software iscsi if it is
+                        * not the default iface (that is handled below)
+                        */
+                       if (!t || strcmp(t->name, DEFAULT_TRANSPORT) ||
+                           !strcmp(iface->name, DEFAULT_IFACENAME)) {
+                               free(iface);
+                               continue;
+                       }
+
+                       rc = idbm_bind_iface_to_nodes(disc_node_fn, data, iface,
+                                                     bound_recs);
+                       free(iface);
+                       if (discovery_error_fatal(rc))
+                               goto fail;
+                       found = 1;
+               }
+
+               /* create default iface with old/default behavior */
+               if (!found) {
+                       struct iface_rec def_iface;
+
+                       memset(&def_iface, 0, sizeof(struct iface_rec));
+                       iface_setup_defaults(&def_iface);
+                       return idbm_bind_iface_to_nodes(disc_node_fn, data,
+                                                       &def_iface, bound_recs);
+               }
+       } else {
+               list_for_each_entry(iface, ifaces, list) {
+                       if (strcmp(iface->name, DEFAULT_IFACENAME) &&
+                           !iface_is_valid(iface)) {
+                               log_error("iface %s is not valid. Will not "
+                                         "bind node to it. Iface settings "
+                                         iface_fmt, iface->name,
+                                         iface_str(iface));
+                               continue;
+                       }
+
+                       rc = idbm_bind_iface_to_nodes(disc_node_fn, data, iface,
+                                                     bound_recs);
+                       if (discovery_error_fatal(rc))
+                               goto fail;
+               }
+       }
+       return 0;
+
+fail:
+       list_for_each_entry_safe(iface, tmp_iface, &def_ifaces, list) {
+               list_del(&iface->list);
+               free(iface);
+       }
+
+       list_for_each_entry_safe(rec, tmp_rec, bound_recs, list) {
+               list_del(&rec->list);
+               free(rec);
+       }
+       return rc;
+}
+
+static void idbm_rm_disc_node_links(char *disc_dir)
+{
+       char *target = NULL, *tpgt = NULL, *port = NULL;
+       char *address = NULL, *iface_id = NULL;
+       DIR *disc_dirfd;
+       struct dirent *disc_dent;
+       node_rec_t *rec;
+
+       rec = calloc(1, sizeof(*rec));
+       if (!rec)
+               return;
+
+       disc_dirfd = opendir(disc_dir);
+       if (!disc_dirfd)
+               goto free_rec;
+
+       /* rm links to nodes */
+       while ((disc_dent = readdir(disc_dirfd))) {
+               if (!strcmp(disc_dent->d_name, ".") ||
+                   !strcmp(disc_dent->d_name, ".."))
+                       continue;
+
+
+               if (get_params_from_disc_link(disc_dent->d_name, &target, &tpgt,
+                                             &address, &port, &iface_id)) {
+                       log_error("Improperly formed disc to node link");
+                       continue;
+               }
+
+               log_debug(5, "disc removal removing link %s %s %s %s",
+                         target, address, port, iface_id);
+
+               memset(rec, 0, sizeof(*rec));
+               strlcpy(rec->name, target, TARGET_NAME_MAXLEN);
+               rec->tpgt = atoi(tpgt);
+               rec->conn[0].port = atoi(port);
+               strlcpy(rec->conn[0].address, address, NI_MAXHOST);
+               strlcpy(rec->iface.name, iface_id, ISCSI_MAX_IFACE_LEN);
+
+               if (idbm_delete_node(rec))
+                       log_error("Could not delete node %s/%s/%s,%s/%s",
+                                 NODE_CONFIG_DIR, target, address, port,
+                                 iface_id);
+       }
+
+       closedir(disc_dirfd);
+free_rec:
+       free(rec);
+}
+
+int idbm_delete_discovery(discovery_rec_t *drec)
+{
+       char *portal;
+       struct stat statb;
+       int rc = 0;
+
+       portal = calloc(1, PATH_MAX);
+       if (!portal)
+               return ISCSI_ERR_NOMEM;
+
+       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", portal);
+
+       if (stat(portal, &statb)) {
+               log_debug(5, "Could not stat %s to delete disc err %d",
+                         portal, errno);
+               goto free_portal;
+       }
+
+       if (S_ISDIR(statb.st_mode)) {
+               strlcat(portal, "/", PATH_MAX);
+               strlcat(portal,
+                       disc_type_to_config_vals[drec->type].config_name,
+                       PATH_MAX);
+       }
+
+       if (unlink(portal))
+               log_debug(5, "Could not remove %s err %d", portal, errno);
+
+       memset(portal, 0, PATH_MAX);
+       snprintf(portal, PATH_MAX, "%s/%s,%d",
+                disc_type_to_config_vals[drec->type].config_root,
+                drec->address, drec->port);
+       idbm_rm_disc_node_links(portal);
+
+       /* rm portal dir */
+       if (S_ISDIR(statb.st_mode)) {
+               memset(portal, 0, PATH_MAX);
+               snprintf(portal, PATH_MAX, "%s/%s,%d",
+                        disc_type_to_config_vals[drec->type].config_root,
+                        drec->address, drec->port);
+               rmdir(portal);
+       }
+
+free_portal:
+       free(portal);
+       return rc;
+}
+
+/*
+ * Backwards Compat or SLP:
+ * if there is no link then this is pre svn 780 version where
+ * we did not link the disc source and node
+ */
+static int idbm_remove_disc_to_node_link(node_rec_t *rec,
+                                        char *portal)
+{
+       int rc = 0;
+       struct stat statb;
+       node_rec_t *tmprec;
+
+       tmprec = malloc(sizeof(*tmprec));
+       if (!tmprec)
+               return ISCSI_ERR_NOMEM;
+
+       memset(portal, 0, PATH_MAX);
+       snprintf(portal, PATH_MAX, "%s/%s/%s,%d,%d/%s", NODE_CONFIG_DIR,
+                rec->name, rec->conn[0].address, rec->conn[0].port, rec->tpgt,
+                rec->iface.name);
+
+       rc = __idbm_rec_read(tmprec, portal, false);
+       if (rc) {
+               /* old style recs will not have tpgt or a link so skip */
+               rc = 0;
+               goto done;
+       }
+
+       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);
+       rc = setup_disc_to_node_link(portal, tmprec);
+       if (rc)
+               goto done;
+
+       rc = idbm_lock();
+       if (rc)
+               goto done;
+
+       if (!stat(portal, &statb)) {
+               if (unlink(portal)) {
+                       log_error("Could not remove link %s: %s",
+                                 portal, strerror(errno));
+                       rc = ISCSI_ERR_IDBM;
+               } else
+                       log_debug(7, "rmd %s", portal);
+       } else
+               log_debug(7, "Could not stat %s", portal);
+       idbm_unlock();
+
+done:
+       free(tmprec);
+       return rc;
+}
+
+static int st_disc_filter(const struct dirent *dir)
+{
+       return strcmp(dir->d_name, ".") && strcmp(dir->d_name, "..") &&
+               strcmp(dir->d_name, ST_CONFIG_NAME);
+}
+
+int idbm_delete_node(node_rec_t *rec)
+{
+       struct stat statb;
+       char *portal;
+       int rc = 0, dir_rm_rc = 0;
+
+       portal = calloc(1, PATH_MAX);
+       if (!portal)
+               return ISCSI_ERR_NOMEM;
+
+       rc = idbm_remove_disc_to_node_link(rec, portal);
+       if (rc)
+               goto free_portal;
+
+       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",
+                 portal, rec->iface.name);
+
+       rc = idbm_lock();
+       if (rc)
+               goto free_portal;
+
+       if (!stat(portal, &statb))
+               goto rm_conf;
+
+       snprintf(portal, PATH_MAX, "%s/%s/%s,%d,%d/%s", NODE_CONFIG_DIR,
+                rec->name, rec->conn[0].address, rec->conn[0].port,
+                rec->tpgt, rec->iface.name);
+       log_debug(5, "Removing config file %s", portal);
+
+       if (!stat(portal, &statb))
+               goto rm_conf;
+
+       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", portal, strerror(errno));
+               rc = ISCSI_ERR_IDBM;
+               goto unlock;
+       }
+
+       memset(portal, 0, PATH_MAX);
+       snprintf(portal, PATH_MAX, "%s/%s/%s,%d,%d", NODE_CONFIG_DIR,
+                rec->name, rec->conn[0].address, rec->conn[0].port,
+                rec->tpgt);
+       if (!stat(portal, &statb)) {
+               struct dirent **namelist;
+               int n, i;
+
+               memset(portal, 0, PATH_MAX);
+               snprintf(portal, PATH_MAX, "%s/%s/%s,%d,%d", NODE_CONFIG_DIR,
+                        rec->name, rec->conn[0].address, rec->conn[0].port,
+                        rec->tpgt);
+               n = scandir(portal, &namelist, st_disc_filter, alphasort);
+               if (n < 0)
+                       goto free_portal;
+               if (n == 0)
+                       dir_rm_rc = rmdir(portal);
+
+               for (i = 0; i < n; i++)
+                       free(namelist[i]);
+               free(namelist);
+       }
+       /* rm target dir */
+       if (!dir_rm_rc) {
+               memset(portal, 0, PATH_MAX);
+               snprintf(portal, PATH_MAX, "%s/%s", NODE_CONFIG_DIR, rec->name);
+               rmdir(portal);
+       }
+unlock:
+       idbm_unlock();
+free_portal:
+       free(portal);
+       return rc;
+}
+
+void
+idbm_sendtargets_defaults(struct iscsi_sendtargets_config *cfg)
+{
+       idbm_sync_config();
+       memcpy(cfg, &db->drec_st.u.sendtargets,
+              sizeof(struct iscsi_sendtargets_config));
+}
+
+void
+idbm_isns_defaults(struct iscsi_isns_config *cfg)
+{
+       idbm_sync_config();
+       memcpy(cfg, &db->drec_isns.u.isns,
+              sizeof(struct iscsi_isns_config));
+}
+
+void
+idbm_slp_defaults(struct iscsi_slp_config *cfg)
+{
+       memcpy(cfg, &db->drec_slp.u.slp,
+              sizeof(struct iscsi_slp_config));
+}
+
+int
+idbm_session_autoscan(struct iscsi_session *session)
+{
+       if (session)
+               return session->nrec.session.scan;
+       return db->nrec.session.scan;
+}
+
+struct user_param *idbm_alloc_user_param(char *name, char *value)
+{
+       struct user_param *param;
+
+       param = calloc(1, sizeof(*param));
+       if (!param)
+               return NULL;
+
+       INIT_LIST_HEAD(&param->list);
+
+       param->name = strdup(name);
+       if (!param->name)
+               goto free_param;
+
+       param->value = strdup(value);
+       if (!param->value)
+               goto free_name;
+
+       return param;
+
+free_name:
+       free(param->name);
+free_param:
+       free(param);
+       return NULL;
+}
+
+void idbm_free_user_param(struct user_param *param)
+{
+       if (!param)
+               return;
+
+       if (param->name)
+               free(param->name);
+
+       if (param->value)
+               free(param->value);
+
+       free(param);
+}
+
+int idbm_node_set_rec_from_param(struct list_head *params, node_rec_t *rec,
+                                int verify)
+{
+       struct user_param *param;
+       recinfo_t *info;
+       int rc = 0;
+
+       if (list_empty(params))
+               return 0;
+
+       info = idbm_recinfo_alloc(MAX_KEYS);
+       if (!info)
+               return ISCSI_ERR_NOMEM;
+
+       idbm_recinfo_node(rec, info);
+
+       if (verify) {
+               list_for_each_entry(param, params, list) {
+                       rc = idbm_verify_param(info, param->name);
+                       if (rc)
+                               goto free_info;
+               }
+       }
+
+       list_for_each_entry(param, params, list) {
+               rc = idbm_rec_update_param(info, param->name, param->value, 0);
+               if (rc) {
+                       if (rc == ISCSI_ERR_INVAL)
+                               log_error("Unknown parameter %s.", param->name);
+                       goto free_info;
+               }
+       }
+
+free_info:
+       free(info);
+       return rc;
+}
+
+int idbm_node_set_param(void *data, node_rec_t *rec)
+{
+       int rc;
+
+       rc = idbm_node_set_rec_from_param(data, rec, 1);
+       if (rc)
+               return rc;
+
+       return idbm_rec_write(rec, true);
+}
+
+int idbm_discovery_set_param(void *data, discovery_rec_t *rec)
+{
+       struct list_head *params = data;
+       struct user_param *param;
+       recinfo_t *info;
+       int rc = 0;
+
+       info = idbm_recinfo_alloc(MAX_KEYS);
+       if (!info)
+               return ISCSI_ERR_NOMEM;
+
+       idbm_recinfo_discovery((discovery_rec_t *)rec, info);
+
+       list_for_each_entry(param, params, list) {
+               rc = idbm_verify_param(info, param->name);
+               if (rc)
+                       goto free_info;
+       }
+
+       list_for_each_entry(param, params, list) {
+               rc = idbm_rec_update_param(info, param->name, param->value, 0);
+               if (rc)
+                       goto free_info;
+       }
+
+       rc = idbm_discovery_write((discovery_rec_t *)rec);
+       if (rc)
+               goto free_info;
+
+free_info:
+       free(info);
+       return rc;
+}
+
+int idbm_init(idbm_get_config_file_fn *fn)
+{
+       /* make sure root db dir is there */
+       if (access(ISCSI_DB_ROOT, F_OK) != 0) {
+               if (mkdir(ISCSI_DB_ROOT, 0770) != 0) {
+                       log_error("Could not make %s %d", ISCSI_DB_ROOT,
+                                  errno);
+                       return errno;
+               }
+       }
+
+       db = malloc(sizeof(idbm_t));
+       if (!db) {
+               log_error("out of memory on idbm allocation");
+               return ISCSI_ERR_NOMEM;
+       }
+       memset(db, 0, sizeof(idbm_t));
+       db->get_config_file = fn;
+       return 0;
+}
+
+void idbm_terminate(void)
+{
+       if (db)
+               free(db);
+}
+
+static bool idbm_populate_rec(struct node_rec *rec,
+                             char *targetname, int tpgt, char *ip,
+                             int port, struct iface_rec *iface,
+                             int verbose)
+{
+       if (targetname)
+               strlcpy(rec->name, targetname, TARGET_NAME_MAXLEN);
+       rec->tpgt = tpgt;
+       rec->conn[0].port = port;
+       if (ip)
+               strlcpy(rec->conn[0].address, ip, NI_MAXHOST);
+       memset(&rec->iface, 0, sizeof(struct iface_rec));
+       if (iface) {
+               iface_copy(&rec->iface, iface);
+               if (strlen(iface->name)) {
+                       if (iface_conf_read(&rec->iface)) {
+                               if (verbose)
+                                       log_error("Could not read iface info "
+                                                 "for %s.", iface->name);
+                               return false;
+                       }
+               }
+       }
+       return true;
+}
+
+/**
+ * idbm_create_rec - allocate and setup a node record
+ * @targetname: target name
+ * @tgpt: target portal group
+ * @ip: ip address of portal
+ * @port: port of portal
+ * @iface: iscsi iface info
+ * @verbose: flag indicating whether to log ifaces setup errors
+ *
+ * The iface only needs to have the name set. This function will
+ * read in the other values.
+ */
+struct node_rec *idbm_create_rec(char *targetname, int tpgt, char *ip,
+                                int port, struct iface_rec *iface,
+                                int verbose)
+{
+       struct node_rec *rec;
+
+       rec = calloc(1, sizeof(*rec));
+       if (!rec) {
+               log_error("Could not not allocate memory to create node "
+                         "record.");
+               return NULL;
+       }
+
+       idbm_node_setup_defaults(rec);
+
+       if (!idbm_populate_rec(rec, targetname, tpgt, ip, port, iface, verbose)) {
+               goto free_rec;
+       }
+       return rec;
+free_rec:
+       free(rec);
+       return NULL;
+}
+
+struct node_rec *idbm_create_rec_from_boot_context(struct boot_context *context)
+{
+       node_rec_t *rec;
+
+       rec = malloc(sizeof(*rec));
+       if (!rec) {
+               log_error("Could not not allocate memory to create node "
+                         "record.");
+               return NULL;
+       }
+
+       idbm_node_setup_from_conf(rec);
+
+       /* tpgt hard coded to 1 ??? */
+       if (!idbm_populate_rec(rec, context->targetname, 1,
+                              context->target_ipaddr, context->target_port,
+                              NULL, 1)) {
+               log_error("Could not setup rec for fw discovery login.");
+               free(rec);
+               return NULL;
+       }
+
+       iface_setup_defaults(&rec->iface);
+       strlcpy(rec->session.auth.username, context->chap_name,
+               sizeof(context->chap_name));
+       strlcpy((char *)rec->session.auth.password, context->chap_password,
+               sizeof(context->chap_password));
+       strlcpy(rec->session.auth.username_in, context->chap_name_in,
+               sizeof(context->chap_name_in));
+       strlcpy((char *)rec->session.auth.password_in,
+               context->chap_password_in,
+               sizeof(context->chap_password_in));
+       rec->session.auth.password_length =
+                               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);
+
+       return rec;
+}
+
+void idbm_node_setup_defaults(node_rec_t *rec)
+{
+       int i;
+
+       memset(rec, 0, sizeof(node_rec_t));
+
+       INIT_LIST_HEAD(&rec->list);
+
+       rec->tpgt = PORTAL_GROUP_TAG_UNKNOWN;
+       rec->disc_type = DISCOVERY_TYPE_STATIC;
+       rec->leading_login = 0;
+       rec->session.cmds_max = CMDS_MAX;
+       rec->session.xmit_thread_priority = XMIT_THREAD_PRIORITY;
+       rec->session.initial_cmdsn = 0;
+       rec->session.queue_depth = QUEUE_DEPTH;
+       rec->session.nr_sessions = 1;
+       rec->session.initial_login_retry_max = DEF_INITIAL_LOGIN_RETRIES_MAX;
+       rec->session.reopen_max = DEF_SESSION_REOPEN_MAX;
+       rec->session.auth.authmethod = 0;
+       /* TYPE_INT_LIST fields should be initialized to ~0 to indicate unset values */
+       memset(rec->session.auth.chap_algs, ~0, sizeof(rec->session.auth.chap_algs));
+       rec->session.auth.chap_algs[0] = AUTH_CHAP_ALG_MD5;
+       rec->session.auth.password_length = 0;
+       rec->session.auth.password_in_length = 0;
+       rec->session.err_timeo.abort_timeout = DEF_ABORT_TIMEO;
+       rec->session.err_timeo.lu_reset_timeout = DEF_LU_RESET_TIMEO;
+       rec->session.err_timeo.tgt_reset_timeout = DEF_TGT_RESET_TIMEO;
+       rec->session.err_timeo.host_reset_timeout = DEF_HOST_RESET_TIMEO;
+       rec->session.timeo.replacement_timeout = DEF_REPLACEMENT_TIMEO;
+       rec->session.info = NULL;
+       rec->session.sid = 0;
+       rec->session.multiple = 0;
+       rec->session.scan = DEF_INITIAL_SCAN;
+       idbm_setup_session_defaults(&rec->session.iscsi);
+
+       for (i=0; i<ISCSI_CONN_MAX; i++) {
+               rec->conn[i].startup = ISCSI_STARTUP_MANUAL;
+               rec->conn[i].port = ISCSI_LISTEN_PORT;
+               rec->conn[i].tcp.window_size = TCP_WINDOW_SIZE;
+               rec->conn[i].tcp.type_of_service = 0;
+               rec->conn[i].timeo.login_timeout= DEF_LOGIN_TIMEO;
+               rec->conn[i].timeo.logout_timeout= DEF_LOGOUT_TIMEO;
+               rec->conn[i].timeo.auth_timeout = 45;
+
+               rec->conn[i].timeo.noop_out_interval = DEF_NOOP_OUT_INTERVAL;
+               rec->conn[i].timeo.noop_out_timeout = DEF_NOOP_OUT_TIMEO;
+
+               idbm_setup_conn_defaults(&rec->conn[i].iscsi);
+       }
+
+       iface_setup_defaults(&rec->iface);
+}
+
+struct node_rec *
+idbm_find_rec_in_list(struct list_head *rec_list, char *targetname, char *addr,
+                     int port, struct iface_rec *iface)
+{
+       struct node_rec *rec;
+
+       list_for_each_entry(rec, rec_list, list) {
+               if (__iscsi_match_session(rec, targetname, addr, port, iface,
+                                         MATCH_ANY_SID))
+                       return rec;
+       }
+
+       return NULL;
+}
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/idbm.h b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/idbm.h
new file mode 100644 (file)
index 0000000..0fde800
--- /dev/null
@@ -0,0 +1,198 @@
+/*
+ * iSCSI Discovery Database Library
+ *
+ * Copyright (C) 2004 Dmitry Yusupov, Alex Aizman
+ * Copyright (C) 2006 Mike Christie
+ * Copyright (C) 2006 Red Hat, Inc. All rights reserved.
+ * 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 IDBM_H
+#define IDBM_H
+
+#include <stdio.h>
+#include <stdbool.h>
+#include <sys/types.h>
+#include "initiator.h"
+#include "config.h"
+#include "list.h"
+#include "flashnode.h"
+
+#define NODE_CONFIG_DIR                ISCSI_DB_ROOT"/nodes"
+#define SLP_CONFIG_DIR         ISCSI_DB_ROOT"/slp"
+#define ISNS_CONFIG_DIR                ISCSI_DB_ROOT"/isns"
+#define STATIC_CONFIG_DIR      ISCSI_DB_ROOT"/static"
+#define FW_CONFIG_DIR          ISCSI_DB_ROOT"/fw"
+#define ST_CONFIG_DIR          ISCSI_DB_ROOT"/send_targets"
+
+#define ST_CONFIG_NAME         "st_config"
+#define ISNS_CONFIG_NAME       "isns_config"
+
+#define TYPE_INT       0
+#define TYPE_INT_O     1
+#define TYPE_STR       2
+#define TYPE_UINT8     3
+#define TYPE_UINT16    4
+#define TYPE_UINT32    5
+#define TYPE_INT_LIST  6
+
+#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. */
+#define OPTS_MAXVAL    8
+typedef struct recinfo {
+       int             type;
+       char            name[NAME_MAXVAL];
+       char            value[VALUE_MAXVAL];
+       void            *data;
+       int             data_len;
+       int             visible;
+       char*           opts[OPTS_MAXVAL];
+       int             numopts;
+       /*
+        * bool indicating if we can change it or not.
+        * TODO: make it a enum that can indicate wheter it also requires
+        * a relogin to pick up if a session is running.
+        */
+       int             can_modify;
+} recinfo_t;
+
+typedef char *(idbm_get_config_file_fn)(void);
+
+typedef struct idbm {
+       void            *discdb;
+       void            *nodedb;
+       char            *configfile;
+       int             refs;
+       idbm_get_config_file_fn *get_config_file;
+       node_rec_t      nrec;
+       recinfo_t       ninfo[MAX_KEYS];
+       discovery_rec_t drec_st;
+       recinfo_t       dinfo_st[MAX_KEYS];
+       discovery_rec_t drec_slp;
+       recinfo_t       dinfo_slp[MAX_KEYS];
+       discovery_rec_t drec_isns;
+       recinfo_t       dinfo_isns[MAX_KEYS];
+} idbm_t;
+
+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);
+typedef int (idbm_portal_op_fn)(int *found,  void *data, char *targetname,
+                               int tpgt, char *ip, int port, bool ruw_lock);
+typedef int (idbm_node_op_fn)(int *found, void *data,
+                             char *targetname, bool ruw_lock);
+
+struct rec_op_data {
+       void *data;
+       node_rec_t *match_rec;
+       idbm_iface_op_fn *fn;
+};
+extern int idbm_for_each_portal(int *found, void *data, idbm_portal_op_fn *fn,
+                               char *targetname, bool ruw_lock);
+extern int idbm_for_each_node(int *found, void *data,
+                             idbm_node_op_fn *fn, bool ruw_lock);
+extern int idbm_for_each_rec(int *found, void *data,
+                            idbm_iface_op_fn *fn, bool ruw_lock);
+
+
+typedef int (idbm_drec_op_fn)(void *data, discovery_rec_t *drec);
+extern int idbm_for_each_st_drec(void *data, idbm_drec_op_fn *fn);
+extern int idbm_for_each_isns_drec(void *data, idbm_drec_op_fn *fn);
+
+extern int idbm_init(idbm_get_config_file_fn *fn);
+
+extern void idbm_node_setup_from_conf(node_rec_t *rec);
+extern void idbm_terminate(void);
+extern int idbm_print_node_info(void *data, node_rec_t *rec);
+extern int idbm_print_node_flat(void *data, node_rec_t *rec);
+extern int idbm_print_node_tree(struct node_rec *last_rec, struct node_rec *rec,
+                               char *prefix);
+extern int idbm_print_node_and_iface_tree(void *data, node_rec_t *rec);
+extern int idbm_print_discovery_info(discovery_rec_t *rec, int show);
+extern int idbm_print_all_discovery(int info_level);
+extern int idbm_delete_discovery(discovery_rec_t *rec);
+extern void idbm_node_setup_defaults(node_rec_t *rec);
+extern int idbm_delete_node(node_rec_t *rec);
+extern int idbm_add_node(node_rec_t *newrec, discovery_rec_t *drec,
+                        int overwrite);
+struct list_head;
+typedef int (idbm_disc_nodes_fn)(void *data, struct iface_rec *iface,
+                                struct list_head *recs);
+extern int idbm_bind_ifaces_to_nodes(idbm_disc_nodes_fn *disc_node_fn,
+                                    void *data, struct list_head *ifaces,
+                                    struct list_head *bound_recs);
+extern int idbm_add_discovery(discovery_rec_t *newrec);
+extern void idbm_sendtargets_defaults(struct iscsi_sendtargets_config *cfg);
+extern void idbm_isns_defaults(struct iscsi_isns_config *cfg);
+extern void idbm_slp_defaults(struct iscsi_slp_config *cfg);
+extern int idbm_session_autoscan(struct iscsi_session *session);
+extern int idbm_discovery_read(discovery_rec_t *rec, int type, char *addr,
+                               int port);
+extern int idbm_rec_read(node_rec_t *out_rec, char *target_name,
+                        int tpgt, char *addr, int port,
+                        struct iface_rec *iface, bool disable_lock);
+extern int idbm_node_set_rec_from_param(struct list_head *params,
+                                       node_rec_t *rec, int verify);
+extern int idbm_node_set_param(void *data, node_rec_t *rec);
+extern int idbm_discovery_set_param(void *data, discovery_rec_t *rec);
+struct user_param *idbm_alloc_user_param(char *name, char *value);
+void idbm_free_user_param(struct user_param *param);
+extern void idbm_node_setup_defaults(node_rec_t *rec);
+extern struct node_rec *idbm_find_rec_in_list(struct list_head *rec_list,
+                                             char *targetname, char *addr,
+                                             int port, struct iface_rec *iface);
+
+/* lower level idbm functions for use by iface.c */
+extern void idbm_recinfo_config(recinfo_t *info, FILE *f);
+extern void idbm_recinfo_iface(struct iface_rec *r, recinfo_t *ri);
+extern int idbm_lock(void);
+extern void idbm_unlock(void);
+extern recinfo_t *idbm_recinfo_alloc(int max_keys);
+extern int idbm_verify_param(recinfo_t *info, char *name);
+extern int idbm_rec_update_param(recinfo_t *info, char *name, char *value,
+                                int line_number);
+extern void idbm_recinfo_node(node_rec_t *r, recinfo_t *ri);
+
+enum {
+       IDBM_PRINT_TYPE_DISCOVERY,
+       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);
+
+struct boot_context;
+extern struct node_rec *idbm_create_rec(char *targetname, int tpgt,
+                                       char *ip, int port,
+                                       struct iface_rec *iface,
+                                       int verbose);
+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/pkgs/open-iscsi/open-iscsi-2.1.8/usr/idbm_fields.h b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/idbm_fields.h
new file mode 100644 (file)
index 0000000..4a967fc
--- /dev/null
@@ -0,0 +1,245 @@
+#ifndef IDBM_FIELDS_H
+#define IDBM_FIELDS_H
+
+#include "version.h"
+
+#define ISCSI_BEGIN_REC        "# BEGIN RECORD "ISCSI_VERSION_STR
+#define ISCSI_END_REC  "# END RECORD"
+
+/* node fields */
+#define NODE_NAME      "node.name"
+#define NODE_TPGT      "node.tpgt"
+#define NODE_STARTUP   "node.startup"
+#define NODE_LEADING_LOGIN "node.leading_login"
+#define NODE_DISC_ADDR "node.discovery_address"
+#define NODE_DISC_PORT "node.discovery_port"
+#define NODE_DISC_TYPE "node.discovery_type"
+#define NODE_BOOT_LUN  "node.boot_lun"
+
+/* session fields */
+#define SESSION_INIT_CMDSN     "node.session.initial_cmdsn"
+#define SESSION_INIT_LOGIN_RETRY "node.session.initial_login_retry_max"
+#define SESSION_CMDS_MAX       "node.session.cmds_max"
+#define SESSION_XMIT_THREAD_PRIORITY "node.session.xmit_thread_priority"
+#define SESSION_QDEPTH         "node.session.queue_depth"
+#define SESSION_NR_SESSIONS    "node.session.nr_sessions"
+#define SESSION_AUTH_METHOD    "node.session.auth.authmethod"
+#define SESSION_USERNAME       "node.session.auth.username"
+#define SESSION_PASSWORD       "node.session.auth.password"
+#define SESSION_PASSWORD_LEN   "node.session.auth.password_length"
+#define SESSION_USERNAME_IN    "node.session.auth.username_in"
+#define SESSION_PASSWORD_IN    "node.session.auth.password_in"
+#define SESSION_PASSWORD_IN_LEN        "node.session.auth.password_in_length"
+#define SESSION_CHAP_ALGS      "node.session.auth.chap_algs"
+#define SESSION_REPLACEMENT_TMO        "node.session.timeo.replacement_timeout"
+#define SESSION_ABORT_TMO      "node.session.err_timeo.abort_timeout"
+#define SESSION_LU_RESET_TMO   "node.session.err_timeo.lu_reset_timeout"
+#define SESSION_TGT_RESET_TMO  "node.session.err_timeo.tgt_reset_timeout"
+#define SESSION_HOST_RESET_TMO "node.session.err_timeo.host_reset_timeout"
+#define SESSION_FAST_ABORT     "node.session.iscsi.FastAbort"
+#define SESSION_INITIAL_R2T    "node.session.iscsi.InitialR2T"
+#define SESSION_IMM_DATA       "node.session.iscsi.ImmediateData"
+#define SESSION_FIRST_BURST    "node.session.iscsi.FirstBurstLength"
+#define SESSION_MAX_BURST      "node.session.iscsi.MaxBurstLength"
+#define SESSION_DEF_TIME2RETAIN        "node.session.iscsi.DefaultTime2Retain"
+#define SESSION_DEF_TIME2WAIT  "node.session.iscsi.DefaultTime2Wait"
+#define SESSION_MAX_CONNS      "node.session.iscsi.MaxConnections"
+#define SESSION_MAX_R2T                "node.session.iscsi.MaxOutstandingR2T"
+#define SESSION_ERL            "node.session.iscsi.ERL"
+#define SESSION_SCAN           "node.session.scan"
+#define SESSION_REOPEN_MAX     "node.session.reopen_max"
+
+/* connections fields */
+#define CONN_ADDR              "node.conn[%d].address"
+#define CONN_PORT              "node.conn[%d].port"
+#define CONN_STARTUP           "node.conn[%d].startup"
+#define CONN_WINDOW_SIZE       "node.conn[%d].tcp.window_size"
+#define CONN_SERVICE_TYPE      "node.conn[%d].tcp.type_of_service"
+#define CONN_LOGOUT_TMO                "node.conn[%d].timeo.logout_timeout"
+#define CONN_LOGIN_TMO         "node.conn[%d].timeo.login_timeout"
+#define CONN_AUTH_TMO          "node.conn[%d].timeo.auth_timeout"
+#define CONN_NOP_INT           "node.conn[%d].timeo.noop_out_interval"
+#define CONN_NOP_TMO           "node.conn[%d].timeo.noop_out_timeout"
+#define CONN_MAX_XMIT_DLEN     "node.conn[%d].iscsi.MaxXmitDataSegmentLength"
+#define CONN_MAX_RECV_DLEN     "node.conn[%d].iscsi.MaxRecvDataSegmentLength"
+#define CONN_HDR_DIGEST                "node.conn[%d].iscsi.HeaderDigest"
+#define CONN_DATA_DIGEST       "node.conn[%d].iscsi.DataDigest"
+#define CONN_IFMARKER          "node.conn[%d].iscsi.IFMarker"
+#define CONN_OFMARKER          "node.conn[%d].iscsi.OFMarker"
+
+/* iface fields */
+#define IFACE_HWADDR           "iface.hwaddress"
+#define IFACE_ISCSINAME                "iface.iscsi_ifacename"
+#define IFACE_NETNAME          "iface.net_ifacename"
+#define IFACE_TRANSPORTNAME    "iface.transport_name"
+#define IFACE_INAME            "iface.initiatorname"
+#define IFACE_ISID             "iface.isid"
+#define IFACE_BOOT_PROTO       "iface.bootproto"
+#define IFACE_IPADDR           "iface.ipaddress"
+#define IFACE_PREFIX_LEN       "iface.prefix_len"
+#define IFACE_SUBNET_MASK      "iface.subnet_mask"
+#define IFACE_GATEWAY          "iface.gateway"
+#define IFACE_PRIMARY_DNS      "iface.primary_dns"
+#define IFACE_SEC_DNS          "iface.secondary_dns"
+#define IFACE_VLAN_ID          "iface.vlan_id"
+#define IFACE_VLAN_PRIORITY    "iface.vlan_priority"
+#define IFACE_VLAN_STATE       "iface.vlan_state"
+#define IFACE_LINKLOCAL        "iface.ipv6_linklocal"
+#define IFACE_ROUTER           "iface.ipv6_router"
+#define IFACE_IPV6_AUTOCFG     "iface.ipv6_autocfg"
+#define IFACE_LINKLOCAL_AUTOCFG        "iface.linklocal_autocfg"
+#define IFACE_ROUTER_AUTOCFG   "iface.router_autocfg"
+#define IFACE_STATE            "iface.state"
+#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"
+#define DISC_TYPE              "discovery.type"
+/* sendtargets */
+#define DISC_ST_ADDR           "discovery.sendtargets.address"
+#define DISC_ST_PORT           "discovery.sendtargets.port"
+#define DISC_ST_AUTH_METHOD    "discovery.sendtargets.auth.authmethod"
+#define DISC_ST_USERNAME       "discovery.sendtargets.auth.username"
+#define DISC_ST_PASSWORD       "discovery.sendtargets.auth.password"
+#define DISC_ST_PASSWORD_LEN   "discovery.sendtargets.auth.password_length"
+#define DISC_ST_USERNAME_IN    "discovery.sendtargets.auth.username_in"
+#define DISC_ST_PASSWORD_IN    "discovery.sendtargets.auth.password_in"
+#define DISC_ST_PASSWORD_IN_LEN        "discovery.sendtargets.auth.password_in_length"
+#define DISC_ST_LOGIN_TMO      "discovery.sendtargets.timeo.login_timeout"
+#define DISC_ST_REOPEN_MAX     "discovery.sendtargets.reopen_max"
+#define DISC_ST_DISC_DAEMON_POLL_INVAL "discovery.sendtargets.discoveryd_poll_inval"
+#define DISC_ST_USE_DISC_DAEMON        "discovery.sendtargets.use_discoveryd"
+#define DISC_ST_AUTH_TMO       "discovery.sendtargets.timeo.auth_timeout"
+#define DISC_ST_ACTIVE_TMO     "discovery.sendtargets.timeo.active_timeout"
+#define DISC_ST_MAX_RECV_DLEN  "discovery.sendtargets.iscsi.MaxRecvDataSegmentLength"
+
+#define DISC_ISNS_DISC_DAEMON_POLL_INVAL       "discovery.isns.discoveryd_poll_inval"
+#define DISC_ISNS_USE_DISC_DAEMON      "discovery.isns.use_discoveryd"
+#define DISC_ISNS_ADDR         "discovery.sendtargets.address"
+#define DISC_ISNS_PORT         "discovery.sendtargets.port"
+
+/* host auth fields */
+#define HOST_AUTH_INDEX                        "host.auth.tbl_idx"
+#define HOST_AUTH_METHOD               "host.auth.authmethod"
+#define HOST_AUTH_USERNAME             "host.auth.username"
+#define HOST_AUTH_PASSWORD             "host.auth.password"
+#define HOST_AUTH_PASSWORD_LEN         "host.auth.password_length"
+#define HOST_AUTH_USERNAME_IN          "host.auth.username_in"
+#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/pkgs/open-iscsi/open-iscsi-2.1.8/usr/iface.c b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/iface.c
new file mode 100644 (file)
index 0000000..70527ed
--- /dev/null
@@ -0,0 +1,2580 @@
+/*
+ * iSCSI iface helpers
+ *
+ * Copyright (C) 2008 Mike Christie
+ * Copyright (C) 2008 Red Hat, Inc. All rights reserved.
+ * maintained by open-iscsi@@googlegroups.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * See the file COPYING included with this distribution for more details.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <dirent.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <arpa/inet.h>
+#include <libopeniscsiusr/libopeniscsiusr.h>
+
+#include "log.h"
+#include "list.h"
+#include "iscsi_sysfs.h"
+#include "iscsi_settings.h"
+#include "config.h"
+#include "transport.h"
+#include "idbm.h"
+#include "iface.h"
+#include "session_info.h"
+#include "host.h"
+#include "fw_context.h"
+#include "sysdeps.h"
+#include "iscsi_err.h"
+#include "iscsi_netlink.h"
+
+#define _unwrap(x) (x && strlen(x)) ? x : UNKNOWN_VALUE
+
+/*
+ * Default ifaces for use with transports that do not bind to hardware
+ * by defaults (transports that let the interconnect layer to the routing
+ * by defaults).
+ */
+
+/*
+ * iSCSI over TCP/IP
+ */
+static struct iface_rec iface_default = {
+       .name           = "default",
+       .transport_name = "tcp",
+};
+
+/*
+ * iSER
+ */
+static struct iface_rec iface_iser = {
+       .name           = "iser",
+       .transport_name = "iser",
+};
+
+static struct iface_rec *default_ifaces[] = {
+       &iface_default,
+       &iface_iser,
+       NULL,
+};
+
+static struct iface_rec *iface_match_default(struct iface_rec *iface)
+{
+       struct iface_rec *def_iface;
+       int i = 0;
+
+       while ((def_iface = default_ifaces[i++])) {
+               if (!strcmp(iface->name, def_iface->name))
+                       return def_iface;
+       }
+       return NULL;
+}
+
+static void iface_init(struct iface_rec *iface)
+{
+       if (!strlen(iface->name))
+               sprintf(iface->name, DEFAULT_IFACENAME);
+}
+
+/*
+ * Default is to use tcp through whatever the network layer
+ * selects for us with the initiatorname.iscsi iname.
+ */
+void iface_setup_defaults(struct iface_rec *iface)
+{
+       sprintf(iface->transport_name, DEFAULT_TRANSPORT);
+       iface_init(iface);
+}
+
+struct iface_rec *iface_alloc(char *ifname, int *err)
+{
+       struct iface_rec *iface;
+
+       if (!strlen(ifname) || strlen(ifname) + 1 > ISCSI_MAX_IFACE_LEN) {
+               *err = ISCSI_ERR_INVAL;
+               return NULL;
+       }
+
+       iface = calloc(1, sizeof(*iface));
+       if (!iface) {
+               *err = ISCSI_ERR_NOMEM;
+               return NULL;
+       }
+
+       strlcpy(iface->name, ifname, ISCSI_MAX_IFACE_LEN);
+       INIT_LIST_HEAD(&iface->list);
+       return iface;
+}
+
+static int __iface_conf_read(struct iface_rec *iface)
+{
+       char *iface_conf;
+       recinfo_t *info;
+       FILE *f;
+       int rc = 0;
+
+       iface_conf = calloc(1, PATH_MAX);
+       if (!iface_conf)
+               return ISCSI_ERR_NOMEM;
+
+       info = idbm_recinfo_alloc(MAX_KEYS);
+       if (!info) {
+               rc = ISCSI_ERR_NOMEM;
+               goto free_conf;
+       }
+
+       snprintf(iface_conf, PATH_MAX, "%s/%s", IFACE_CONFIG_DIR,
+                iface->name);
+
+       log_debug(5, "looking for iface conf %s", iface_conf);
+       f = fopen(iface_conf, "r");
+       if (!f) {
+               /*
+                * if someone passes in default but has not defined
+                * an iface with default then we do it for them
+                */
+               if (!strcmp(iface->name, DEFAULT_IFACENAME)) {
+                       iface_setup_defaults(iface);
+                       rc = 0;
+               } else
+                       rc = ISCSI_ERR_IDBM;
+               goto free_info;
+       }
+
+       iface_init(iface);
+       idbm_recinfo_iface(iface, info);
+       idbm_recinfo_config(info, f);
+       fclose(f);
+
+free_info:
+       free(info);
+free_conf:
+       free(iface_conf);
+       return rc;
+}
+
+int iface_conf_read(struct iface_rec *iface)
+{
+       struct iface_rec *def_iface;
+       int rc, retry = 0;
+
+       def_iface = iface_match_default(iface);
+       if (def_iface) {
+               /*
+                * older tools allowed default to have different
+                * transport_names so we do not want to overwrite
+                * it.
+                */
+               if (!strcmp(def_iface->name, DEFAULT_IFACENAME)) {
+                       if (!strlen(iface->name))
+                               strcpy(iface->name, def_iface->name);
+                       if (!strlen(iface->netdev))
+                               strcpy(iface->netdev, def_iface->netdev);
+                       if (!strlen(iface->hwaddress))
+                               strcpy(iface->hwaddress, def_iface->hwaddress);
+                       if (!strlen(iface->transport_name))
+                               strcpy(iface->transport_name,
+                                      def_iface->transport_name);
+                       if (!strlen(iface->iname))
+                               strcpy(iface->iname, def_iface->iname);
+               } else {
+                       iface_init(iface);
+                       iface_copy(iface, def_iface);
+               }
+               return 0;
+       }
+
+retry_read:
+       rc = idbm_lock();
+       if (rc)
+               return rc;
+
+       rc = __iface_conf_read(iface);
+       idbm_unlock();
+
+       /*
+        * cmd was run before running -m iface, so force def bindings
+        * creation to see if that was the one requested
+        */
+       if (retry < 1 && rc == ISCSI_ERR_IDBM) {
+               iface_setup_host_bindings();
+               retry++;
+               goto retry_read;
+       }
+
+       return rc;
+}
+
+int iface_conf_delete(struct iface_rec *iface)
+{
+       struct iface_rec *def_iface;
+       char *iface_conf;
+       int rc = 0;
+
+       def_iface = iface_match_default(iface);
+       if (def_iface) {
+               log_error("iface %s is a special interface and "
+                         "cannot be deleted.", iface->name);
+               return ISCSI_ERR_INVAL;
+       }
+
+       iface_conf = calloc(1, PATH_MAX);
+       if (!iface_conf)
+               return ISCSI_ERR_NOMEM;
+
+       sprintf(iface_conf, "%s/%s", IFACE_CONFIG_DIR, iface->name);
+       rc = idbm_lock();
+       if (rc)
+               goto free_conf;
+
+       if (unlink(iface_conf))
+               rc = ISCSI_ERR_IDBM;
+       idbm_unlock();
+
+free_conf:
+       free(iface_conf);
+       return rc;
+}
+
+int iface_conf_write(struct iface_rec *iface)
+{
+       struct iface_rec *def_iface;
+       char *iface_conf;
+       FILE *f;
+       int rc = 0;
+
+       def_iface = iface_match_default(iface);
+       if (def_iface) {
+               log_error("iface %s is a special interface and "
+                         "is not stored in %s.", iface->name,
+                         IFACE_CONFIG_DIR);
+               return ISCSI_ERR_INVAL;
+       }
+
+       iface_conf = calloc(1, PATH_MAX);
+       if (!iface_conf)
+               return ISCSI_ERR_NOMEM;
+
+       sprintf(iface_conf, "%s/%s", IFACE_CONFIG_DIR, iface->name);
+       f = fopen(iface_conf, "w");
+       if (!f) {
+               rc = ISCSI_ERR_IDBM;
+               goto free_conf;
+       }
+
+       rc = idbm_lock();
+       if (rc)
+               goto close_f;
+
+       idbm_print(IDBM_PRINT_TYPE_IFACE, iface, 1, f);
+       idbm_unlock();
+
+close_f:
+       fclose(f);
+free_conf:
+       free(iface_conf);
+       return rc;
+}
+
+int iface_conf_update(struct list_head *params, struct iface_rec *iface)
+{
+       struct iface_rec *def_iface;
+       recinfo_t *info;
+       struct user_param *param;
+       int rc = 0;
+
+       def_iface = iface_match_default(iface);
+       if (def_iface) {
+               log_error("iface %s is a special interface and "
+                         "cannot be modified.", iface->name);
+               return ISCSI_ERR_INVAL;
+       }
+
+       info = idbm_recinfo_alloc(MAX_KEYS);
+       if (!info)
+               return ISCSI_ERR_NOMEM;
+
+       idbm_recinfo_iface(iface, info);
+
+       list_for_each_entry(param, params, list) {
+               rc = idbm_verify_param(info, param->name);
+               if (rc)
+                       goto free_info;
+       }
+
+       list_for_each_entry(param, params, list) {
+               rc = idbm_rec_update_param(info, param->name, param->value, 0);
+               if (rc)
+                       goto free_info;
+       }
+
+       rc = iface_conf_write(iface);
+free_info:
+       free(info);
+       return rc;
+}
+
+#if 0 /* Unused */
+static int iface_get_next_id(void)
+{
+       struct stat statb;
+       char *iface_conf;
+       int i, rc = ENOSPC;
+
+       iface_conf = calloc(1, PATH_MAX);
+       if (!iface_conf)
+               return ENOMEM;
+
+       for (i = 0; i < INT_MAX; i++) {
+               memset(iface_conf, 0, PATH_MAX);
+               /* check len */
+               snprintf(iface_conf, PATH_MAX, "iface%d", i);
+               if (strlen(iface_conf) > ISCSI_MAX_IFACE_LEN - 1) {
+                       log_error("iface namespace is full. Remove unused "
+                                 "iface definitions from %s or send mail "
+                                 "to open-iscsi@googlegroups.com to report "
+                                 "the problem", IFACE_CONFIG_DIR);
+                       rc = ENOSPC;
+                       break;
+               }
+               memset(iface_conf, 0, PATH_MAX);
+               snprintf(iface_conf, PATH_MAX, "%s/iface%d", IFACE_CONFIG_DIR,
+                       i);
+
+               if (!stat(iface_conf, &statb))
+                       continue;
+               if (errno == ENOENT) {
+                       rc = i;
+                       break;
+               }
+       }
+
+       free(iface_conf);
+        return rc;
+}
+#endif /* Unused */
+
+struct iface_search {
+       struct iface_rec *pattern;
+       struct iface_rec *found;
+};
+
+static int __iface_get_by_net_binding(void *data, struct iface_rec *iface)
+{
+       struct iface_search *search = data;
+
+       if (!strcmp(search->pattern->name, iface->name)) {
+               iface_copy(search->found, iface);
+               return 1;
+       }
+
+       if (iface_is_bound_by_hwaddr(search->pattern)) {
+               if (!strcasecmp(iface->hwaddress,
+                               search->pattern->hwaddress)) {
+                       iface_copy(search->found, iface);
+                       return 1;
+               } else
+                       return 0;
+       }
+
+       if (iface_is_bound_by_netdev(search->pattern)) {
+               if (!strcmp(iface->netdev, search->pattern->netdev)) {
+                       iface_copy(search->found, iface);
+                       return 1;
+               } else
+                       return 0;
+       }
+
+/*
+       if (iface_is_bound_by_ipaddr(search->pattern)) {
+               if (!strcmp(iface->ipaddress, search->pattern->ipaddress)) {
+                       iface_copy(search->found, iface);
+                       return 1;
+               } else
+                       return 0;
+       }
+*/
+       return 0;
+}
+
+/*
+ * Before 2.0.870, we only could bind by netdeivce or hwaddress,
+ * so we did a simple reverse lookup to go from sysfs info to
+ * the iface name. After 2.0.870 we added a lot of options to the
+ * iface binding so we added the ifacename to the kernel.
+ *
+ * This function is for older kernels that do not export the ifacename.
+ * If the user was doing iscsi_tcp session binding we will find
+ * the iface by matching net info.
+ */
+int iface_get_by_net_binding(struct iface_rec *pattern,
+                            struct iface_rec *out_rec)
+{
+       int num_found = 0, rc;
+       struct iface_search search;
+
+       if (!iface_is_bound_by_hwaddr(pattern) &&
+           !iface_is_bound_by_netdev(pattern)) {
+               sprintf(out_rec->name, DEFAULT_IFACENAME);
+               return 0;
+       }
+
+       search.pattern = pattern;
+       search.found = out_rec;
+
+       rc = iface_for_each_iface(&search, 0, &num_found,
+                                 __iface_get_by_net_binding);
+       if (rc == 1)
+               return 0;
+       return ISCSI_ERR_NO_OBJS_FOUND;
+}
+
+/*
+ * detect IPv4 vs IPv4 IP address
+ */
+enum iscsi_iface_type iface_get_iptype(struct iface_rec *iface)
+{
+       enum iscsi_iface_type res = ISCSI_IFACE_TYPE_IPV4;
+
+       /* address might not be set if user config with another tool */
+       if (!strlen(iface->ipaddress) ||
+           !strcmp(UNKNOWN_VALUE, iface->ipaddress)) {
+               /* unknown or empty IP address: try to figure out by name */
+               if (strstr(iface->name, "ipv6"))
+                       res = ISCSI_IFACE_TYPE_IPV6;
+       } else {
+               /* figure out what type of IP address string we have */
+               if (strcmp(iface->bootproto, "dhcp") &&
+                   !strchr(iface->ipaddress, '.')) {
+                       /* bootproto is NOT "dhcp", IP addr does NOT have a dot in it */
+                       res = ISCSI_IFACE_TYPE_IPV6;
+               }
+       }
+
+       log_debug(8, "iface: ipaddr=\"%s\" name=\"%s\" bootproto=\"%s\" -> %s",
+                       iface->ipaddress, iface->name,
+                       iface->bootproto,
+                       res == ISCSI_IFACE_TYPE_IPV4 ? "IPv4" : "IPv6");
+
+       return res;
+}
+
+static int iface_setup_binding_from_kern_iface(void *data,
+                                              struct iface_rec *kern_iface)
+{
+       struct host_info *hinfo = data;
+       struct iface_rec iface;
+       char iface_path[PATH_MAX];
+
+       if (!strlen(hinfo->iface.hwaddress)) {
+               log_error("Invalid offload iSCSI host %u. Missing "
+                         "hwaddress. Try upgrading %s driver.",
+                         hinfo->host_no, hinfo->iface.transport_name);
+               return 0;
+       }
+
+       memset(&iface, 0, sizeof(struct iface_rec));
+       if (kern_iface) {
+               memcpy(&iface, kern_iface, sizeof(iface));
+
+               snprintf(iface.name, sizeof(iface.name), "%s.%s.%s.%u",
+                        kern_iface->transport_name,
+                        kern_iface->hwaddress,
+                        iface_get_iptype(kern_iface) == ISCSI_IFACE_TYPE_IPV4 ?
+                        "ipv4" : "ipv6", kern_iface->iface_num);
+       } else {
+               snprintf(iface.name, sizeof(iface.name), "%s.%s",
+                        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);
+
+       if (access(iface_path, F_OK) != 0) {
+               /* not found so create it */
+               if (iface_conf_write(&iface)) {
+                       log_error("Could not create default iface conf %s.",
+                                 iface.name);
+                       /* fall through - will not be persistent */
+               }
+       }
+
+       return 0;
+}
+
+static int __iface_setup_host_bindings(__attribute__((unused))void *data,
+                                      struct host_info *hinfo)
+{
+       struct iface_rec *def_iface;
+       struct iscsi_transport *t;
+       int i = 0, nr_found;
+
+       t = iscsi_sysfs_get_transport_by_hba(hinfo->host_no);
+       if (!t)
+               return 0;
+
+       /* do not setup binding for hosts using non offload drivers */
+       while ((def_iface = default_ifaces[i++])) {
+               if (!strcmp(t->name, def_iface->transport_name))
+                       return 0;
+       }
+
+       nr_found = 0;
+       iscsi_sysfs_for_each_iface_on_host(hinfo, hinfo->host_no,
+                                          &nr_found,
+                                          iface_setup_binding_from_kern_iface);
+       if (!nr_found)
+               iface_setup_binding_from_kern_iface(hinfo, NULL);
+       return 0;
+}
+
+/*
+ * Create a default iface for offload cards. We assume that we will
+ * be able identify each host by MAC.
+ */
+void iface_setup_host_bindings(void)
+{
+       int nr_found = 0;
+
+       if (idbm_lock())
+               return;
+
+       if (access(IFACE_CONFIG_DIR, F_OK) != 0) {
+               if (mkdir(IFACE_CONFIG_DIR, 0770) != 0) {
+                       log_error("Could not make %s. HW/OFFLOAD iscsi "
+                                 "may not be supported", IFACE_CONFIG_DIR);
+                       idbm_unlock();
+                       return;
+               }
+       }
+       idbm_unlock();
+
+       transport_probe_for_offload();
+
+       if (iscsi_sysfs_for_each_host(NULL, &nr_found,
+                                     __iface_setup_host_bindings))
+               log_error("Could not scan scsi hosts. HW/OFFLOAD iscsi "
+                         "operations may not be supported, or please "
+                         "see README for instructions on setting up ifaces.");
+}
+
+void iface_copy(struct iface_rec *dst, struct iface_rec *src)
+{
+       if (strlen(src->name))
+               strcpy(dst->name, src->name);
+       if (src->iface_num)
+               dst->iface_num = src->iface_num;
+       if (strlen(src->netdev))
+               strcpy(dst->netdev, src->netdev);
+       if (strlen(src->ipaddress))
+               strcpy(dst->ipaddress, src->ipaddress);
+       if (strlen(src->subnet_mask))
+               strcpy(dst->subnet_mask, src->subnet_mask);
+       if (strlen(src->gateway))
+               strcpy(dst->gateway, src->gateway);
+       if (strlen(src->bootproto))
+               strcpy(dst->bootproto, src->bootproto);
+       if (strlen(src->ipv6_linklocal))
+               strcpy(dst->ipv6_linklocal, src->ipv6_linklocal);
+       if (strlen(src->ipv6_router))
+               strcpy(dst->ipv6_router, src->ipv6_router);
+       if (strlen(src->ipv6_autocfg))
+               strcpy(dst->ipv6_autocfg, src->ipv6_autocfg);
+       if (strlen(src->linklocal_autocfg))
+               strcpy(dst->linklocal_autocfg, src->linklocal_autocfg);
+       if (strlen(src->router_autocfg))
+               strcpy(dst->router_autocfg, src->router_autocfg);
+       if (src->vlan_id)
+               dst->vlan_id = src->vlan_id;
+       if (src->vlan_priority)
+               dst->vlan_priority = src->vlan_priority;
+       if (strlen(src->vlan_state))
+               strcpy(dst->vlan_state, src->vlan_state);
+       if (strlen(src->state))
+               strcpy(dst->state, src->state);
+       if (src->mtu)
+               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))
+               strcpy(dst->transport_name, src->transport_name);
+       if (strlen(src->iname))
+               strcpy(dst->iname, src->iname);
+}
+
+int iface_is_valid(struct iface_rec *iface)
+{
+       if (!iface)
+               return 0;
+
+       if (!strlen(iface->name))
+               return 0;
+
+       if (!strlen(iface->transport_name))
+               return 0;
+
+       if (iface_is_bound_by_hwaddr(iface))
+               return 1;
+
+       if (iface_is_bound_by_netdev(iface))
+               return 1;
+//     if (iface_is_bound_by_ipaddr(iface))
+//             return 1;
+
+       /* bound by transport name */
+       return 1;
+}
+
+int iface_match(struct iface_rec *pattern, struct iface_rec *iface)
+{
+       if (!pattern || !iface)
+               return 1;
+
+       if (!strlen(pattern->name))
+               return 1;
+
+       if (!strcmp(pattern->name, iface->name)) {
+               if (!strcmp(pattern->name, DEFAULT_IFACENAME))
+                       return 1;
+               /*
+                * For default we allow the same name, but different
+                * transports.
+                */
+               if (!strlen(pattern->transport_name))
+                       return 1;
+
+               if (!strcmp(pattern->transport_name, iface->transport_name))
+                       return 1;
+               /* fall through */
+       }
+       return 0;
+}
+
+int iface_is_bound_by_hwaddr(struct iface_rec *iface)
+{
+       if (iface && strlen(iface->hwaddress) &&
+           strcmp(iface->hwaddress, DEFAULT_HWADDRESS))
+               return 1;
+       return 0;
+}
+
+int iface_is_bound_by_netdev(struct iface_rec *iface)
+{
+       if (iface && strlen(iface->netdev) &&
+          strcmp(iface->netdev, DEFAULT_NETDEV))
+               return 1;
+       return 0;
+}
+
+int iface_is_bound_by_ipaddr(struct iface_rec *iface)
+{
+       if (iface && strlen(iface->ipaddress) &&
+          strcmp(iface->ipaddress, DEFAULT_IPADDRESS))
+               return 1;
+       return 0;
+}
+
+void iface_print(struct iscsi_iface *iface, char *prefix)
+{
+       const char *ipaddress = iscsi_iface_ipaddress_get(iface);
+
+       printf("%sIface Name: %s\n", prefix,
+              (strlen(iscsi_iface_name_get(iface)) > 0) ?
+              iscsi_iface_name_get(iface) : UNKNOWN_VALUE);
+
+       printf("%sIface Transport: %s\n", prefix,
+              (strlen(iscsi_iface_transport_name_get(iface)) > 0) ?
+              iscsi_iface_transport_name_get(iface) : UNKNOWN_VALUE);
+
+       printf("%sIface Initiatorname: %s\n", prefix,
+              (strlen(iscsi_iface_iname_get(iface)) > 0) ?
+              iscsi_iface_iname_get(iface) : UNKNOWN_VALUE);
+
+       if (!strlen(ipaddress))
+               printf("%sIface IPaddress: %s\n", prefix, UNKNOWN_VALUE);
+       else if (strchr(ipaddress, '.'))
+               printf("%sIface IPaddress: %s\n", prefix, ipaddress);
+       else
+               printf("%sIface IPaddress: [%s]\n", prefix, ipaddress);
+
+       printf("%sIface HWaddress: %s\n", prefix,
+              (strlen(iscsi_iface_hwaddress_get(iface)) > 0) ?
+              iscsi_iface_hwaddress_get(iface) : UNKNOWN_VALUE);
+
+       printf("%sIface Netdev: %s\n", prefix,
+              (strlen(iscsi_iface_netdev_get(iface)) > 0) ?
+              iscsi_iface_netdev_get(iface) : UNKNOWN_VALUE);
+}
+
+struct iface_print_node_data {
+       struct node_rec *last_rec;
+       struct iface_rec *match_iface;
+};
+
+static int iface_print_nodes(void *data, node_rec_t *rec)
+{
+       struct iface_print_node_data *print_data = data;
+
+       if (!iface_match(print_data->match_iface, &rec->iface))
+               return -1;
+
+       idbm_print_node_tree(print_data->last_rec, rec, "\t");
+       return 0;
+}
+
+/**
+ * iface_print_tree - print out binding info
+ * @iface: iface to print out
+ *
+ * Currently this looks like the iface conf print, because we only
+ * have the binding info. When we store the iface specific node settings
+ * in the iface record then it will look different.
+ */
+int iface_print_tree(__attribute__((unused))void *data,
+                    struct iface_rec *iface)
+{
+       struct node_rec last_rec;
+       struct iface_print_node_data print_data;
+       int num_found = 0;
+
+       printf("Iface: %s\n", iface->name);
+
+       memset(&last_rec, 0, sizeof(struct node_rec ));
+
+       print_data.match_iface = iface;
+       print_data.last_rec = &last_rec;
+
+       idbm_for_each_rec(&num_found, &print_data, iface_print_nodes, false);
+       return 0;
+}
+
+void iface_print_flat(struct iscsi_iface *iface)
+{
+       printf("%s %s,%s,%s,%s,%s\n",
+              _unwrap(iscsi_iface_name_get(iface)),
+              _unwrap(iscsi_iface_transport_name_get(iface)),
+              _unwrap(iscsi_iface_hwaddress_get(iface)),
+              _unwrap(iscsi_iface_ipaddress_get(iface)),
+              _unwrap(iscsi_iface_netdev_get(iface)),
+              _unwrap(iscsi_iface_iname_get(iface)));
+}
+
+int iface_for_each_iface(void *data, int skip_def, int *nr_found,
+                        iface_op_fn *fn)
+{
+       DIR *iface_dirfd;
+       struct dirent *iface_dent;
+       struct iface_rec *iface, *def_iface;
+       int err = 0, i = 0;
+
+       if (!skip_def) {
+               while ((def_iface = default_ifaces[i++])) {
+                       iface = iface_alloc(def_iface->name, &err);
+                       if (!iface) {
+                               log_error("Could not add iface %s.",
+                                         def_iface->name);
+                               continue;
+                       }
+                       iface_copy(iface, def_iface);
+                       err = fn(data, iface);
+                       free(iface);
+                       if (err)
+                               return err;
+                       (*nr_found)++;
+               }
+       }
+
+       iface_dirfd = opendir(IFACE_CONFIG_DIR);
+       if (!iface_dirfd)
+               return errno;
+
+       while ((iface_dent = readdir(iface_dirfd))) {
+               if (!strcmp(iface_dent->d_name, ".") ||
+                   !strcmp(iface_dent->d_name, ".."))
+                       continue;
+
+               if (!strcmp(iface_dent->d_name, "iface.example"))
+                       continue;
+
+               log_debug(5, "iface_for_each_iface found %s",
+                        iface_dent->d_name);
+               iface = iface_alloc(iface_dent->d_name, &err);
+               if (!iface || err) {
+                       if (err == ISCSI_ERR_INVAL)
+                               log_error("Invalid iface name %s. Must be "
+                                         "from 1 to %d characters.",
+                                          iface_dent->d_name,
+                                          ISCSI_MAX_IFACE_LEN - 1);
+                       else
+                               log_error("Could not add iface %s.",
+                                         iface_dent->d_name);
+                       continue;
+               }
+
+               err = idbm_lock();
+               if (err) {
+                       free(iface);
+                       continue;
+               }
+
+               err = __iface_conf_read(iface);
+               idbm_unlock();
+               if (err) {
+                       log_error("Could not read def iface %s (err %d)",
+                                 iface->name, err);
+                       free(iface);
+                       continue;
+               }
+
+               if (!iface_is_valid(iface)) {
+                       log_debug(5, "iface is not valid "
+                                 "Iface settings " iface_fmt,
+                                 iface_str(iface));
+                       free(iface);
+                       continue;
+               }
+
+               err = fn(data, iface);
+               free(iface);
+               if (err)
+                       break;
+               (*nr_found)++;
+       }
+
+       closedir(iface_dirfd);
+       return err;
+}
+
+static int iface_link(void *data, struct iface_rec *iface)
+{
+       struct list_head *ifaces = data;
+       struct iface_rec *iface_copy;
+
+       iface_copy = calloc(1, sizeof(*iface_copy));
+       if (!iface_copy)
+               return ISCSI_ERR_NOMEM;
+
+       memcpy(iface_copy, iface, sizeof(*iface_copy));
+       INIT_LIST_HEAD(&iface_copy->list);
+       list_add_tail(&iface_copy->list, ifaces);
+       return 0;
+}
+
+/**
+ * iface_link_ifaces - link non default ifaces
+ * @ifaces: list to add ifaces to
+ *
+ * This will return a list of the ifaces created by iscsiadm
+ * or the user. It does not return the static default ones.
+ */
+void iface_link_ifaces(struct list_head *ifaces)
+{
+       int nr_found = 0;
+
+       iface_for_each_iface(ifaces, 1, &nr_found, iface_link);
+}
+
+/*
+ * ipv6 address strings will have at least two colons
+ *
+ * NOTE: does NOT validate the IP address
+ */
+static bool ipaddr_is_ipv6(char *ipaddr)
+{
+       char *first_colon, *second_colon;
+       bool res = false;
+
+       if (ipaddr) {
+               first_colon = strchr(ipaddr, ':');
+               if (first_colon) {
+                       second_colon = strchr(first_colon+1, ':');
+                       if (second_colon &&
+                           (second_colon != first_colon))
+                               res = true;
+               }
+               log_debug(8, "%s(%s) -> %u",
+                       __FUNCTION__, ipaddr, res);
+       } else
+               log_debug(8, "%s(nil) -> %u",
+                       __FUNCTION__, res);
+       return res;
+}
+
+/**
+ * iface_setup_from_boot_context - setup iface from boot context info
+ * @iface: iface t setup
+ * @context: boot context info
+ *
+ * Returns 1 if setup for offload.
+ */
+int iface_setup_from_boot_context(struct iface_rec *iface,
+                                  struct boot_context *context)
+{
+       struct iscsi_transport *t = NULL;
+       uint32_t hostno;
+
+       if (strlen(context->initiatorname))
+               strlcpy(iface->iname, context->initiatorname,
+                       sizeof(iface->iname));
+
+       if (strlen(context->scsi_host_name)) {
+               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;
+               }
+       } 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 */
+               if (!net_get_transport_name_from_netdev(context->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) {
+                       /*
+                        * If the MAC in the boot info does not match an iscsi
+                        * 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",
+                                 context->mac);
+                       return 0;
+               }
+
+               strlcpy(iface->netdev, context->iface, sizeof(iface->netdev));
+#else
+               return 0;
+#endif
+       } else
+               return 0;
+
+       /*
+        * set up for access through a offload card.
+        */
+       if (!t)
+               t = iscsi_sysfs_get_transport_by_hba(hostno);
+       if (!t) {
+               log_error("Could not get transport for host%u. "
+                         "Make sure the iSCSI driver is loaded.",
+                         hostno);
+               return 0;
+       }
+       strcpy(iface->transport_name, t->name);
+
+       strlcpy(iface->hwaddress, context->mac,
+               sizeof(iface->hwaddress));
+       strlcpy(iface->ipaddress, context->ipaddr,
+               sizeof(iface->ipaddress));
+       iface->vlan_id = atoi(context->vlan);
+       strlcpy(iface->subnet_mask, context->mask,
+               sizeof(iface->subnet_mask));
+       strlcpy(iface->gateway, context->gateway,
+               sizeof(iface->gateway));
+       snprintf(iface->name, sizeof(iface->name), "%s.%s.%s.%u",
+                iface->transport_name, context->mac,
+                ipaddr_is_ipv6(iface->ipaddress) ?  "ipv6" : "ipv4",
+                iface->iface_num);
+
+       log_debug(1, "iface " iface_fmt "", iface_str(iface));
+       return 1;
+}
+
+/**
+ * iface_create_ifaces_from_boot_contexts - create ifaces based on boot info
+ * @ifaces: list to store ifaces in
+ * @targets: list of targets to create ifaces from
+ *
+ * This function will create an iface struct based on the boot info
+ * and it will create (or update if existing already) an iface rec in
+ * the ifaces dir based on the info.
+ */
+int iface_create_ifaces_from_boot_contexts(struct list_head *ifaces,
+                                          struct list_head *targets)
+{
+       struct boot_context *context;
+       struct iface_rec *iface, *tmp_iface;
+       int rc = 0;
+
+       list_for_each_entry(context, targets, list) {
+               rc = 0;
+               /* 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",
+                                 context->iface);
+                       goto fail;
+               }
+               if (!iface_setup_from_boot_context(iface, context)) {
+                       /* no offload so forget it */
+                       free(iface);
+                       continue;
+               }
+
+               rc = iface_conf_write(iface);
+               if (rc) {
+                       log_error("Could not setup default iface conf "
+                                 "for %s.", iface->name);
+                       free(iface);
+                       goto fail;
+               }
+               list_add_tail(&iface->list, ifaces);
+       }
+
+       return 0;
+fail:
+       list_for_each_entry_safe(iface, tmp_iface, ifaces, list) {
+               list_del(&iface->list);
+               free(iface);
+       }
+       return rc;
+}
+
+struct iface_param_count {
+       struct iface_rec *primary;
+       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
+ * @iface: iface to setup
+ */
+static int __iface_get_param_count(void *data, struct iface_rec *iface)
+{
+       struct iface_param_count *iface_params = data;
+       enum iscsi_iface_type iptype;
+       int count = 0;
+
+       if (strcmp(iface_params->primary->hwaddress, iface->hwaddress))
+               return 0;
+
+       iptype = iface_get_iptype(iface);
+       if (iptype == ISCSI_IFACE_TYPE_IPV4) {
+
+               if (strcmp(iface->state, "disable")) {
+                       if (strstr(iface->bootproto, "dhcp")) {
+                               /* DHCP enabled */
+                               count++;
+                       } else {
+                               /* DHCP disabled */
+                               count++;
+
+                               if (strstr(iface->ipaddress, ".")) {
+                                       /* User configured IPv4 Address */
+                                       count++;
+
+                                       if (strstr(iface->subnet_mask, "."))
+                                               /* User configured Subnet */
+                                               count++;
+
+                                       if (strstr(iface->gateway, "."))
+                                               /* User configured Gateway */
+                                               count++;
+                               } else {
+                                       /*
+                                        * IPv4 Address not valid, decrement
+                                        * count of DHCP
+                                        */
+                                       count--;
+                               }
+                       }
+
+                       /*
+                        * If IPv4 configuration in iface file is valid,
+                        * enable state and other parameters (if any)
+                        */
+                       if (count) {
+                               /* iface state */
+                               count++;
+
+                               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++;
+
+                               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++;
+
+                               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->ttl)
+                                       count++;
+
+                               iface_get_common_param_count(iface, &count);
+                       }
+               } 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")) {
+                               /* Autocfg enabled */
+                               count++;
+                       } else {
+                               /* Autocfg disabled */
+                               count++;
+
+                               if (strstr(iface->ipaddress, ":"))
+                                       /* User configured IPv6 Address */
+                                       count++;
+                               else
+                                       /*
+                                        * IPv6 Address not valid, decrement
+                                        * count of IPv6 Autocfg
+                                        */
+                                       count--;
+                       }
+
+                       /* IPv6 LinkLocal Address */
+                       if (strstr(iface->linklocal_autocfg, "auto"))
+                               /* Autocfg enabled */
+                               count++;
+                       else {
+                               /* Autocfg disabled */
+                               count++;
+
+                               if (strstr(iface->ipv6_linklocal, ":"))
+                                       /* User configured LinkLocal Address */
+                                       count++;
+                               else
+                                       /*
+                                        * LinkLocal Address not valid,
+                                        * decrement count of LinkLocal Autocfg
+                                        */
+                                       count--;
+                       }
+
+                       /* IPv6 Router Address */
+                       if (strstr(iface->router_autocfg, "auto"))
+                               /* Autocfg enabled */
+                               count++;
+                       else {
+                               /* Autocfg disabled */
+                               count++;
+
+                               if (strstr(iface->ipv6_router, ":"))
+                                       /* User configured Router Address */
+                                       count++;
+                               else
+                                       /*
+                                        * Router Address not valid,
+                                        * decrement count of Router Autocfg
+                                        */
+                                       count--;
+                       }
+
+                       /*
+                        * If IPv6 configuration in iface file is valid,
+                        * enable state and other parameters (if any)
+                        */
+                       if (count) {
+                               /* iface state */
+                               count++;
+
+                               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->nd_reachable_tmo)
+                                       count++;
+
+                               if (iface->nd_rexmit_time)
+                                       count++;
+
+                               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 {
+                       /* IPv6 is disabled, iface state */
+                       count++;
+               }
+       }
+
+       iface_params->count += count;
+       return 0;
+}
+
+/**
+ * iface_get_param_count - Gets netconfig parameter count from iface
+ * @iface: iface to setup
+ * @iface_all: Flag for number of ifaces to traverse (1 for all)
+ *
+ * Returns netconfig parameter count.
+ */
+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");
+
+       iface_params.primary = iface;
+       iface_params.count = 0;
+
+       if (iface_all)
+               rc = iface_for_each_iface(&iface_params, 0, &num_found,
+                                         __iface_get_param_count);
+       else
+               rc = __iface_get_param_count(&iface_params, iface);
+
+       log_debug(8, "iface_get_param_count: rc = %d, count = %d",
+                 rc, iface_params.count);
+       return iface_params.count;
+}
+
+/* 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;
+       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) + 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 = 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 */
+static int iface_fill_vlan_id(struct iovec *iov, struct iface_rec *iface,
+                             uint32_t iface_type)
+{
+       int len;
+       struct iscsi_iface_param_info *net_param;
+       uint16_t vlan = 0;
+       struct nlattr *attr;
+
+       len = sizeof(struct iscsi_iface_param_info) + 2;
+       iov->iov_base = iscsi_nla_alloc(ISCSI_NET_PARAM_VLAN_TAG, 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_TAG;
+       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->vlan_id <= ISCSI_MAX_VLAN_ID &&
+           iface->vlan_priority <= ISCSI_MAX_VLAN_PRIORITY)
+               /*
+                * Bit 15-13: User Priority of VLAN
+                * Bit 11-00: VLAN ID
+                */
+               vlan = (iface->vlan_priority << 13) |
+                      (iface->vlan_id & ISCSI_MAX_VLAN_ID);
+       memcpy(net_param->value, &vlan, net_param->len);
+       return 0;
+}
+
+/* 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(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 = 1;
+       net_param->param = param;
+       net_param->iface_type = iface_type;
+       net_param->param_type = param_type;
+       if (!strcmp(param_val, "disable"))
+               net_param->value[0] = ISCSI_NET_PARAM_DISABLE;
+       else if (!strcmp(param_val, "enable"))
+               net_param->value[0] = ISCSI_NET_PARAM_ENABLE;
+       else
+               goto free;
+       return 0;
+free:
+       free(iov->iov_base);
+       iov->iov_base = NULL;
+       iov->iov_len = 0;
+       return 1;
+}
+
+#define IFACE_SET_PARAM_STATE(iov, inum, itype, param, ptype, ival,    \
+                             gcnt, lcnt) {                             \
+       if (!iface_fill_param_state(iov, inum, itype, param, ptype,     \
+                                   ival)) {                            \
+               (*gcnt)++;                                              \
+               (*lcnt)++;                                              \
+       }                                                               \
+}
+
+/* IPv4 Bootproto: DHCP/static */
+static int iface_fill_net_bootproto(struct iovec *iov, struct iface_rec *iface)
+{
+       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_IPV4_BOOTPROTO, 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_IPV4_BOOTPROTO;
+       net_param->iface_type = ISCSI_IFACE_TYPE_IPV4;
+       net_param->iface_num = iface->iface_num;
+       net_param->param_type = ISCSI_NET_PARAM;
+       net_param->len = 1;
+       if (!strcmp(iface->bootproto, "dhcp"))
+               net_param->value[0] = ISCSI_BOOTPROTO_DHCP;
+       else
+               net_param->value[0] = ISCSI_BOOTPROTO_STATIC;
+       return 0;
+}
+
+/* IPv6 IPAddress Autocfg: nd/dhcpv6/disable */
+static int iface_fill_net_autocfg(struct iovec *iov, struct iface_rec *iface)
+{
+       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_IPV6_ADDR_AUTOCFG, 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_IPV6_ADDR_AUTOCFG;
+       net_param->iface_type = ISCSI_IFACE_TYPE_IPV6;
+       net_param->param_type = ISCSI_NET_PARAM;
+       net_param->len = 1;
+
+       if (!strcmp(iface->ipv6_autocfg, "nd"))
+               net_param->value[0] = ISCSI_IPV6_AUTOCFG_ND_ENABLE;
+       else if (!strcmp(iface->ipv6_autocfg, "dhcpv6"))
+               net_param->value[0] = ISCSI_IPV6_AUTOCFG_DHCPV6_ENABLE;
+       else
+               net_param->value[0] = ISCSI_IPV6_AUTOCFG_DISABLE;
+
+       return 0;
+}
+
+/* IPv6 LinkLocal Autocfg: enable/disable */
+static int iface_fill_linklocal_autocfg(struct iovec *iov,
+                                       struct iface_rec *iface)
+{
+       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_IPV6_LINKLOCAL_AUTOCFG,
+                                       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_IPV6_LINKLOCAL_AUTOCFG;
+       net_param->iface_type = ISCSI_IFACE_TYPE_IPV6;
+       net_param->param_type = ISCSI_NET_PARAM;
+       net_param->len = 1;
+
+       if (strstr(iface->linklocal_autocfg, "auto"))
+               net_param->value[0] = ISCSI_IPV6_LINKLOCAL_AUTOCFG_ENABLE;
+       else
+               net_param->value[0] = ISCSI_IPV6_LINKLOCAL_AUTOCFG_DISABLE;
+
+       return 0;
+}
+
+/* IPv6 Router Autocfg: enable/disable */
+static int iface_fill_router_autocfg(struct iovec *iov, struct iface_rec *iface)
+{
+       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_IPV6_ROUTER_AUTOCFG,
+                                       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_IPV6_ROUTER_AUTOCFG;
+       net_param->iface_type = ISCSI_IFACE_TYPE_IPV6;
+       net_param->param_type = ISCSI_NET_PARAM;
+       net_param->len = 1;
+
+       if (strstr(iface->router_autocfg, "auto"))
+               net_param->value[0] = ISCSI_IPV6_ROUTER_AUTOCFG_ENABLE;
+       else
+               net_param->value[0] = ISCSI_IPV6_ROUTER_AUTOCFG_DISABLE;
+
+       return 0;
+}
+
+/* IPv4 IPAddress/Subnet Mask/Gateway: 4 bytes */
+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;
+       struct iscsi_iface_param_info *net_param;
+       struct nlattr *attr;
+
+       len = sizeof(struct iscsi_iface_param_info) + 4;
+       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 = param;
+       net_param->iface_type = ISCSI_IFACE_TYPE_IPV4;
+       net_param->iface_num = iface_num;
+       net_param->len = 4;
+       net_param->param_type = ISCSI_NET_PARAM;
+       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] &&
+           !net_param->value[2] && !net_param->value[3])
+               goto free;
+
+       return 0;
+free:
+       free(iov->iov_base);
+       iov->iov_base = NULL;
+       iov->iov_len = 0;
+       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, uint32_t iface_num,
+                                   uint16_t param, char *param_val)
+{
+       int rc;
+       int len;
+       struct iscsi_iface_param_info *net_param;
+       struct nlattr *attr;
+
+       len = sizeof(struct iscsi_iface_param_info) + 16;
+       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 = param;
+       net_param->iface_type = ISCSI_IFACE_TYPE_IPV6;
+       net_param->iface_num = iface_num;
+       net_param->param_type = ISCSI_NET_PARAM;
+       net_param->len = 16;
+       rc = inet_pton(AF_INET6, param_val, net_param->value);
+       if (rc <= 0)
+               goto free;
+
+       return 0;
+free:
+       free(iov->iov_base);
+       iov->iov_base = NULL;
+       iov->iov_len = 0;
+       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;
+       int count;
+};
+
+static int __iface_build_net_config(void *data, struct iface_rec *iface)
+{
+       struct iface_net_config *net_config = data;
+       struct iovec *iov;
+       int iptype = ISCSI_IFACE_TYPE_IPV4;
+       int count = 0;
+
+       if (strcmp(net_config->primary->hwaddress, iface->hwaddress))
+               return 0;
+
+       /* 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);
+       switch (iptype) {
+       case ISCSI_IFACE_TYPE_IPV4:
+               if (!strcmp(iface->state, "disable")) {
+                       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;
+               }
+
+               if (strstr(iface->bootproto, "dhcp")) {
+                       if (!iface_fill_net_bootproto(&iov[net_config->count],
+                                                     iface)) {
+                               net_config->count++;
+                               count++;
+                       }
+               } else if (strstr(iface->ipaddress, ".")) {
+                       if (!iface_fill_net_bootproto(&iov[net_config->count],
+                                                     iface)) {
+                               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);
+               }
+
+               /*
+                * If IPv4 configuration in iface file is valid,
+                * fill state and other parameters (if any)
+                */
+               if (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);
+               }
+               break;
+
+       case ISCSI_IFACE_TYPE_IPV6:
+               if (!strcmp(iface->state, "disable")) {
+                       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;
+               }
+
+               /* For IPv6 Address */
+               if (strstr(iface->ipv6_autocfg, "nd") ||
+                   strstr(iface->ipv6_autocfg, "dhcpv6")) {
+                       if (!iface_fill_net_autocfg(&iov[net_config->count],
+                                                   iface)) {
+                               net_config->count++;
+                               count++;
+                       }
+               } else if (strstr(iface->ipaddress, ":")) {
+                       if (!iface_fill_net_autocfg(&iov[net_config->count],
+                                                   iface)) {
+                               net_config->count++;
+                               count++;
+                       }
+                       /* User provided IPv6 Address */
+                       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 */
+               if (strstr(iface->linklocal_autocfg, "auto")) {
+                       if (!iface_fill_linklocal_autocfg(
+                                               &iov[net_config->count],
+                                               iface)) {
+                               net_config->count++;
+                               count++;
+                       }
+               } else if (strstr(iface->ipv6_linklocal, ":")) {
+                       if (!iface_fill_linklocal_autocfg(
+                                               &iov[net_config->count],
+                                               iface)) {
+                               net_config->count++;
+                               count++;
+                       }
+                       /* User provided Link Local Address */
+                       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 */
+               if (strstr(iface->router_autocfg, "auto")) {
+                       if (!iface_fill_router_autocfg(&iov[net_config->count],
+                                                      iface)) {
+                               net_config->count++;
+                               count++;
+                       }
+               } else if (strstr(iface->ipv6_router, ":")) {
+                       if (!iface_fill_router_autocfg(&iov[net_config->count],
+                                                      iface)) {
+                               net_config->count++;
+                               count++;
+                       }
+                       /* User provided Router Address */
+                       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);
+               }
+
+               /*
+                * If IPv6 configuration in iface file is valid,
+                * fill state and other parameters
+                */
+               if (count) {
+                       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++;
+                       }
+               }
+
+               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;
+}
+
+/**
+ * iface_build_net_config - Setup neconfig parameter buffers
+ * @iface: iface to setup
+ * @iface_all: Flag for number of ifaces to traverse (1 for all)
+ * @iovs: iovec buffer for netconfig parameters
+ *
+ * Returns total number of netconfig parameter buffers used.
+ */
+int iface_build_net_config(struct iface_rec *iface, int iface_all,
+                          struct iovec *iovs)
+{
+       int num_found = 0, rc;
+       struct iface_net_config net_config;
+
+       log_debug(8, "In iface_build_net_config");
+
+       net_config.primary = iface;
+       net_config.iovs = iovs;
+       net_config.count = 0;
+
+       if (iface_all)
+               rc = iface_for_each_iface(&net_config, 0, &num_found,
+                                         __iface_build_net_config);
+       else
+               rc = __iface_build_net_config(&net_config, iface);
+
+       log_debug(8, "iface_build_net_config: rc = %d, count = %d",
+                 rc, net_config.count);
+       return net_config.count;
+}
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/iface.h b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/iface.h
new file mode 100644 (file)
index 0000000..7e1e6a2
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * iSCSI iface helpers
+ *
+ * Copyright (C) 2008 Mike Christie
+ * Copyright (C) 2008 Red Hat, Inc. All rights reserved.
+ * 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 ISCSI_IFACE_H
+#define ISCSI_IFACE_H
+
+#include <libopeniscsiusr/libopeniscsiusr.h>
+
+#define IFACE_CONFIG_DIR       ISCSI_DB_ROOT"/ifaces"
+
+struct iface_rec;
+struct list_head;
+struct boot_context;
+
+extern void iface_copy(struct iface_rec *dst, struct iface_rec *src);
+extern int iface_match(struct iface_rec *pattern, struct iface_rec *iface);
+extern struct iface_rec *iface_alloc(char *ifname, int *err);
+extern int iface_conf_read(struct iface_rec *iface);
+extern void iface_setup_defaults(struct iface_rec *iface);
+extern int iface_is_bound_by_hwaddr(struct iface_rec *iface);
+extern int iface_is_bound_by_netdev(struct iface_rec *iface);
+extern int iface_is_bound_by_ipaddr(struct iface_rec *iface);
+typedef int (iface_op_fn)(void *data, struct iface_rec *iface);
+extern int iface_for_each_iface(void *data, int skip_def, int *nr_found,
+                                iface_op_fn *fn);
+extern void iface_print(struct iscsi_iface *iface, char *prefix);
+extern void iface_print_flat(struct iscsi_iface *iface);
+extern int iface_print_tree(void *data, struct iface_rec *iface);
+extern void iface_setup_host_bindings(void);
+extern int iface_get_by_net_binding(struct iface_rec *pattern,
+                                   struct iface_rec *out_rec);
+extern int iface_conf_update(struct list_head *params,
+                            struct iface_rec *iface);
+extern int iface_conf_write(struct iface_rec *iface);
+extern int iface_conf_delete(struct iface_rec *iface);
+extern int iface_is_valid(struct iface_rec *iface);
+extern void iface_link_ifaces(struct list_head *ifaces);
+extern int iface_setup_from_boot_context(struct iface_rec *iface,
+                                   struct boot_context *context);
+extern int iface_create_ifaces_from_boot_contexts(struct list_head *ifaces,
+                                                 struct list_head *targets);
+extern int iface_get_param_count(struct iface_rec *iface_primary,
+                                int iface_all);
+extern int iface_build_net_config(struct iface_rec *iface_primary,
+                                 int iface_all, struct iovec *iovs);
+extern enum iscsi_iface_type iface_get_iptype(struct iface_rec *iface);
+
+#define iface_fmt "[hw=%s,ip=%s,net_if=%s,iscsi_if=%s]"
+#define iface_str(_iface) \
+       (_iface)->hwaddress, (_iface)->ipaddress, (_iface)->netdev, \
+       (_iface)->name
+
+#endif
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/initiator.c b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/initiator.c
new file mode 100644 (file)
index 0000000..56bf38b
--- /dev/null
@@ -0,0 +1,2226 @@
+/*
+ * iSCSI Session Management and Slow-path Control
+ *
+ * Copyright (C) 2004 Dmitry Yusupov, Alex Aizman
+ * Copyright (C) 2006 Mike Christie
+ * Copyright (C) 2006 Red Hat, Inc. All rights reserved.
+ * 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 <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/resource.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <dirent.h>
+#include <fcntl.h>
+
+#include "initiator.h"
+#include "transport.h"
+#include "iscsid.h"
+#include "iscsi_if.h"
+#include "mgmt_ipc.h"
+#include "event_poll.h"
+#include "iscsi_ipc.h"
+#include "idbm.h"
+#include "log.h"
+#include "iscsi_util.h"
+#include "scsi.h"
+#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"
+
+#define ISCSI_CONN_ERR_REOPEN_DELAY    3
+#define ISCSI_INTERNAL_ERR_REOPEN_DELAY        5
+
+#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)
+{
+       int i;
+
+       for (i = 0; i < CONTEXT_POOL_MAX; i++) {
+               conn->context_pool[i] = calloc(1,
+                                          sizeof(struct iscsi_ev_context) +
+                                          ipc->ctldev_bufmax);
+               if (!conn->context_pool[i]) {
+                       int j;
+                       for (j = 0; j < i; j++)
+                               free(conn->context_pool[j]);
+                       return ENOMEM;
+               }
+               conn->context_pool[i]->conn = conn;
+       }
+
+       return 0;
+}
+
+static void iscsi_ev_context_free(iscsi_conn_t *conn)
+{
+       int i;
+
+       for (i = 0; i < CONTEXT_POOL_MAX; i++) {
+               if (!conn->context_pool[i])
+                       continue;
+
+               if (conn->context_pool[i]->allocated)
+                       /* missing flush on shutdown */
+                       conn_error(conn, "BUG: context_pool leak %p",
+                                 conn->context_pool[i]);
+               free(conn->context_pool[i]);
+       }
+}
+
+static struct iscsi_ev_context *
+iscsi_ev_context_get(iscsi_conn_t *conn, int ev_size)
+{
+       struct iscsi_ev_context *ev_context;
+       int i;
+
+       if (ev_size > ipc->ctldev_bufmax)
+               return NULL;
+
+       for (i = 0; i < CONTEXT_POOL_MAX; i++) {
+               if (!conn->context_pool[i])
+                       continue;
+
+               if (!conn->context_pool[i]->allocated) {
+                       ev_context = conn->context_pool[i];
+
+                       memset(&ev_context->actor, 0,
+                               sizeof(struct actor));
+                       ev_context->allocated = 1;
+                       /* some callers abuse this pointer */
+                       ev_context->data = (void *)ev_context +
+                                       sizeof(struct iscsi_ev_context);
+                       conn_debug(7, conn, "get ev context %p",
+                                 &ev_context->actor);
+                       return ev_context;
+               }
+       }
+       return NULL;
+}
+
+static void iscsi_ev_context_put(struct iscsi_ev_context *ev_context)
+{
+       log_debug(7, "put ev context %p:%s", &ev_context->actor,
+                 (&ev_context->actor)->name);
+       ev_context->allocated = 0;
+}
+
+static void session_online_devs(int host_no, int sid)
+{
+       iscsi_sysfs_for_each_device(NULL, host_no, sid,
+                                   iscsi_sysfs_set_device_online);
+}
+
+static conn_login_status_e
+__login_response_status(iscsi_conn_t *conn,
+                     enum iscsi_login_status login_status)
+{
+       switch (login_status) {
+       case LOGIN_OK:
+               /* check the status class and detail */
+               return CONN_LOGIN_SUCCESS;
+       case LOGIN_REDIRECT:
+               return CONN_LOGIN_IMM_REDIRECT_RETRY;
+       case LOGIN_IO_ERROR:
+       case LOGIN_REDIRECTION_FAILED:
+               return CONN_LOGIN_RETRY;
+       default:
+               conn_error(conn, "Login error (Login status %d)", login_status);
+               break;
+       }
+
+       return CONN_LOGIN_FAILED;
+}
+
+static conn_login_status_e
+__check_iscsi_status_class(iscsi_session_t *session, int cid,
+                       uint8_t status_class, uint8_t status_detail)
+{
+       iscsi_conn_t *conn = &session->conn[cid];
+
+       switch (status_class) {
+       case ISCSI_STATUS_CLS_SUCCESS:
+               return CONN_LOGIN_SUCCESS;
+       case ISCSI_STATUS_CLS_REDIRECT:
+               switch (status_detail) {
+               case ISCSI_LOGIN_STATUS_TGT_MOVED_TEMP:
+                       return CONN_LOGIN_IMM_RETRY;
+               case ISCSI_LOGIN_STATUS_TGT_MOVED_PERM:
+                       /*
+                        * for a permanent redirect, we need to update the
+                        * failback address
+                        */
+                       memset(&conn->failback_saddr, 0,
+                               sizeof(struct sockaddr_storage));
+                       conn->failback_saddr = conn->saddr;
+                        return CONN_LOGIN_IMM_REDIRECT_RETRY;
+               default:
+                       conn_error(conn, "login rejected: redirection "
+                               "type 0x%x not supported", status_detail);
+                       return CONN_LOGIN_RETRY;
+               }
+       case ISCSI_STATUS_CLS_INITIATOR_ERR:
+               switch (status_detail) {
+               case ISCSI_LOGIN_STATUS_AUTH_FAILED:
+                       log_error("session %d login rejected: Initiator "
+                              "failed authentication with target",
+                               session->id);
+                       return CONN_LOGIN_AUTH_FAILED;
+               case ISCSI_LOGIN_STATUS_TGT_FORBIDDEN:
+                       conn_error(conn, "login rejected: initiator "
+                              "failed authorization with target");
+                       return CONN_LOGIN_AUTH_FAILED;
+               case ISCSI_LOGIN_STATUS_TGT_NOT_FOUND:
+                       conn_error(conn, "login rejected: initiator "
+                              "error - target not found (%02x/%02x)",
+                              status_class, status_detail);
+                       return CONN_LOGIN_FAILED;
+               case ISCSI_LOGIN_STATUS_NO_VERSION:
+                       /*
+                        * FIXME: if we handle multiple protocol versions,
+                        * before we log an error, try the other supported
+                        * versions.
+                        */
+                       conn_error(conn, "login rejected: incompatible "
+                              "version (%02x/%02x), non-retryable, "
+                              "giving up", status_class, status_detail);
+                       return CONN_LOGIN_FAILED;
+               default:
+                       conn_error(conn, "login rejected: initiator "
+                              "error (%02x/%02x)", status_class, status_detail);
+                       return CONN_LOGIN_FAILED;
+               }
+       case ISCSI_STATUS_CLS_TARGET_ERR:
+               conn_error(conn, "login rejected: target error "
+                      "(%02x/%02x)", status_class, status_detail);
+               /*
+                * We have no idea what the problem is. But spec says initiator
+                * may retry later.
+                */
+                return CONN_LOGIN_RETRY;
+       default:
+               conn_error(conn, "login response with unknown status "
+                      "class 0x%x, detail 0x%x", status_class, status_detail);
+               break;
+       }
+
+       return CONN_LOGIN_FAILED;
+}
+
+static int
+__session_conn_create(iscsi_session_t *session, int cid)
+{
+       iscsi_conn_t *conn = &session->conn[cid];
+       conn_rec_t *conn_rec = &session->nrec.conn[cid];
+       node_rec_t *rec = &session->nrec;
+       int err;
+
+       conn->id = cid;
+       if (iscsi_ev_context_alloc(conn)) {
+               conn_error(conn, "cannot allocate context_pool");
+               return ISCSI_ERR_NOMEM;
+       }
+
+       /* set session reconnection retry max */
+       session->reopen_max = rec->session.reopen_max;
+
+       conn->state = ISCSI_CONN_STATE_FREE;
+       conn->session = session;
+       actor_init(&conn->login_timer, iscsi_login_timedout, NULL);
+       /*
+        * TODO: we must export the socket_fd/transport_eph from sysfs
+        * so if iscsid is resyncing up we can pick that up and cleanup up
+        * the old connection. Right now we leak a connection.
+        * We can also probably merge these two fields.
+        */
+       conn->socket_fd = -1;
+       conn->transport_ep_handle = -1;
+       /* connection's timeouts */
+       conn->logout_timeout = conn_rec->timeo.logout_timeout;
+       if (!conn->logout_timeout) {
+               conn_error(conn, "Invalid timeo.logout_timeout. Must be greater "
+                         "than zero. Using default %d.",
+                         DEF_LOGOUT_TIMEO);
+               conn->logout_timeout = DEF_LOGOUT_TIMEO;
+       }
+
+       conn->login_timeout = conn_rec->timeo.login_timeout;
+       if (!conn->login_timeout) {
+               conn_error(conn, "Invalid timeo.login_timeout. Must be greater "
+                         "than zero. Using default %d.",
+                         DEF_LOGIN_TIMEO);
+               conn->login_timeout = DEF_LOGIN_TIMEO;
+       }
+
+       conn->auth_timeout = conn_rec->timeo.auth_timeout;
+
+       /* noop-out setting */
+       conn->noop_out_interval = conn_rec->timeo.noop_out_interval;
+       conn->noop_out_timeout = conn_rec->timeo.noop_out_timeout;
+       if (conn->noop_out_interval && !conn->noop_out_timeout) {
+               conn_error(conn, "Invalid timeo.noop_out_timeout. Must be greater "
+                         "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) {
+               conn_error(conn, "Invalid timeo.noop_out_interval. Must be greater "
+                         "than zero. Using default %d.",
+                         DEF_NOOP_OUT_INTERVAL);
+               conn->noop_out_interval = DEF_NOOP_OUT_INTERVAL;
+       }
+
+       iscsi_copy_operational_params(conn, &session->nrec.session.iscsi,
+                                     &conn_rec->iscsi);
+
+       /* TCP options */
+       conn->tcp_window_size = conn_rec->tcp.window_size;
+       /* FIXME: type_of_service */
+
+       /* resolve the string address to an IP address */
+       err = iscsi_setup_portal(conn, conn_rec->address, conn_rec->port);
+       if (err)
+               return err;
+       return 0;
+}
+
+static void
+session_release(iscsi_session_t *session)
+{
+       log_debug(2, "Releasing session:%d %p", session->id, session);
+
+       if (session->target_alias)
+               free(session->target_alias);
+       iscsi_ev_context_free(&session->conn[0]);
+       free(session);
+}
+
+static iscsi_session_t*
+__session_create(node_rec_t *rec, struct iscsi_transport *t, int *rc)
+{
+       iscsi_session_t *session;
+       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);
+
+       INIT_LIST_HEAD(&session->list);
+       session->t = t;
+       session->reopen_qtask.mgmt_ipc_fd = -1;
+       session->id = INVALID_SESSION_ID;
+       session->use_ipc = 1;
+
+       /* save node record. we might need it for redirection */
+       memcpy(&session->nrec, rec, sizeof(node_rec_t));
+
+       session->portal_group_tag = rec->tpgt;
+       session->type = ISCSI_SESSION_TYPE_NORMAL;
+       session->r_stage = R_STAGE_NO_CHANGE;
+       strlcpy(session->target_name, rec->name, TARGET_NAME_MAXLEN);
+
+       if (strlen(session->nrec.iface.iname))
+               session->initiator_name = session->nrec.iface.iname;
+       else if (dconfig->initiator_name)
+               session->initiator_name = dconfig->initiator_name;
+       else {
+               log_error("No initiator name set. Cannot create session.");
+               *rc = ISCSI_ERR_INVAL;
+               goto free_session;
+       }
+
+       if (strlen(session->nrec.iface.alias))
+               session->initiator_alias = session->nrec.iface.alias;
+       else
+               session->initiator_alias = dconfig->initiator_alias;
+
+       /* session's eh parameters */
+       session->replacement_timeout = rec->session.timeo.replacement_timeout;
+       session->fast_abort = rec->session.iscsi.FastAbort;
+       session->abort_timeout = rec->session.err_timeo.abort_timeout;
+       session->lu_reset_timeout = rec->session.err_timeo.lu_reset_timeout;
+       session->tgt_reset_timeout = rec->session.err_timeo.tgt_reset_timeout;
+       session->host_reset_timeout = rec->session.err_timeo.host_reset_timeout;
+
+       /* OUI and uniqifying number */
+       session->isid[0] = DRIVER_ISID_0;
+       session->isid[1] = DRIVER_ISID_1;
+       session->isid[2] = DRIVER_ISID_2;
+       session->isid[3] = 0;
+       session->isid[4] = 0;
+       session->isid[5] = 0;
+
+       /* setup authentication variables for the session*/
+       iscsi_setup_authentication(session, &rec->session.auth);
+
+       iscsi_session_init_params(session);
+
+        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;
+                }
+        }
+
+       /* reset session reopen count */
+       session->reopen_cnt = 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)
+{
+       struct iscsi_ev_context *ev_context;
+       struct iscsi_conn *conn = &session->conn[0];
+       int i;
+
+       for (i = 0; i < CONTEXT_POOL_MAX; i++) {
+               ev_context = conn->context_pool[i];
+               if (!ev_context)
+                       continue;
+
+               if (ev_context->allocated) {
+                       actor_delete(&(conn->context_pool[i]->actor));
+                       iscsi_ev_context_put(ev_context);
+               }
+       }
+}
+
+static void
+__session_destroy(iscsi_session_t *session)
+{
+       log_debug(1, "destroying session:%d", session->id);
+       list_del(&session->list);
+       iscsi_flush_context_pool(session);
+       session_release(session);
+}
+
+static void
+conn_delete_timers(iscsi_conn_t *conn)
+{
+       actor_delete(&conn->login_timer);
+       actor_delete(&conn->nop_out_timer);
+}
+
+static int 
+session_conn_shutdown(iscsi_conn_t *conn, queue_task_t *qtask,
+                     int err)
+{
+       iscsi_session_t *session = conn->session;
+
+       conn_debug(2, conn, "disconnect conn");
+       /* this will check for a valid interconnect connection */
+       if (session->t->template->ep_disconnect)
+               session->t->template->ep_disconnect(conn);
+
+       if (session->id == INVALID_SESSION_ID)
+               goto cleanup;
+
+       if (!iscsi_sysfs_session_has_leadconn(session->id))
+               goto cleanup;
+
+       if (conn->state == ISCSI_CONN_STATE_IN_LOGIN ||
+           conn->state == ISCSI_CONN_STATE_IN_LOGOUT ||
+           conn->state == ISCSI_CONN_STATE_LOGGED_IN) {
+               conn_debug(2, conn, "stop conn (conn state %d)", conn->state);
+               if (ipc->stop_conn(session->t->handle, session->id,
+                                  conn->id, STOP_CONN_TERM)) {
+                       conn_error(conn, "can't stop connection (%d)", errno);
+                       return ISCSI_ERR_INTERNAL;
+               }
+       }
+
+       conn_debug(2, conn, "kdestroy conn");
+       if (ipc->destroy_conn(session->t->handle, session->id,
+               conn->id)) {
+               conn_error(conn, "can not safely destroy connection");
+               return ISCSI_ERR_INTERNAL;
+       }
+
+cleanup:
+       if (session->id != INVALID_SESSION_ID) {
+               log_debug(2, "kdestroy session %u", session->id);
+               session->r_stage = R_STAGE_SESSION_DESTOYED;
+               if (ipc->destroy_session(session->t->handle, session->id)) {
+                       log_error("can not safely destroy session %d",
+                                 session->id);
+                       return ISCSI_ERR_INTERNAL;
+               }
+       }
+
+       log_warning("Connection%d:%d to [target: %s, portal: %s,%d] "
+                   "through [iface: %s] is shutdown.",
+                   session->id, conn->id, session->nrec.name,
+                   session->nrec.conn[conn->id].address,
+                   session->nrec.conn[conn->id].port,
+                   session->nrec.iface.name);
+
+       mgmt_ipc_write_rsp(qtask, err);
+       conn_delete_timers(conn);
+       __session_destroy(session);
+       return ISCSI_SUCCESS;
+}
+
+static void
+queue_delayed_reopen(queue_task_t *qtask, int delay)
+{
+       iscsi_conn_t *conn = qtask->conn;
+
+       conn_debug(4, conn, "Requeue reopen attempt in %d secs", delay);
+
+       /*
+        * iscsi_login_eh can handle the login resched as
+        * if it were login time out
+        */
+       actor_timer_mod(&conn->login_timer, delay, qtask);
+}
+
+static int iscsi_conn_connect(struct iscsi_conn *conn, queue_task_t *qtask)
+{
+       struct iscsi_ev_context *ev_context;
+       int rc;
+
+       ev_context = iscsi_ev_context_get(conn, 0);
+       if (!ev_context) {
+               /* while reopening the recv pool should be full */
+               conn_error(conn, "BUG: __session_conn_reopen could not get conn "
+                         "context for recv.");
+               return ENOMEM;
+       }
+       ev_context->data = qtask;
+
+       rc = conn->session->t->template->ep_connect(conn, 1);
+       if (rc < 0 && errno != EINPROGRESS) {
+               char serv[NI_MAXSERV];
+
+               getnameinfo((struct sockaddr *) &conn->saddr,
+                           sizeof(conn->saddr),
+                           conn->host, sizeof(conn->host), serv, sizeof(serv),
+                           NI_NUMERICHOST|NI_NUMERICSERV);
+
+               conn_error(conn, "cannot make a connection to %s:%s (%d,%d)",
+                         conn->host, serv, rc, errno);
+               iscsi_ev_context_put(ev_context);
+               return ENOTCONN;
+       }
+
+       iscsi_sched_ev_context(ev_context, conn, 0, EV_CONN_POLL);
+       conn_debug(3, conn, "Setting login timer %p timeout %d", &conn->login_timer,
+                 conn->login_timeout);
+       actor_timer_mod(&conn->login_timer, conn->login_timeout, qtask);
+       return 0;
+}
+
+static void
+__session_conn_reopen(iscsi_conn_t *conn, queue_task_t *qtask, int do_stop,
+                     int redirected)
+{
+       iscsi_session_t *session = conn->session;
+       uint32_t delay;
+
+       log_debug(1, "re-opening session %d (reopen_cnt %d)", session->id,
+                       session->reopen_cnt);
+
+       qtask->conn = conn;
+
+       /* flush stale polls or errors queued */
+       iscsi_flush_context_pool(session);
+       conn_delete_timers(conn);
+       conn->state = ISCSI_CONN_STATE_XPT_WAIT;
+
+       conn->session->t->template->ep_disconnect(conn);
+       if (do_stop) {
+               /* state: ISCSI_CONN_STATE_CLEANUP_WAIT */
+               if (ipc->stop_conn(session->t->handle, session->id,
+                                  conn->id, do_stop)) {
+                       log_error("can't stop connection %d:%d (%d)",
+                                 session->id, conn->id, errno);
+                       delay = ISCSI_INTERNAL_ERR_REOPEN_DELAY;
+                       goto queue_reopen;
+               }
+               log_debug(3, "connection %d:%d is stopped for recovery",
+                         session->id, conn->id);
+       }
+
+       if (!redirected) {
+               delay = session->def_time2wait;
+               session->def_time2wait = 0;
+               if (delay)
+                       goto queue_reopen;
+       }
+
+       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;
+       }
+       return;
+
+queue_reopen:
+       conn_debug(4, conn, "Waiting %u seconds before trying to reconnect.", delay);
+       queue_delayed_reopen(qtask, delay);
+}
+
+static void
+session_conn_reopen(iscsi_conn_t *conn, queue_task_t *qtask, int do_stop)
+{
+       /*
+        * If we were temporarily redirected, we need to fall back to
+        * the original address to see where the target will send us
+        * for the retry
+        */
+       memset(&conn->saddr, 0, sizeof(struct sockaddr_storage));
+       conn->saddr = conn->failback_saddr;
+
+       __session_conn_reopen(conn, qtask, do_stop, 0);
+}
+
+static int iscsi_retry_initial_login(struct iscsi_conn *conn)
+{
+       int initial_login_retry_max;
+       struct timeval now, timeout, fail_time;
+
+       initial_login_retry_max =
+                       conn->session->nrec.session.initial_login_retry_max;
+
+       memset(&now, 0, sizeof(now));
+       memset(&timeout, 0, sizeof(timeout));
+       memset(&fail_time, 0, sizeof(fail_time));
+
+       timeout.tv_sec = initial_login_retry_max * conn->login_timeout;
+       if (gettimeofday(&now, NULL)) {
+               conn_error(conn, "Could not get time of day. Dropping down to "
+                         "max retry check.");
+               return initial_login_retry_max > conn->session->reopen_cnt;
+       }
+       timeradd(&conn->initial_connect_time, &timeout, &fail_time);
+
+       /*
+        * if we have been trying for login_retry_max * login_timeout
+        * then it is time to give up
+        */
+       if (timercmp(&now, &fail_time, >)) {
+               conn_debug(1, conn, "Giving up on initial login attempt after "
+                         "%u seconds.",
+                         initial_login_retry_max * conn->login_timeout);
+               return 0;
+       }
+
+       return 1;
+}
+
+static int iscsi_login_is_fatal_err(int err)
+{
+       if (err == ISCSI_ERR_LOGIN_AUTH_FAILED ||
+           err == ISCSI_ERR_FATAL_LOGIN)
+               return 1;
+       return 0;
+}
+
+static void iscsi_login_eh(struct iscsi_conn *conn, struct queue_task *qtask,
+                          int err)
+{
+       struct iscsi_session *session = conn->session;
+       int stop_flag = 0;
+
+       conn_debug(3, conn, "iscsi_login_eh");
+       /*
+        * Flush polls and other events
+        */
+       iscsi_flush_context_pool(conn->session);
+
+       switch (conn->state) {
+       case ISCSI_CONN_STATE_XPT_WAIT:
+               switch (session->r_stage) {
+               case R_STAGE_NO_CHANGE:
+                       conn_debug(6, conn, "login failed ISCSI_CONN_STATE_XPT_WAIT/"
+                                 "R_STAGE_NO_CHANGE");
+                       /* timeout during initial connect.
+                        * clean connection. write ipc rsp or retry */
+                       if (iscsi_login_is_fatal_err(err) ||
+                           !iscsi_retry_initial_login(conn))
+                               session_conn_shutdown(conn, qtask, err);
+                       else {
+                               stop_flag = (session->id < INVALID_SESSION_ID) ? STOP_CONN_TERM : 0;
+                               conn_debug(6, conn, "connection %p socket_fd: %d stop_flag: %d\n",
+                                         conn, conn->socket_fd, stop_flag);
+                               session_conn_reopen(conn, qtask, stop_flag);
+                       }
+                       break;
+               case R_STAGE_SESSION_REDIRECT:
+                       conn_debug(6, conn, "login failed ISCSI_CONN_STATE_XPT_WAIT/"
+                                 "R_STAGE_SESSION_REDIRECT");
+                       /* timeout during initial redirect connect
+                        * clean connection. write ipc rsp or retry */
+                       if (iscsi_login_is_fatal_err(err) ||
+                           !iscsi_retry_initial_login(conn))
+                               session_conn_shutdown(conn, qtask, err);
+                       else
+                               session_conn_reopen(conn, qtask, 0);
+                       break;
+               case R_STAGE_SESSION_REOPEN:
+                       conn_debug(6, conn, "login failed ISCSI_CONN_STATE_XPT_WAIT/"
+                                 "R_STAGE_SESSION_REOPEN (reopen_cnt=%d, reopen_max=%d)",
+                                 session->reopen_cnt, session->reopen_max);
+                       if (session->reopen_max &&
+                           (session->reopen_cnt > session->reopen_max)) {
+                               log_info("Giving up on session %d after %d retries", 
+                                               session->id, session->reopen_max);
+                               session_conn_shutdown(conn, qtask, err);
+                               break;
+                       }
+                       /* timeout during reopen connect. try again */
+                       session_conn_reopen(conn, qtask, 0);
+                       break;
+               case R_STAGE_SESSION_CLEANUP:
+                       session_conn_shutdown(conn, qtask, err);
+                       break;
+               default:
+                       break;
+               }
+
+               break;
+       case ISCSI_CONN_STATE_IN_LOGIN:
+               switch (session->r_stage) {
+               case R_STAGE_NO_CHANGE:
+               case R_STAGE_SESSION_REDIRECT:
+                       conn_debug(6, conn, "login failed ISCSI_CONN_STATE_IN_LOGIN/"
+                                 "R_STAGE_NO_CHANGE %d",
+                                 session->reopen_cnt);
+                       /*
+                        * send pdu timeout during initial connect or
+                        * initial redirected connect. Clean connection
+                        * and write rsp or retry.
+                        */
+                       if (iscsi_login_is_fatal_err(err) ||
+                           !iscsi_retry_initial_login(conn))
+                               session_conn_shutdown(conn, qtask, err);
+                       else
+                               session_conn_reopen(conn, qtask,
+                                                   STOP_CONN_RECOVER);
+                       break;
+               case R_STAGE_SESSION_REOPEN:
+                       conn_debug(6, conn, "login failed ISCSI_CONN_STATE_IN_LOGIN/"
+                                 "R_STAGE_SESSION_REOPEN %d",
+                                 session->reopen_cnt);
+                       session_conn_reopen(conn, qtask, STOP_CONN_RECOVER);
+                       break;
+               case R_STAGE_SESSION_CLEANUP:
+                       session_conn_shutdown(conn, qtask,
+                                             ISCSI_ERR_PDU_TIMEOUT);
+                       break;
+               default:
+                       break;
+               }
+
+               break;
+       default:
+               conn_error(conn, "Ignoring login error %d in conn state %d.",
+                         err, conn->state);
+               break;
+       }
+}
+
+static void
+__conn_error_handle(iscsi_session_t *session, iscsi_conn_t *conn)
+{
+       int i;
+
+       /*
+        * if we got an error while trying to logout for the user then
+        * just cleanup and return to the user.
+        */
+       if (conn->logout_qtask) {
+               session_conn_shutdown(conn, conn->logout_qtask, ISCSI_SUCCESS);
+               return;
+       }
+
+       switch (conn->state) {
+       case ISCSI_CONN_STATE_IN_LOGOUT:
+               /* logout was from eh - fall down to cleanup */
+       case ISCSI_CONN_STATE_LOGGED_IN:
+               /* mark failed connection */
+               conn->state = ISCSI_CONN_STATE_CLEANUP_WAIT;
+
+               if (session->erl > 0) {
+                       /* check if we still have some logged in connections */
+                       for (i=0; i<ISCSI_CONN_MAX; i++) {
+                               if (session->conn[i].state ==
+                                   ISCSI_CONN_STATE_LOGGED_IN)
+                                       break;
+                       }
+                       if (i != ISCSI_CONN_MAX) {
+                               /* FIXME: re-assign leading connection
+                                *        for ERL>0 */
+                       }
+
+                       break;
+               }
+
+               /* mark all connections as failed */
+               for (i=0; i<ISCSI_CONN_MAX; i++) {
+                       if (session->conn[i].state ==
+                           ISCSI_CONN_STATE_LOGGED_IN)
+                               session->conn[i].state =
+                                               ISCSI_CONN_STATE_CLEANUP_WAIT;
+               }
+               session->r_stage = R_STAGE_SESSION_REOPEN;
+               break;
+       case ISCSI_CONN_STATE_IN_LOGIN:
+               if (session->r_stage == R_STAGE_SESSION_REOPEN) {
+                       queue_task_t *qtask;
+
+                       if (session->notify_qtask)
+                               qtask = session->notify_qtask;
+                       else
+                               qtask = &session->reopen_qtask;
+                       iscsi_login_eh(conn, qtask, ISCSI_ERR_TRANS);
+                       return;
+               }
+               conn_debug(1, conn, "ignoring conn error in login. "
+                         "let it timeout");
+               return;
+       case ISCSI_CONN_STATE_XPT_WAIT:
+               conn_debug(1, conn, "ignoring conn error in XPT_WAIT. "
+                         "let connection fail on its own");
+               return;
+       case ISCSI_CONN_STATE_CLEANUP_WAIT:
+               conn_debug(1, conn, "ignoring conn error in CLEANUP_WAIT. "
+                         "let connection stop");
+               return;
+       default:
+               conn_debug(8, conn, "invalid state %d", conn->state);
+               return;
+       }
+
+       if (session->r_stage == R_STAGE_SESSION_REOPEN) {
+               session_conn_reopen(conn, &session->reopen_qtask,
+                                   STOP_CONN_RECOVER);
+               return;
+       }
+}
+
+static void session_conn_error(void *data)
+{
+       struct iscsi_ev_context *ev_context = data;
+       enum iscsi_err error = *(enum iscsi_err *)ev_context->data;
+       iscsi_conn_t *conn = ev_context->conn;
+       iscsi_session_t *session = conn->session;
+       int sid = session->id;
+
+       log_warning("Kernel reported iSCSI connection %d:%d error (%d - %s) "
+                   "state (%d)", session->id, conn->id, error,
+                   kern_err_code_to_string(error), conn->state);
+
+       iscsi_ev_context_put(ev_context);
+
+       switch (error) {
+       case ISCSI_ERR_INVALID_HOST:
+               if (session_conn_shutdown(conn, NULL, ISCSI_SUCCESS))
+                       log_error("BUG: Could not shutdown session:%d.", sid);
+               break;
+       default:
+               __conn_error_handle(session, conn);
+       }
+}
+
+static void iscsi_login_timedout(void *data)
+{
+       struct queue_task *qtask = data;
+       struct iscsi_conn *conn = qtask->conn;
+
+       switch (conn->state) {
+       case ISCSI_CONN_STATE_XPT_WAIT:
+               iscsi_login_eh(conn, qtask, ISCSI_ERR_TRANS_TIMEOUT);
+               break;
+       case ISCSI_CONN_STATE_IN_LOGIN:
+               iscsi_login_eh(conn, qtask, ISCSI_ERR_PDU_TIMEOUT);
+               break;
+       default:
+               iscsi_login_eh(conn, qtask, ISCSI_ERR_INTERNAL);
+               break;
+       }
+}
+
+static void iscsi_login_redirect(iscsi_conn_t *conn)
+{
+       iscsi_session_t *session = conn->session;
+       iscsi_login_context_t *c = &conn->login_context;
+
+       conn_debug(3, conn, "login redirect ...");
+
+       if (session->r_stage == R_STAGE_NO_CHANGE)
+               session->r_stage = R_STAGE_SESSION_REDIRECT;
+
+       __session_conn_reopen(conn, c->qtask, STOP_CONN_RECOVER, 1);
+}
+
+static int
+__send_nopin_rsp(iscsi_conn_t *conn, struct iscsi_nopin *rhdr, char *data)
+{
+       struct iscsi_nopout hdr;
+
+       memset(&hdr, 0, sizeof(struct iscsi_nopout));
+       hdr.opcode = ISCSI_OP_NOOP_OUT | ISCSI_OP_IMMEDIATE;
+       hdr.flags = ISCSI_FLAG_CMD_FINAL;
+       hdr.dlength[0] = rhdr->dlength[0];
+       hdr.dlength[1] = rhdr->dlength[1];
+       hdr.dlength[2] = rhdr->dlength[2];
+       memcpy(hdr.lun, rhdr->lun, 8);
+       hdr.ttt = rhdr->ttt;
+       hdr.itt = ISCSI_RESERVED_TAG;
+
+       return iscsi_io_send_pdu(conn, (struct iscsi_hdr*)&hdr,
+              ISCSI_DIGEST_NONE, data, ISCSI_DIGEST_NONE, 0);
+}
+
+static int
+__send_nopout(iscsi_conn_t *conn)
+{
+       struct iscsi_nopout hdr;
+
+       memset(&hdr, 0, sizeof(struct iscsi_nopout));
+       hdr.opcode = ISCSI_OP_NOOP_OUT | ISCSI_OP_IMMEDIATE;
+       hdr.flags = ISCSI_FLAG_CMD_FINAL;
+       hdr.itt = 0;  /* XXX: let kernel send_pdu set for us*/
+       hdr.ttt = ISCSI_RESERVED_TAG;
+       /* we have hdr.lun reserved, and no data */
+       return iscsi_io_send_pdu(conn, (struct iscsi_hdr*)&hdr,
+               ISCSI_DIGEST_NONE, NULL, ISCSI_DIGEST_NONE, 0);
+}
+
+static void conn_nop_out_timeout(void *data)
+{
+       iscsi_conn_t *conn = (iscsi_conn_t*)data;
+       iscsi_session_t *session = conn->session;
+
+       log_warning("Nop-out timedout after %d seconds on connection %d:%d "
+                   "state (%d). Dropping session.", conn->noop_out_timeout,
+                   session->id, conn->id, conn->state);
+       /* XXX: error handle */
+       __conn_error_handle(session, conn);
+}
+
+static void conn_send_nop_out(void *data)
+{
+       iscsi_conn_t *conn = data;
+
+       /*
+        * we cannot start new request during logout and the logout timer
+        * will figure things out.
+        */
+       if (conn->state == ISCSI_CONN_STATE_IN_LOGOUT)
+               return;
+
+       __send_nopout(conn);
+
+       actor_timer(&conn->nop_out_timer, conn->noop_out_timeout,
+                   conn_nop_out_timeout, conn);
+       conn_debug(3, conn, "noop out timeout timer %p start, timeout %d",
+                &conn->nop_out_timer, conn->noop_out_timeout);
+}
+
+void free_initiator(void)
+{
+       struct iscsi_transport *t;
+       iscsi_session_t *session, *tmp;
+
+       list_for_each_entry(t, &transports, list) {
+               list_for_each_entry_safe(session, tmp, &t->sessions, list) {
+                       list_del(&session->list);
+                       iscsi_flush_context_pool(session);
+                       session_release(session);
+               }
+       }
+
+       free_transports();
+}
+
+static void session_scan_host(struct iscsi_session *session, int hostno,
+                             queue_task_t *qtask)
+{
+       pid_t pid;
+
+       pid = iscsi_sysfs_scan_host(hostno, 1, idbm_session_autoscan(session));
+       if (pid == 0) {
+               mgmt_ipc_write_rsp(qtask, ISCSI_SUCCESS);
+
+               if (session)
+                       iscsi_sysfs_for_each_device(
+                                       &session->nrec.session.queue_depth,
+                                       hostno, session->id,
+                                       iscsi_sysfs_set_queue_depth);
+               exit(0);
+       } else if (pid > 0) {
+               reap_inc();
+               if (qtask && qtask->mgmt_ipc_fd >= 0) {
+                       close(qtask->mgmt_ipc_fd);
+                       free(qtask);
+               }
+       } else
+               mgmt_ipc_write_rsp(qtask, ISCSI_ERR_INTERNAL);
+}
+
+static void
+setup_full_feature_phase(iscsi_conn_t *conn)
+{
+       iscsi_session_t *session = conn->session;
+       iscsi_login_context_t *c = &conn->login_context;
+       int rc;
+
+       actor_delete(&conn->login_timer);
+
+       if (iscsi_session_set_neg_params(conn)) {
+               iscsi_login_eh(conn, c->qtask, ISCSI_ERR_LOGIN);
+               return;
+       }
+
+       if (ipc->start_conn(session->t->handle, session->id, conn->id,
+                           &rc) || rc) {
+               log_error("can't start connection %d:%d retcode %d (%d)",
+                         session->id, conn->id, rc, errno);
+               iscsi_login_eh(conn, c->qtask, ISCSI_ERR_INTERNAL);
+               return;
+       }
+
+       conn->state = ISCSI_CONN_STATE_LOGGED_IN;
+       if (session->r_stage == R_STAGE_NO_CHANGE ||
+           session->r_stage == R_STAGE_SESSION_REDIRECT) {
+               /*
+                * scan host is one-time deal. We
+                * don't want to re-scan it on recovery.
+                */
+               if (conn->id == 0)
+                       session_scan_host(session, session->hostno, c->qtask);
+
+               log_warning("Connection%d:%d to [target: %s, portal: %s,%d] "
+                           "through [iface: %s] is operational now",
+                           session->id, conn->id, session->nrec.name,
+                           session->nrec.conn[conn->id].address,
+                           session->nrec.conn[conn->id].port,
+                           session->nrec.iface.name);
+       } else {
+               session->notify_qtask = NULL;
+
+               session_online_devs(session->hostno, session->id);
+               mgmt_ipc_write_rsp(c->qtask, ISCSI_SUCCESS);
+               log_warning("connection%d:%d is operational after recovery "
+                           "(%d attempts)", session->id, conn->id,
+                            session->reopen_cnt);
+       }
+
+       /*
+        * reset ERL=0 reopen counter
+        */
+       session->reopen_cnt = 0;
+       session->r_stage = R_STAGE_NO_CHANGE;
+
+       /* noop_out */
+       if (conn->userspace_nop && conn->noop_out_interval) {
+               actor_timer(&conn->nop_out_timer, conn->noop_out_interval,
+                          conn_send_nop_out, conn);
+               conn_debug(3, conn, "noop out timer %p start",
+                         &conn->nop_out_timer);
+       }
+}
+
+static void iscsi_logout_timedout(void *data)
+{
+       struct iscsi_ev_context *ev_context = data;
+       struct iscsi_conn *conn = ev_context->conn;
+
+       iscsi_ev_context_put(ev_context);
+       /*
+        * assume we were in ISCSI_CONN_STATE_IN_LOGOUT or there
+        * was some nasty error
+        */
+       conn_debug(3, conn, "logout timeout, dropping conn...");
+       __conn_error_handle(conn->session, conn);
+}
+
+static int iscsi_send_logout(iscsi_conn_t *conn)
+{
+       struct iscsi_logout hdr;
+       struct iscsi_ev_context *ev_context;
+
+       if (conn->state != ISCSI_CONN_STATE_LOGGED_IN)
+               return EINVAL;
+
+       memset(&hdr, 0, sizeof(struct iscsi_logout));
+       hdr.opcode = ISCSI_OP_LOGOUT | ISCSI_OP_IMMEDIATE;
+       hdr.flags = ISCSI_FLAG_CMD_FINAL |
+          (ISCSI_LOGOUT_REASON_CLOSE_SESSION & ISCSI_FLAG_LOGOUT_REASON_MASK);
+       /* kernel will set the rest */
+
+       if (!iscsi_io_send_pdu(conn, (struct iscsi_hdr*)&hdr,
+                              ISCSI_DIGEST_NONE, NULL, ISCSI_DIGEST_NONE, 0))
+               return EIO;
+       conn->state = ISCSI_CONN_STATE_IN_LOGOUT;
+
+       ev_context = iscsi_ev_context_get(conn, 0);
+       if (!ev_context) {
+               /* unbounded logout */
+               log_warning("connection%d:%d Could not allocate conn context for logout.",
+                       conn->session->id, conn->id);
+               return ENOMEM;
+       } else {
+               iscsi_sched_ev_context(ev_context, conn,
+                                        conn->logout_timeout,
+                                        EV_CONN_LOGOUT_TIMER);
+               conn_debug(3, conn, "logout timeout timer %u",
+                         conn->logout_timeout * 1000);
+       }
+
+       return 0;
+}
+
+static void iscsi_stop(void *data)
+{
+       struct iscsi_ev_context *ev_context = data;
+       struct iscsi_conn *conn = ev_context->conn;
+       int rc = 0;
+       int sid = conn->session->id;
+
+       iscsi_ev_context_put(ev_context);
+
+       if (!(conn->session->t->caps & CAP_LOGIN_OFFLOAD)) {
+               rc = iscsi_send_logout(conn);
+               if (!rc)
+                       return;
+
+               conn_error(conn, "Could not send logout pdu(%s) from iscsi_stop. Dropping session",
+                          strerror(rc));
+       }
+
+       rc = session_conn_shutdown(conn, conn->logout_qtask, ISCSI_SUCCESS);
+       if (rc)
+               log_error("BUG: Could not shutdown session:%d.", sid);
+}
+
+static void iscsi_recv_nop_in(iscsi_conn_t *conn, struct iscsi_hdr *hdr)
+{
+       if (!conn->userspace_nop) {
+               conn_error(conn, "Got nop in, but kernel supports nop handling.");
+               return;
+       }
+
+       if (hdr->ttt == ISCSI_RESERVED_TAG) {
+               /* noop out rsp */
+               actor_delete(&conn->nop_out_timer);
+               /* schedule a new ping */
+               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,
+                                     conn->data)) {
+                       conn_error(conn, "can not send nopin response");
+               }
+}
+
+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;
+
+       conn_debug(3, conn, "Recv: logout response %d", logout_rsp->response);
+       if (logout_rsp->response == 2 || logout_rsp->response == 3) {
+               conn->session->def_time2wait = ntohs(logout_rsp->t2wait);
+               conn_debug(4, conn, "logout rsp returned time2wait %u",
+                         conn->session->def_time2wait);
+       }
+       /* TODO process the hdr */
+       __conn_error_handle(conn->session, conn);
+}
+
+static void iscsi_recv_async_msg(iscsi_conn_t *conn, struct iscsi_hdr *hdr)
+{
+       iscsi_session_t *session = conn->session;
+       struct iscsi_async *async_hdr = (struct iscsi_async *)hdr;
+       char *buf = conn->data;
+       unsigned int senselen;
+       struct scsi_sense_hdr sshdr;
+       int rc = 0;
+
+       conn_debug(3, conn, "Read AEN %d", async_hdr->async_event);
+
+       switch (async_hdr->async_event) {
+       case ISCSI_ASYNC_MSG_SCSI_EVENT:
+               senselen = (buf[0] << 8) | buf[1];
+               buf += 2;
+
+               if (!scsi_normalize_sense((uint8_t *)buf, senselen, &sshdr)) {
+                       conn_error(conn, "Could not handle AEN %d. Invalid sense.",
+                                 async_hdr->async_event);
+                       break;
+               }
+
+               if (sshdr.asc == 0x3f && sshdr.ascq == 0x0e
+                   && idbm_session_autoscan(session))
+                       session_scan_host(session, session->hostno, NULL);
+               break;
+       case ISCSI_ASYNC_MSG_REQUEST_LOGOUT:
+               conn_warn(conn, "Target requests logout within %u seconds" , ntohs(async_hdr->param3));
+               /*
+                * for ASYNC LOUOUT request, initiator would try to send a
+                * logout request and desire target's logout response, in
+                * logout response handler, initiator would call __conn_error_handle()
+                * to try to relogin.
+                *
+                * While if iscsi_send_logout() failed, we don't know what target
+                * would do, maybe target would close connection? Which would trigger
+                * initiator relogin too.
+                *
+                * Now we just print an error log to tell the iscsi_send_logout()
+                * failed and the failed reason, do nothing special.
+                */
+               rc = iscsi_send_logout(conn);
+               if (rc)
+                       conn_error(conn, "Could not send logout in response to logout request aen:%s",
+                                  strerror(rc));
+               break;
+       case ISCSI_ASYNC_MSG_DROPPING_CONNECTION:
+               conn_warn(conn, "Target dropping %u, reconnect min %u 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", 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:%d", session->id);
+               __conn_error_handle(session, conn);
+               break;
+       case ISCSI_ASYNC_MSG_VENDOR_SPECIFIC:
+       default:
+               log_warning("AEN not supported");
+       }
+}
+
+static void iscsi_recv_login_rsp(struct iscsi_conn *conn)
+{ 
+       struct iscsi_session *session = conn->session;
+       iscsi_login_context_t *c = &conn->login_context;
+       int err = ISCSI_ERR_FATAL_LOGIN;
+
+       if (iscsi_login_rsp(session, c)) {
+               conn_debug(1, conn, "login_rsp ret (%d)", c->ret);
+
+               switch (__login_response_status(conn, c->ret)) {
+               case CONN_LOGIN_FAILED:
+                       goto failed;
+               case CONN_LOGIN_RETRY:
+                       goto retry;
+               case CONN_LOGIN_IMM_REDIRECT_RETRY:
+                       iscsi_login_redirect(conn);
+                       return;
+               default:
+                       ; /* success - fall through */
+               }
+
+               /* check the login status */
+               switch (__check_iscsi_status_class(session, conn->id,
+                                                  c->status_class,
+                                                  c->status_detail)) {
+               case CONN_LOGIN_AUTH_FAILED:
+                       err = ISCSI_ERR_LOGIN_AUTH_FAILED;
+                       goto failed;
+               case CONN_LOGIN_FAILED:
+                       goto failed;
+               case CONN_LOGIN_IMM_REDIRECT_RETRY:
+                       iscsi_login_redirect(conn);
+                       return;
+               case CONN_LOGIN_IMM_RETRY:
+               case CONN_LOGIN_RETRY:
+                       goto retry;
+               default:
+                       ; /* success - fall through */
+               }
+       }
+
+       if (conn->current_stage != ISCSI_FULL_FEATURE_PHASE) {
+               /* more nego. needed! */
+               conn->state = ISCSI_CONN_STATE_IN_LOGIN;
+               if (iscsi_login_req(session, c)) {
+                       iscsi_login_eh(conn, c->qtask, ISCSI_ERR_LOGIN);
+                       return;
+               }
+       } else
+               setup_full_feature_phase(conn);
+
+       return;
+retry:
+       /* retry if not initial login or initial login has not timed out */
+       iscsi_login_eh(conn, c->qtask, ISCSI_ERR_LOGIN);
+       return;
+failed:
+       /* force failure if initial login */
+       session->reopen_cnt = session->nrec.session.initial_login_retry_max;
+       iscsi_login_eh(conn, c->qtask, err);
+       return;
+}
+
+static void session_conn_recv_pdu(void *data)
+{
+       struct iscsi_ev_context *ev_context = data;
+       iscsi_conn_t *conn = ev_context->conn;
+       struct iscsi_hdr hdr;
+
+       conn->recv_context = ev_context;
+
+       switch (conn->state) {
+       case ISCSI_CONN_STATE_IN_LOGIN:
+               iscsi_recv_login_rsp(conn);
+               break;
+       case ISCSI_CONN_STATE_LOGGED_IN:
+       case ISCSI_CONN_STATE_IN_LOGOUT:
+       case ISCSI_CONN_STATE_LOGOUT_REQUESTED:
+               /* read incoming PDU */
+               if (iscsi_io_recv_pdu(conn, &hdr, ISCSI_DIGEST_NONE,
+                                     conn->data, ISCSI_DEF_MAX_RECV_SEG_LEN,
+                                     ISCSI_DIGEST_NONE, 0) < 0)
+                       return;
+
+               switch (hdr.opcode & ISCSI_OPCODE_MASK) {
+               case ISCSI_OP_NOOP_IN:
+                       iscsi_recv_nop_in(conn, &hdr);
+                       break;
+               case ISCSI_OP_LOGOUT_RSP:
+                       iscsi_recv_logout_rsp(conn, &hdr);
+                       break;
+               case ISCSI_OP_ASYNC_EVENT:
+                       iscsi_recv_async_msg(conn, &hdr);
+                       break;
+               default:
+                       conn_error(conn, "unsupported opcode 0x%x", hdr.opcode);
+                       break;
+               }
+               break;
+       case ISCSI_CONN_STATE_XPT_WAIT:
+               iscsi_ev_context_put(ev_context);
+               conn_debug(1, conn, "ignoring incoming PDU in XPT_WAIT. "
+                         "let connection re-establish or fail");
+               break;
+       case ISCSI_CONN_STATE_CLEANUP_WAIT:
+               iscsi_ev_context_put(ev_context);
+               conn_debug(1, conn, "ignoring incoming PDU in XPT_WAIT. "
+                         "let connection cleanup");
+               break;
+       default:
+               iscsi_ev_context_put(ev_context);
+               conn_error(conn, "Invalid state %d. Dropping PDU.", conn->state);
+       }
+}
+
+static void session_increase_wq_priority(struct iscsi_session *session)
+{
+       DIR *proc_dir;
+       struct dirent *proc_dent;
+       struct stat statb;
+       char stat_file[PATH_SIZE];
+       char sbuf[1024];        /* got this from ps */
+       int pid, stat_fd, num_read;
+       char *proc_name, *proc_name_end;
+       uint32_t host_no;
+
+       /* drivers like bnx2i and qla4xxx do not have a write wq */
+       if (session->t->caps & CAP_DATA_PATH_OFFLOAD)
+               return;
+
+       proc_dir = opendir(PROC_DIR);
+       if (!proc_dir)
+               goto fail;
+
+       while ((proc_dent = readdir(proc_dir))) {
+               if (!strcmp(proc_dent->d_name, ".") ||
+                   !strcmp(proc_dent->d_name, ".."))
+                       continue;
+               if (sscanf(proc_dent->d_name, "%d", &pid) != 1)
+                       continue;
+
+               memset(stat_file, 0, sizeof(stat_file));
+               sprintf(stat_file, PROC_DIR"/%d/stat", pid);
+               if (stat(stat_file, &statb))
+                       continue;
+
+               if (!S_ISREG( statb.st_mode))
+                       continue;
+
+               stat_fd = open(stat_file, O_RDONLY);
+               if (stat_fd == -1)
+                       continue;
+
+               memset(sbuf, 0, sizeof(sbuf));
+               num_read = read(stat_fd, sbuf, sizeof(sbuf));
+               close(stat_fd);
+               if (num_read == -1)
+                       continue;
+               if (num_read == sizeof(sbuf))
+                       sbuf[num_read - 1] = '\0';
+               else
+                       sbuf[num_read] = '\0';
+
+               /*
+                * Finally match proc name to iscsi thread name.
+                * In newer kernels the name is iscsi_wq_%HOST_NO.
+                * In older kernels before 2.6.30, it was scsi_wq_%HOST_NO.
+                *
+                * We only support newer kernels.
+                */
+               proc_name = strchr(sbuf, '(') + 1;
+               if (!proc_name)
+                       continue;
+
+               proc_name_end = strchr(proc_name, ')');
+               if (!proc_name_end)
+                       continue;
+
+               *proc_name_end = '\0';
+
+               if (sscanf(proc_name, "iscsi_q_%u\n", &host_no) == 1) {
+                       if (host_no == session->hostno) {
+                               if (!setpriority(PRIO_PROCESS, pid,
+                                       session->nrec.session.xmit_thread_priority)) {
+                                       closedir(proc_dir);
+                                       return;
+                               } else
+                                       break;
+                       }
+               }
+       }
+       closedir(proc_dir);
+fail:
+       log_error("Could not set session%d priority. "
+                 "READ/WRITE throughout and latency could be "
+                 "affected.", session->id);
+}
+
+static int session_ipc_create(struct iscsi_session *session)
+{
+       struct iscsi_conn *conn = &session->conn[0];
+       int err = 0, pass_ep = 1;
+       uint32_t host_no = -1;
+
+       if (session->t->template->ep_connect != ktransport_ep_connect)
+               pass_ep = 0;
+retry_create:
+       err = ipc->create_session(session->t->handle,
+                                 pass_ep ? conn->transport_ep_handle : 0,
+                                 session->nrec.session.initial_cmdsn,
+                                 session->nrec.session.cmds_max,
+                                 session->nrec.session.queue_depth,
+                                 &session->id, &host_no);
+       /*
+        * Older kernels were not passed the sessions's leading conn ep,
+        * so we will get -EINVAL || -ENOSYS for iser.
+        *
+        * 2.6.22 and earlier would send -EINVAL instead of -ENOSYS.
+        */
+       if (pass_ep && (err == -ENOSYS || err == -EINVAL)) {
+               pass_ep = 0;
+               goto retry_create;
+       }
+
+       if (!err) {
+               session->hostno = host_no;
+               session_increase_wq_priority(session);
+       }
+       return err;
+}
+
+static void setup_offload_login_phase(iscsi_conn_t *conn)
+{
+       iscsi_session_t *session = conn->session;
+       iscsi_login_context_t *c = &conn->login_context;
+       int rc;
+
+       actor_delete(&conn->login_timer);
+
+       if (iscsi_session_set_params(conn)) {
+               iscsi_login_eh(conn, c->qtask, ISCSI_ERR_LOGIN);
+               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;
+       }
+
+       conn->state = ISCSI_CONN_STATE_IN_LOGIN;
+       if (ipc->start_conn(session->t->handle, session->id, conn->id,
+                           &rc) || rc) {
+               if (rc == -EEXIST) {
+                       conn_error(conn, "Session already exists.");
+                       session_conn_shutdown(conn, c->qtask,
+                                             ISCSI_ERR_SESS_EXISTS);
+               } else {
+                       log_error("can't start connection %d:%d retcode (%d)",
+                                 session->id, conn->id, rc);
+                       iscsi_login_eh(conn, c->qtask, ISCSI_ERR_INTERNAL);
+               }
+               return;
+       }
+
+       session->notify_qtask = c->qtask;
+}
+
+
+static void session_conn_poll(void *data)
+{
+       struct iscsi_ev_context *ev_context = data;
+       iscsi_conn_t *conn = ev_context->conn;
+       struct iscsi_session *session = conn->session;
+       int err = ISCSI_SUCCESS;
+       queue_task_t *qtask = ev_context->data;
+       iscsi_login_context_t *c = &conn->login_context;
+       int rc;
+
+       iscsi_ev_context_put(ev_context);
+
+       if (conn->state != ISCSI_CONN_STATE_XPT_WAIT)
+               return;
+
+       rc = session->t->template->ep_poll(conn, 1);
+       if (rc == 0) {
+               conn_debug(4, conn, "poll not connected %d", rc);
+               ev_context = iscsi_ev_context_get(conn, 0);
+               if (!ev_context) {
+                       /* while polling the recv pool should be full */
+                       conn_error(conn, "BUG: session_conn_poll could not get conn "
+                                 "context.");
+                       iscsi_login_eh(conn, qtask, ISCSI_ERR_INTERNAL);
+                       return;
+               }
+               ev_context->data = qtask;
+               /* 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));
+
+               /* do not allocate new connection in case of reopen */
+               if (session->id == INVALID_SESSION_ID) {
+                       if (conn->id == 0 && session_ipc_create(session)) {
+                               log_error("Can't create session.");
+                               err = ISCSI_ERR_INTERNAL;
+                               goto cleanup;
+                       }
+                       log_debug(3, "created new iSCSI session sid %d host "
+                                 "no %u", session->id, session->hostno);
+
+                       err = ipc->create_conn(session->t->handle,
+                                       session->id, conn->id, &conn->id);
+                       if (err) {
+                               log_error("Can't create connection for session%d.",
+                                       session->id);
+                               err = ISCSI_ERR_INTERNAL;
+                               goto cleanup;
+                       }
+                       log_debug(3, "created new iSCSI connection "
+                                 "%d:%d", session->id, conn->id);
+               }
+
+               iscsi_copy_operational_params(conn,
+                                       &session->nrec.session.iscsi,
+                                       &session->nrec.conn[conn->id].iscsi);
+               /*
+                * TODO: use the iface number or some other value
+                * so this will be persistent
+                */
+               session->isid[3] = (session->id >> 16) & 0xff;
+               session->isid[4] = (session->id >>  8) & 0xff;
+               session->isid[5] = session->id & 0xff;
+
+               if (ipc->bind_conn(session->t->handle, session->id,
+                                  conn->id, conn->transport_ep_handle,
+                                  (conn->id == 0), &rc) || rc) {
+                       log_error("can't bind conn %d:%d to session %d, "
+                                 "retcode %d (%d)", session->id, conn->id,
+                                  session->id, rc, errno);
+                       iscsi_login_eh(conn, qtask, ISCSI_ERR_LOGIN);
+                       return;
+               }
+               log_debug(3, "bound iSCSI connection %d:%d to session %d",
+                         session->id, conn->id, session->id);
+
+               c->qtask = qtask;
+               c->cid = conn->id;
+               c->buffer = conn->data;
+               c->bufsize = sizeof(conn->data);
+
+               conn->exp_statsn = iscsi_sysfs_get_exp_statsn(session->id);
+
+               if (session->t->caps & CAP_LOGIN_OFFLOAD) {
+                       setup_offload_login_phase(conn);
+                       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;
+               }
+
+               conn->state = ISCSI_CONN_STATE_IN_LOGIN;
+               if (iscsi_login_req(session, c)) {
+                       iscsi_login_eh(conn, qtask, ISCSI_ERR_LOGIN);
+                       return;
+               }
+       } else {
+               conn_debug(4, conn, "poll error %d", rc);
+               queue_delayed_reopen(qtask, ISCSI_CONN_ERR_REOPEN_DELAY);
+       }
+
+       return;
+
+cleanup:
+       session_conn_shutdown(conn, qtask, err);
+}
+
+static void session_conn_process_login(void *data)
+{
+       struct iscsi_ev_context *ev_context = data;
+       enum iscsi_conn_state state = *(enum iscsi_conn_state *)
+                                                       ev_context->data;
+       struct iscsi_conn *conn = ev_context->conn;
+       struct iscsi_session *session = conn->session;
+       iscsi_login_context_t *c = &conn->login_context;
+       queue_task_t *qtask;
+
+       iscsi_ev_context_put(ev_context);
+       if (!(session->t->caps & CAP_LOGIN_OFFLOAD))
+               return;
+
+       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
+        * logged in
+        */
+       log_debug(3, "session created sid %u host no %d", session->id,
+                 session->hostno);
+
+       if (session->r_stage == R_STAGE_NO_CHANGE ||
+           session->r_stage == R_STAGE_SESSION_REDIRECT) {
+               /*
+                * scan host is one-time deal. We
+                * don't want to re-scan it on recovery.
+                */
+               session_scan_host(session, session->hostno,
+                                c->qtask);
+               session->notify_qtask = NULL;
+
+               log_warning("Connection%d:%d to [target: %s, portal: %s,%d] "
+                           "through [iface: %s] is operational now",
+                           session->id, conn->id, session->nrec.name,
+                           session->nrec.conn[conn->id].address,
+                           session->nrec.conn[conn->id].port,
+                           session->nrec.iface.name);
+       } else {
+               session->notify_qtask = NULL;
+               mgmt_ipc_write_rsp(c->qtask, ISCSI_SUCCESS);
+       }
+
+       /*
+        * reset ERL=0 reopen counter
+        */
+       session->reopen_cnt = 0;
+       session->r_stage = R_STAGE_NO_CHANGE;
+
+       return;
+
+failed_login:
+       qtask = session->notify_qtask;
+       session->notify_qtask = NULL;
+       mgmt_ipc_write_rsp(qtask, ISCSI_ERR_LOGIN);
+       if (ipc->destroy_conn(session->t->handle, session->id, conn->id))
+               log_error("can not safely destroy connection%d:%d",
+                       session->id, conn->id);
+       if (ipc->destroy_session(session->t->handle, session->id))
+               log_error("can not safely destroy session %d", session->id);
+       __session_destroy(session);
+
+}
+
+static int iscsi_sched_ev_context(struct iscsi_ev_context *ev_context,
+                                 struct iscsi_conn *conn, unsigned long tmo,
+                                 int event)
+{
+       enum iscsi_err error;
+
+       conn_debug(7, conn, "sched conn context %p event %d, tmo %lu",
+                 &ev_context->actor, event, tmo);
+
+       ev_context->conn = conn;
+       switch (event) {
+       case EV_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_init(&ev_context->actor, session_conn_error,
+                         ev_context);
+               /*
+                * We handle invalid host, by killing the session.
+                * It must go at the head of the queue, so we do not
+                * initiate error handling or logout or some other op.
+                */
+               if (error == ISCSI_ERR_INVALID_HOST)
+                       actor_schedule_head(&ev_context->actor);
+               else
+                       actor_schedule(&ev_context->actor);
+               break;
+       case EV_CONN_LOGIN:
+               actor_init(&ev_context->actor, session_conn_process_login,
+                         ev_context);
+               actor_schedule(&ev_context->actor);
+               break;
+       case EV_CONN_POLL:
+               actor_timer(&ev_context->actor, tmo,
+                           session_conn_poll, ev_context);
+               break;
+       case EV_CONN_LOGOUT_TIMER:
+               actor_timer(&ev_context->actor, tmo,
+                           iscsi_logout_timedout, ev_context);
+               break;
+       case EV_CONN_STOP:
+               actor_init(&ev_context->actor, iscsi_stop,
+                         ev_context);
+               actor_schedule(&ev_context->actor);
+               break;
+       default:
+               conn_error(conn, "Invalid event type %d.", event);
+       }
+       return 0;
+}
+
+static iscsi_session_t* session_find_by_rec(node_rec_t *rec)
+{
+       struct iscsi_transport *t;
+       iscsi_session_t *session;
+
+       list_for_each_entry(t, &transports, list) {
+               list_for_each_entry(session, &t->sessions, list) {
+                       if (__iscsi_match_session(rec, session->nrec.name,
+                                        session->nrec.conn[0].address,
+                                        session->nrec.conn[0].port,
+                                        &session->nrec.iface,
+                                        MATCH_ANY_SID))
+                               return session;
+               }
+       }
+       return NULL;
+}
+
+/*
+ * a session could be running in the kernel but not in iscsid
+ * due to a resync or because some other app started the session
+ */
+static int session_is_running(node_rec_t *rec)
+{
+       int nr_found = 0;
+
+       if (session_find_by_rec(rec))
+               return 1;
+
+       if (iscsi_sysfs_for_each_session(rec, &nr_found, iscsi_match_session,
+                                        0))
+               return 1;
+
+       return 0;
+}
+
+static int __session_login_task(node_rec_t *rec, queue_task_t *qtask)
+{
+       iscsi_session_t *session;
+       iscsi_conn_t *conn;
+       struct iscsi_transport *t;
+       int rc;
+
+       if (session_is_running(rec)) {
+               if (rec->session.multiple)
+                       log_debug(2, "Adding a copy of an existing session");
+               else
+                       return ISCSI_ERR_SESS_EXISTS;
+       }
+
+       t = iscsi_sysfs_get_transport_by_name(rec->iface.transport_name);
+       if (!t)
+               return ISCSI_ERR_TRANS_NOT_FOUND;
+
+       if ((!(t->caps & CAP_RECOVERY_L0) &&
+            rec->session.iscsi.ERL != 0) ||
+           (!(t->caps & CAP_RECOVERY_L1) &&
+            rec->session.iscsi.ERL > 1)) {
+               log_error("Transport '%s' does not support ERL %d."
+                         "Setting ERL to ERL0.",
+                         t->name, rec->session.iscsi.ERL);
+               rec->session.iscsi.ERL = 0;
+       }
+
+       if (!(t->caps & CAP_MULTI_R2T) &&
+           rec->session.iscsi.MaxOutstandingR2T) {
+               log_error("Transport '%s' does not support "
+                         "MaxOutstandingR2T %d. Setting "
+                         "MaxOutstandingR2T to 1.", t->name,
+                         rec->session.iscsi.MaxOutstandingR2T);
+               rec->session.iscsi.MaxOutstandingR2T = 1;               
+       }
+
+       if (!(t->caps & CAP_HDRDGST) &&
+           rec->conn[0].iscsi.HeaderDigest) {
+               log_error("Transport '%s' does not support "
+                         "HeaderDigest != None. Setting HeaderDigest "
+                         "to None.", t->name);
+               rec->conn[0].iscsi.HeaderDigest = CONFIG_DIGEST_NEVER;
+       }
+
+       if (!(t->caps & CAP_DATADGST) &&
+           rec->conn[0].iscsi.DataDigest) {
+               log_error("Transport '%s' does not support "
+                         "DataDigest != None. Setting DataDigest "
+                         "to None", t->name);
+               rec->conn[0].iscsi.DataDigest = CONFIG_DIGEST_NEVER;
+       }
+
+       if (!(t->caps & CAP_MARKERS) &&
+           rec->conn[0].iscsi.IFMarker) {
+               log_error("Transport '%s' does not support IFMarker. "
+                         "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.", t->name);
+               rec->conn[0].iscsi.OFMarker = 0;
+       }
+
+       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" */
+
+       /* create leading connection */
+       rc = __session_conn_create(session, 0);
+       if (rc) {
+               __session_destroy(session);
+               return rc;
+       }
+       conn = &session->conn[0];
+       qtask->conn = conn;
+
+       rc = iscsi_host_set_net_params(&rec->iface, session);
+       if (rc == ISCSI_ERR_AGAIN) {
+               /*
+                * host/iscsiuio not ready. Cannot block iscsid, so caller is
+                * going to internally retry the operation.
+                */
+               __session_destroy(session);
+               return ISCSI_ERR_HOST_NOT_FOUND;
+       } else if (rc) {
+               __session_destroy(session);
+               return ISCSI_ERR_LOGIN;
+       }
+
+       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;
+       qtask->rsp.command = MGMT_IPC_SESSION_LOGIN;
+       qtask->rsp.err = ISCSI_SUCCESS;
+
+       if (iscsi_conn_connect(conn, qtask)) {
+               log_debug(4, "Initial connect failed. Waiting %u seconds "
+                         "before trying to reconnect.",
+                         ISCSI_CONN_ERR_REOPEN_DELAY);
+               queue_delayed_reopen(qtask, ISCSI_CONN_ERR_REOPEN_DELAY);
+       }
+
+       return ISCSI_SUCCESS;
+}
+
+int
+session_login_task(node_rec_t *rec, queue_task_t *qtask)
+{
+       int rc;
+
+       rc = __session_login_task(rec, qtask);
+       if (rc == ISCSI_ERR_HOST_NOT_FOUND) {
+               rc = queue_session_login_task_retry(NULL, rec, qtask);
+               if (rc)
+                       return rc;
+               /*
+                * we are going to internally retry. Will return final rc
+                * when completed
+                */
+               return ISCSI_SUCCESS;
+       }
+       return rc;
+}
+
+static void session_login_task_retry(void *data)
+{
+       struct login_task_retry_info *info = data;
+       struct node_rec *rec = info->rec;
+       int rc;
+
+       rc = __session_login_task(rec, info->qtask);
+       if (rc == ISCSI_ERR_HOST_NOT_FOUND) {
+               if (info->retry_count == rec->conn[0].timeo.login_timeout) {
+                       /* give up */
+                       goto write_rsp;
+               }
+
+               rc = queue_session_login_task_retry(info, rec, info->qtask);
+               if (rc)
+                       goto write_rsp;
+               /* we are going to internally retry */
+               return;
+       } else if (rc) {
+               /* hard error - no retry */
+               goto write_rsp;
+       } else
+               /* successfully started login operation */
+               goto free;
+write_rsp:
+       mgmt_ipc_write_rsp(info->qtask, rc);
+free:
+       free(info);
+}
+
+static int queue_session_login_task_retry(struct login_task_retry_info *info,
+                                         node_rec_t *rec, queue_task_t *qtask)
+{
+       if (!info) {
+               info = malloc(sizeof(*info));
+               if (!info)
+                       return ISCSI_ERR_NOMEM;
+               memset(info, 0, sizeof(*info));
+               info->qtask = qtask;
+               info->rec = rec;
+       }
+
+       info->retry_count++;
+       log_debug(4, "queue session setup attempt in %d secs, retries %d",
+                 1, info->retry_count);
+       actor_timer(&info->retry_actor, 1, session_login_task_retry, info);
+       return 0;
+}
+
+static int
+sync_conn(iscsi_session_t *session, uint32_t cid)
+{
+       iscsi_conn_t *conn;
+       int rc;
+
+       rc = __session_conn_create(session, cid);
+       if (rc)
+               return rc;
+       conn = &session->conn[cid];
+
+       /* TODO: must export via sysfs so we can pick this up */
+       conn->state = ISCSI_CONN_STATE_CLEANUP_WAIT;
+       return 0;
+}
+
+int
+iscsi_sync_session(node_rec_t *rec, queue_task_t *qtask, uint32_t sid)
+{
+       iscsi_session_t *session;
+       struct iscsi_transport *t;
+       int err;
+
+       session = session_find_by_sid(sid);
+       if (session != NULL)
+               return ISCSI_ERR_SESS_EXISTS;
+
+       t = iscsi_sysfs_get_transport_by_name(rec->iface.transport_name);
+       if (!t)
+               return ISCSI_ERR_TRANS_NOT_FOUND;
+
+       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", sid);
+               goto destroy_session;
+       }
+
+       session->r_stage = R_STAGE_SESSION_REOPEN;
+
+       err = sync_conn(session, 0);
+       if (err)
+               goto destroy_session;
+
+       qtask->rsp.command = MGMT_IPC_SESSION_SYNC;
+
+       log_debug(3, "Started sync iSCSI session %d", session->id);
+       session->notify_qtask = qtask;
+       session_conn_reopen(&session->conn[0], qtask,
+                           STOP_CONN_RECOVER);
+
+       return 0;
+
+destroy_session:
+       __session_destroy(session);
+       log_error("Could not sync session%d err %d", sid, err);
+       return err;
+}
+
+static int session_unbind(struct iscsi_session *session)
+{
+       int err;
+
+       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 %d.", session->id, err);
+       return err;
+}
+
+int session_logout_task(int sid, queue_task_t *qtask)
+{
+       iscsi_session_t *session;
+       iscsi_conn_t *conn;
+       int rc = ISCSI_SUCCESS;
+
+       session = session_find_by_sid(sid);
+       if (!session) {
+                log_debug(1, "session sid %d not found.", sid);
+               return ISCSI_ERR_SESS_NOT_FOUND;
+       }
+       conn = &session->conn[0];
+
+       /*
+        * If syncing up, in XPT_WAIT, and REOPENing, then return
+        * an informative error, since the target for this session
+        * is likely not connected
+        */
+       if (session->notify_qtask &&
+           (conn->state == ISCSI_CONN_STATE_XPT_WAIT) &&
+           (session->r_stage == R_STAGE_SESSION_REOPEN)) {
+               log_warning("session %d cannot be terminted because "
+                           "it's trying to reconnect: try again later",
+                       session->id);
+               return ISCSI_ERR_SESSION_NOT_CONNECTED;
+       }
+
+       /*
+        * If syncing up and not reconnecting,
+        * or if this is the initial login and mgmt_ipc
+        * has not been notified of that result fail the logout request
+        */
+       if (session->notify_qtask ||
+           ((conn->state == ISCSI_CONN_STATE_XPT_WAIT ||
+             conn->state == ISCSI_CONN_STATE_IN_LOGIN) &&
+           (session->r_stage == R_STAGE_NO_CHANGE ||
+            session->r_stage == R_STAGE_SESSION_REDIRECT))) {
+invalid_state:
+               log_error("session %d in invalid state for logout. "
+                          "Try again later", session->id);
+               return ISCSI_ERR_INTERNAL;
+       }
+
+       if (dconfig->safe_logout && session_in_use(sid)) {
+               log_error("Session %d is actively in use for mounted storage, "
+                         "and iscsid.safe_logout is configured.", session->id);
+               return ISCSI_ERR_BUSY;
+       }
+
+       /* FIXME: logout all active connections */
+       conn = &session->conn[0];
+       if (conn->logout_qtask)
+               goto invalid_state;
+
+       qtask->conn = conn;
+       qtask->rsp.command = MGMT_IPC_SESSION_LOGOUT;
+       conn->logout_qtask = qtask;
+
+       switch (conn->state) {
+       case ISCSI_CONN_STATE_LOGGED_IN:
+               if (!session_unbind(session))
+                       return ISCSI_SUCCESS;
+
+               /* LLDs that offload login also offload logout */
+               if (!(session->t->caps & CAP_LOGIN_OFFLOAD)) {
+                       /* unbind is not supported so just do old logout */
+                       rc = iscsi_send_logout(conn);
+                       if (!rc)
+                               return ISCSI_SUCCESS;
+               }
+
+               conn_error(conn, "Could not send logout pdu(%s) from session_logout_task. Dropping session",
+                          strerror(rc));
+               /* fallthrough */
+       default:
+               rc = session_conn_shutdown(conn, qtask, ISCSI_SUCCESS);
+               break;
+       }
+
+       return rc;
+}
+
+int
+iscsi_host_send_targets(__attribute__((unused))queue_task_t *qtask,
+                       int host_no,
+                       __attribute__((unused))int do_login,
+                       struct sockaddr_storage *ss)
+{
+       struct iscsi_transport *t;
+
+       t = iscsi_sysfs_get_transport_by_hba(host_no);
+       if (!t) {
+               log_error("Invalid host no %d for sendtargets", host_no);
+               return ISCSI_ERR_TRANS_NOT_FOUND;
+       }
+       if (!(t->caps & CAP_SENDTARGETS_OFFLOAD))
+               return ISCSI_ERR_TRANS_CAPS;
+
+       if (ipc->sendtargets(t->handle, host_no, (struct sockaddr *)ss))
+               return ISCSI_ERR;
+
+       return ISCSI_SUCCESS;
+}
+
+/*
+ * HW drivers like qla4xxx present an interface that hides most of the iscsi
+ * details. Userspace sends down a discovery event then it gets notified
+ * if the sessions that were logged in as a result asynchronously, or
+ * the card will have sessions preset in the FLASH and will log into them
+ * automaotically then send us notification that a session is setup.
+ */
+static void iscsi_async_session_creation(uint32_t host_no, uint32_t sid)
+{
+       struct iscsi_transport *transport;
+
+       transport = iscsi_sysfs_get_transport_by_hba(host_no);
+       if (!transport)
+               return;
+
+       if (!(transport->caps & CAP_FW_DB))
+               return;
+
+       log_debug(3, "session created sid %u host no %d", sid, host_no);
+       session_online_devs(host_no, sid);
+       session_scan_host(NULL, host_no, NULL);
+}
+
+static void iscsi_async_session_destruction(uint32_t host_no, uint32_t sid)
+{
+       log_debug(3, "session destroyed sid %u host no %d", sid, host_no);
+}
+
+static struct iscsi_ipc_ev_clbk ipc_clbk = {
+       .create_session         = iscsi_async_session_creation,
+       .destroy_session        = iscsi_async_session_destruction,
+       .get_ev_context         = iscsi_ev_context_get,
+       .put_ev_context         = iscsi_ev_context_put,
+       .sched_ev_context       = iscsi_sched_ev_context,
+};
+
+void iscsi_initiator_init(void)
+{
+       ipc_register_ev_callback(&ipc_clbk);
+}
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/initiator.h b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/initiator.h
new file mode 100644 (file)
index 0000000..0222797
--- /dev/null
@@ -0,0 +1,413 @@
+/*
+ * iSCSI Initiator
+ *
+ * Copyright (C) 2004 Dmitry Yusupov, Alex Aizman
+ * 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 INITIATOR_H
+#define INITIATOR_H
+
+#include <stdint.h>
+#include <net/if.h>
+#include <sys/time.h>
+
+#include "types.h"
+#include "iscsi_proto.h"
+#include "iscsi_if.h"
+#include "auth.h"
+#include "mgmt_ipc.h"
+#include "config.h"
+#include "actor.h"
+#include "list.h"
+#include "log.h"
+
+#ifndef ISCSI_CONFIG_ROOT
+#define ISCSI_CONFIG_ROOT      "/etc/iscsi/"
+#endif
+
+#define CONFIG_FILE            ISCSI_CONFIG_ROOT"/iscsid.conf"
+#define INITIATOR_NAME_FILE    ISCSI_CONFIG_ROOT"/initiatorname.iscsi"
+
+#define PID_FILE               "/run/iscsid.pid"
+
+#ifndef LOCK_DIR
+#define LOCK_DIR               "/run/lock/iscsi"
+#endif
+
+#define LOCK_FILE              LOCK_DIR"/lock"
+#define LOCK_WRITE_FILE                LOCK_DIR"/lock.write"
+
+#define conn_info(conn, fmt, ...)                              \
+do {                                                           \
+       if (conn->session == NULL) {                            \
+               log_info(fmt, ##__VA_ARGS__);                   \
+               break;                                          \
+       }                                                       \
+       log_info("connection%d:%d " fmt,                        \
+                  conn->session->id, conn->id, ##__VA_ARGS__); \
+} while(0)
+
+#define conn_warn(conn, fmt, ...)                              \
+do {                                                           \
+       if (conn->session == NULL) {                            \
+               log_warning(fmt, ##__VA_ARGS__);                \
+               break;                                          \
+       }                                                       \
+       log_warning("connection%d:%d " fmt,                     \
+                  conn->session->id, conn->id, ##__VA_ARGS__); \
+} while(0)
+
+#define conn_error(conn, fmt, ...)                             \
+do {                                                           \
+       if (conn->session == NULL) {                            \
+               log_error(fmt, ##__VA_ARGS__);                  \
+               break;                                          \
+       }                                                       \
+       log_error("connection%d:%d " fmt,                       \
+                  conn->session->id, conn->id, ##__VA_ARGS__); \
+} while(0)
+
+#define conn_debug(level, conn, fmt, ...)                      \
+do {                                                           \
+       if (conn->session == NULL) {                            \
+               log_debug(level, fmt, ##__VA_ARGS__);           \
+               break;                                          \
+       }                                                       \
+       log_debug(level, "connection%d:%d " fmt,                \
+                  conn->session->id, conn->id, ##__VA_ARGS__); \
+} while(0)
+
+typedef enum iscsi_session_r_stage_e {
+       R_STAGE_NO_CHANGE,
+       R_STAGE_SESSION_CLEANUP,
+       R_STAGE_SESSION_REOPEN,
+       R_STAGE_SESSION_REDIRECT,
+       R_STAGE_SESSION_DESTOYED,
+} iscsi_session_r_stage_e;
+
+typedef enum conn_login_status_e {
+       CONN_LOGIN_SUCCESS              = 0,
+       CONN_LOGIN_FAILED               = 1,
+       CONN_LOGIN_IO_ERR               = 2,
+       CONN_LOGIN_RETRY                = 3,
+       CONN_LOGIN_IMM_RETRY            = 4,
+       CONN_LOGIN_IMM_REDIRECT_RETRY   = 5,
+       CONN_LOGIN_AUTH_FAILED          = 6,
+} conn_login_status_e;
+
+enum iscsi_login_status {
+       LOGIN_OK                        = 0,
+       LOGIN_IO_ERROR                  = 1,
+       LOGIN_FAILED                    = 2,
+       LOGIN_VERSION_MISMATCH          = 3,
+       LOGIN_NEGOTIATION_FAILED        = 4,
+       LOGIN_AUTHENTICATION_FAILED     = 5,
+       LOGIN_REDIRECTION_FAILED        = 6,
+       LOGIN_INVALID_PDU               = 7,
+       LOGIN_REDIRECT                  = 8,
+};
+
+typedef enum iscsi_event_e {
+       EV_UNKNOWN,
+       EV_CONN_RECV_PDU,
+       EV_CONN_POLL,
+       EV_CONN_ERROR,
+       EV_CONN_LOGOUT_TIMER,
+       EV_CONN_STOP,
+       EV_CONN_LOGIN,
+} iscsi_event_e;
+
+struct queue_task;
+
+typedef struct iscsi_login_context {
+       int cid;
+       char *buffer;
+       size_t bufsize;
+       uint8_t status_class;
+       uint8_t status_detail;
+       struct iscsi_acl *auth_client;
+       struct iscsi_hdr pdu;
+       struct iscsi_login_rsp *login_rsp;
+       char *data;
+       int received_pdu;
+       int max_data_length;
+       int timeout;
+       int final;
+       enum iscsi_login_status ret;
+       struct queue_task *qtask;
+} iscsi_login_context_t;
+
+struct iscsi_session;
+struct iscsi_conn;
+struct iscsi_ev_context;
+
+/* daemon's connection structure */
+typedef struct iscsi_conn {
+       uint32_t id;
+       struct iscsi_session *session;
+       iscsi_login_context_t login_context;
+       struct iscsi_ev_context *recv_context;
+       struct queue_task *logout_qtask;
+       char data[ISCSI_DEF_MAX_RECV_SEG_LEN];
+       char host[NI_MAXHOST];  /* scratch */
+       enum iscsi_conn_state state;
+       int userspace_nop;
+
+       struct timeval initial_connect_time;
+       actor_t login_timer;
+       actor_t nop_out_timer;
+
+#define CONTEXT_POOL_MAX 32
+       struct iscsi_ev_context *context_pool[CONTEXT_POOL_MAX];
+
+       /* login state machine */
+       int current_stage;
+       int next_stage;
+       int partial_response;
+       conn_login_status_e status;
+
+       /* tcp/socket settings */
+
+       /*
+        * Either a tcp/ip or a netlink socket to do
+        * IO through.
+        */
+       int socket_fd;
+       /* address being used for normal session connection */
+       struct sockaddr_storage saddr;
+       /* address received during login */
+       struct sockaddr_storage failback_saddr;
+       int tcp_window_size;
+       int type_of_service;
+
+       /* used for the IPC of bind and for connect/poll/disconnect by
+         * transports (eg iser) which does these ops from the kernel.
+         * In the case of TCP, it is just the transport_fd casted to u64. */
+       uint64_t transport_ep_handle;
+       int bind_ep;
+
+       /* timeouts */
+       int login_timeout;
+       int logout_timeout;
+       int auth_timeout;
+       int active_timeout;
+
+       int noop_out_interval;
+       int noop_out_timeout;
+
+       /* sequencing */
+       uint32_t exp_statsn;
+
+       /* negotiated parameters */
+       uint32_t hdrdgst_en;
+       uint32_t datadgst_en;
+       uint32_t max_recv_dlength;      /* the value we declare */
+       uint32_t max_xmit_dlength;      /* the value declared by the target */
+} iscsi_conn_t;
+
+struct iscsi_ev_context {
+       struct actor actor;
+       struct iscsi_conn *conn;
+       int allocated;
+       void *data;
+};
+
+typedef struct queue_task {
+       iscsi_conn_t *conn;
+       iscsiadm_req_t req;
+       iscsiadm_rsp_t rsp;
+       int mgmt_ipc_fd;
+       int allocated : 1;
+       /* Newer request types include a
+        * variable-length payload */
+       void *payload;
+} queue_task_t;
+
+struct iscsi_transport_template;
+struct iscsi_transport;
+
+/* daemon's session structure */
+typedef struct iscsi_session {
+       struct list_head list;
+       uint32_t id;
+       uint32_t hostno;
+       char netdev[IFNAMSIZ];
+       struct iscsi_transport *t;
+       uint8_t use_ipc;
+       node_rec_t nrec; /* copy of original Node record in database */
+       unsigned int irrelevant_keys_bitmap;
+       int send_async_text;
+       uint32_t itt;
+       uint32_t cmdsn;
+       uint32_t exp_cmdsn;
+       uint32_t max_cmdsn;
+       int erl;
+       uint32_t imm_data_en;
+       uint32_t initial_r2t_en;
+       uint32_t max_r2t;
+       uint32_t fast_abort;
+       uint32_t first_burst;
+       uint32_t max_burst;
+       uint32_t pdu_inorder_en;
+       uint32_t dataseq_inorder_en;
+       uint32_t def_time2wait;
+       uint32_t def_time2retain;
+       int type;
+       int portal_group_tag;
+       uint8_t isid[6];
+       uint16_t tsih;
+       char target_name[TARGET_NAME_MAXLEN + 1];
+       char *target_alias;
+       char *initiator_name;
+       char *initiator_alias;
+       struct auth_str_block auth_recv_string_block;
+       struct auth_str_block auth_send_string_block;
+       struct auth_large_binary auth_recv_binary_block;
+       struct auth_large_binary auth_send_binary_block;
+       struct iscsi_acl auth_client_block;
+       struct iscsi_acl *auth_client;
+       int num_auth_buffers;
+       struct auth_buffer_desc auth_buffers[5];
+       int bidirectional_auth;
+       char username[AUTH_STR_MAX_LEN];
+       uint8_t password[AUTH_STR_MAX_LEN];
+       int password_length;
+       char username_in[AUTH_STR_MAX_LEN];
+       uint8_t password_in[AUTH_STR_MAX_LEN];
+       int password_in_length;
+       unsigned int chap_algs[AUTH_CHAP_ALG_MAX_COUNT];
+       iscsi_conn_t conn[ISCSI_CONN_MAX];
+       uint64_t param_mask;
+
+       /* connection reopens during recovery */
+       int reopen_cnt;
+       int reopen_max;
+       queue_task_t reopen_qtask;
+       iscsi_session_r_stage_e r_stage;
+       uint32_t replacement_timeout;
+
+       int host_reset_timeout;
+       int tgt_reset_timeout;
+       int lu_reset_timeout;
+       int abort_timeout;
+
+       /*
+        * used for hw and sync up to notify caller that the operation
+        * is complete
+        */
+       queue_task_t *notify_qtask;
+} iscsi_session_t;
+
+#define        INVALID_SESSION_ID      (uint32_t)-1
+
+/* login.c */
+
+#define ISCSI_SESSION_TYPE_NORMAL 0
+#define ISCSI_SESSION_TYPE_DISCOVERY 1
+
+/* not defined by iSCSI, but used in the login code to determine
+ * when to send the initial Login PDU
+ */
+#define ISCSI_INITIAL_LOGIN_STAGE -1
+
+#define ISCSI_TEXT_SEPARATOR     '='
+
+/* implemented in iscsi-login.c for use on all platforms */
+extern int iscsi_add_text(struct iscsi_hdr *hdr, char *data, int max_data_length,
+                       char *param, char *value);
+extern enum iscsi_login_status iscsi_login(iscsi_session_t *session, int cid,
+                  char *buffer, size_t bufsize, uint8_t * status_class,
+                  uint8_t * status_detail);
+extern int iscsi_update_address(iscsi_conn_t *conn, char *address);
+extern int iscsi_login_begin(iscsi_session_t *session,
+                            iscsi_login_context_t *c);
+extern int iscsi_login_req(iscsi_session_t *session, iscsi_login_context_t *c);
+extern int iscsi_login_rsp(iscsi_session_t *session, iscsi_login_context_t *c);
+extern int resolve_address(char *host, char *port, struct sockaddr_storage *ss);
+
+/* Digest types */
+#define ISCSI_DIGEST_NONE  0
+#define ISCSI_DIGEST_CRC32C 1
+#define ISCSI_DIGEST_CRC32C_NONE 2     /* offer both, prefer CRC32C */
+#define ISCSI_DIGEST_NONE_CRC32C 3     /* offer both, prefer None */
+
+#define IRRELEVANT_MAXCONNECTIONS      0x01
+#define IRRELEVANT_INITIALR2T          0x02
+#define IRRELEVANT_IMMEDIATEDATA       0x04
+#define IRRELEVANT_MAXBURSTLENGTH      0x08
+#define IRRELEVANT_FIRSTBURSTLENGTH    0x10
+#define IRRELEVANT_MAXOUTSTANDINGR2T   0x20
+#define IRRELEVANT_DATAPDUINORDER      0x40
+#define IRRELEVANT_DATASEQUENCEINORDER 0x80
+
+
+/*
+ * These user/kernel IPC calls are used by transports (eg iSER) that have their
+ * native connection managed from the kernel. The IPC for having the user space
+ * code being able to do it, is implemented as an enhancement of the open iscsi
+ * netlink IPC scheme, currently with the ability to connect/poll-for-establish
+ * ment/disconnect an opaque transport dependent 64 bit ep (endpoint) handle.
+ * The exact IPC ABI for that matter is defined in iscsi_if.h
+ */
+/* netlink.c */
+extern int ktransport_ep_connect(iscsi_conn_t *conn, int non_blocking);
+extern int ktransport_ep_poll(iscsi_conn_t *conn, int timeout_ms);
+extern void ktransport_ep_disconnect(iscsi_conn_t *conn);
+
+/* io.c */
+extern int iscsi_io_tcp_poll(iscsi_conn_t *conn, int timeout_ms);
+extern int iscsi_io_tcp_connect(iscsi_conn_t *conn, int non_blocking);
+extern void iscsi_io_tcp_disconnect(iscsi_conn_t *conn);
+
+extern int iscsi_io_connect(iscsi_conn_t *conn);
+extern void iscsi_io_disconnect(iscsi_conn_t *conn);
+extern int iscsi_io_send_pdu(iscsi_conn_t *conn, struct iscsi_hdr *hdr,
+              int hdr_digest, char *data, int data_digest, int timeout);
+extern int iscsi_io_recv_pdu(iscsi_conn_t *conn, struct iscsi_hdr *hdr,
+       int hdr_digest, char *data, int max_data_length, int data_digest,
+       int timeout);
+
+/* initiator.c */
+extern int session_login_task(node_rec_t *rec, queue_task_t *qtask);
+extern int session_logout_task(int sid, queue_task_t *qtask);
+extern iscsi_session_t *session_find_by_sid(uint32_t sid);
+extern int iscsi_sync_session(node_rec_t *rec, queue_task_t
+                                        *tsk, uint32_t sid);
+extern int iscsi_host_send_targets(queue_task_t *qtask,
+                       int host_no, int do_login, struct sockaddr_storage *ss);
+
+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,
+                                    struct iscsi_session *session);
+extern void iscsi_copy_operational_params(struct iscsi_conn *conn,
+                       struct iscsi_session_operational_config *session_conf,
+                       struct iscsi_conn_operational_config *conn_conf);
+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);
+
+extern int session_in_use(int sid);
+#endif /* INITIATOR_H */
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/initiator_common.c b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/initiator_common.c
new file mode 100644 (file)
index 0000000..bc69fbd
--- /dev/null
@@ -0,0 +1,734 @@
+/*
+ * Common code for setting up discovery and normal sessions.
+ *
+ * Copyright (C) 2004 Dmitry Yusupov, Alex Aizman
+ * Copyright (C) 2006 - 2009 Mike Christie
+ * Copyright (C) 2006 - 2009 Red Hat, Inc. All rights reserved.
+ * 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 <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <dirent.h>
+#include <libmount/libmount.h>
+
+#include "initiator.h"
+#include "transport.h"
+#include "iscsid.h"
+#include "iscsi_ipc.h"
+#include "log.h"
+#include "iscsi_sysfs.h"
+#include "iscsi_settings.h"
+#include "iface.h"
+#include "host.h"
+#include "sysdeps.h"
+#include "iscsi_err.h"
+#include "iscsi_net_util.h"
+
+struct iscsi_session *session_find_by_sid(uint32_t sid)
+{
+       struct iscsi_transport *t;
+       struct iscsi_session *session;
+
+       list_for_each_entry(t, &transports, list) {
+               list_for_each_entry(session, &t->sessions, list) {
+                       if (session->id == sid)
+                               return session;
+               }
+       }
+       return NULL;
+}
+
+static unsigned int align_32_down(unsigned int param)
+{
+       return param & ~0x3;
+}
+
+int iscsi_setup_authentication(struct iscsi_session *session,
+                              struct iscsi_auth_config *auth_cfg)
+{
+       /* if we have any incoming credentials, we insist on authenticating
+        * the target or not logging in at all
+        */
+       if (auth_cfg->username_in[0] || auth_cfg->password_in_length) {
+               /* sanity check the config */
+               if (auth_cfg->password_length == 0) {
+                       log_warning("CHAP configuration has incoming "
+                                   "authentication credentials but has no "
+                                   "outgoing credentials configured.");
+                       return EINVAL;
+               }
+               session->bidirectional_auth = 1;
+       } else {
+               /* no or 1-way authentication */
+               session->bidirectional_auth = 0;
+       }
+
+       /* copy in whatever credentials we have */
+       strlcpy(session->username, auth_cfg->username,
+               sizeof (session->username));
+       session->username[sizeof (session->username) - 1] = '\0';
+       if ((session->password_length = auth_cfg->password_length))
+               memcpy(session->password, auth_cfg->password,
+                      session->password_length);
+
+       strlcpy(session->username_in, auth_cfg->username_in,
+               sizeof (session->username_in));
+       session->username_in[sizeof (session->username_in) - 1] = '\0';
+       if ((session->password_in_length =
+            auth_cfg->password_in_length))
+               memcpy(session->password_in, auth_cfg->password_in,
+                      session->password_in_length);
+
+       memcpy(session->chap_algs, auth_cfg->chap_algs, sizeof(auth_cfg->chap_algs));
+
+       if (session->password_length || session->password_in_length) {
+               /* setup the auth buffers */
+               session->auth_buffers[0].address = &session->auth_client_block;
+               session->auth_buffers[0].length =
+                   sizeof (session->auth_client_block);
+               session->auth_buffers[1].address =
+                   &session->auth_recv_string_block;
+               session->auth_buffers[1].length =
+                   sizeof (session->auth_recv_string_block);
+
+               session->auth_buffers[2].address =
+                   &session->auth_send_string_block;
+               session->auth_buffers[2].length =
+                   sizeof (session->auth_send_string_block);
+
+               session->auth_buffers[3].address =
+                   &session->auth_recv_binary_block;
+               session->auth_buffers[3].length =
+                   sizeof (session->auth_recv_binary_block);
+
+               session->auth_buffers[4].address =
+                   &session->auth_send_binary_block;
+               session->auth_buffers[4].length =
+                   sizeof (session->auth_send_binary_block);
+
+               session->num_auth_buffers = 5;
+               log_debug(6, "authentication setup complete...");
+       } else {
+               session->num_auth_buffers = 0;
+               log_debug(6, "no authentication configured...");
+       }
+
+       return 0;
+}
+
+void
+iscsi_copy_operational_params(struct iscsi_conn *conn,
+                       struct iscsi_session_operational_config *session_conf,
+                       struct iscsi_conn_operational_config *conn_conf)
+{
+       struct iscsi_session *session = conn->session;
+       struct iscsi_transport *t = session->t;
+
+       conn->hdrdgst_en = conn_conf->HeaderDigest;
+       conn->datadgst_en = conn_conf->DataDigest;
+
+       conn->max_recv_dlength =
+                       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",
+                         ISCSI_MIN_MAX_RECV_SEG_LEN,
+                         ISCSI_MAX_MAX_RECV_SEG_LEN,
+                         DEF_INI_MAX_RECV_SEG_LEN);
+               conn_conf->MaxRecvDataSegmentLength =
+                                               DEF_INI_MAX_RECV_SEG_LEN;
+               conn->max_recv_dlength = DEF_INI_MAX_RECV_SEG_LEN;
+       }
+
+       /* zero indicates to use the target's value */
+       conn->max_xmit_dlength =
+                       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",
+                         ISCSI_MIN_MAX_RECV_SEG_LEN,
+                         ISCSI_MAX_MAX_RECV_SEG_LEN,
+                         DEF_INI_MAX_RECV_SEG_LEN);
+               conn_conf->MaxXmitDataSegmentLength =
+                                               DEF_INI_MAX_RECV_SEG_LEN;
+               conn->max_xmit_dlength = DEF_INI_MAX_RECV_SEG_LEN;
+       }
+
+       /* session's operational parameters */
+       session->initial_r2t_en = session_conf->InitialR2T;
+       session->max_r2t = session_conf->MaxOutstandingR2T;
+       session->imm_data_en = session_conf->ImmediateData;
+       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
+        * initial r2t = Yes, so we always check the user values.
+        */
+       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",
+                         session->first_burst,
+                         ISCSI_MIN_FIRST_BURST_LEN,
+                         ISCSI_MAX_FIRST_BURST_LEN,
+                         DEF_INI_FIRST_BURST_LEN);
+               session_conf->FirstBurstLength = DEF_INI_FIRST_BURST_LEN;
+               session->first_burst = DEF_INI_FIRST_BURST_LEN;
+       }
+
+       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",
+                          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;
+               session->max_burst = DEF_INI_MAX_BURST_LEN;
+       }
+
+       if (session->first_burst > session->max_burst) {
+               log_error("Invalid iscsi.FirstBurstLength of %u. Must be "
+                         "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;
+       }
+
+       session->def_time2wait = session_conf->DefaultTime2Wait;
+       session->def_time2retain = session_conf->DefaultTime2Retain;
+       session->erl = session_conf->ERL;
+
+       if (session->type == ISCSI_SESSION_TYPE_DISCOVERY) {
+               /*
+                * Right now, we only support 8K max for kernel based
+                * sendtargets discovery, because the recv pdu buffers are
+                * limited to this size.
+                */
+               if ((t->caps & CAP_TEXT_NEGO) &&
+                    conn->max_recv_dlength > ISCSI_DEF_MAX_RECV_SEG_LEN)
+                       conn->max_recv_dlength = ISCSI_DEF_MAX_RECV_SEG_LEN;
+
+               /* We do not support discovery sessions with digests */
+               conn->hdrdgst_en = ISCSI_DIGEST_NONE;
+               conn->datadgst_en = ISCSI_DIGEST_NONE;
+       }
+
+       if (t->template->create_conn)
+               t->template->create_conn(conn);
+}
+
+int iscsi_setup_portal(struct iscsi_conn *conn, char *address, int port)
+{
+       char serv[NI_MAXSERV];
+
+       sprintf(serv, "%d", port);
+       if (resolve_address(address, serv, &conn->saddr)) {
+               log_error("cannot resolve host name %s", address);
+               return ISCSI_ERR_TRANS;
+       }
+       conn->failback_saddr = conn->saddr;
+
+       getnameinfo((struct sockaddr *)&conn->saddr, sizeof(conn->saddr),
+                   conn->host, sizeof(conn->host), NULL, 0, NI_NUMERICHOST);
+       log_debug(4, "resolved %s to %s", address, conn->host);
+       return 0;
+}
+
+static int host_set_param(struct iscsi_transport *t,
+                  uint32_t host_no, int param, char *value,
+                  int type)
+{
+       int rc;
+
+       rc = ipc->set_host_param(t->handle, host_no, param, value, type);
+       /* 2.6.20 and below returns EINVAL */
+       if (rc && rc != -ENOSYS && rc != -EINVAL) {
+               log_error("can't set operational parameter %d for "
+                         "host %d, retcode %d (%d)", param, host_no,
+                         rc, errno);
+               return ISCSI_ERR_INVAL;
+       }
+       return 0;
+}
+
+static void print_param_value(enum iscsi_param param, void *value, int type)
+{
+       if (type == ISCSI_STRING)
+               log_debug(3, "set operational parameter %d to %s", param, value ? (char *)value : "NULL");
+       else
+               log_debug(3, "set operational parameter %d to %u", param, *(uint32_t *)value);
+}
+
+#define MAX_HOST_PARAMS 2
+
+int iscsi_host_set_params(struct iscsi_session *session)
+{
+       struct iscsi_transport *t = session->t;
+       int i;
+       struct hostparam {
+               int param;
+               int type;
+               void *value;
+       } hosttbl[MAX_HOST_PARAMS] = {
+               {
+                       .param = ISCSI_HOST_PARAM_NETDEV_NAME,
+                       .value = session->nrec.iface.netdev,
+                       .type = ISCSI_STRING,
+               }, {
+                       .param = ISCSI_HOST_PARAM_HWADDRESS,
+                       .value = session->nrec.iface.hwaddress,
+                       .type = ISCSI_STRING,
+               },
+       };
+
+       for (i = 0; i < MAX_HOST_PARAMS; i++) {
+               if (host_set_param(t, session->hostno,
+                                  hosttbl[i].param, hosttbl[i].value,
+                                  hosttbl[i].type)) {
+                       return EPERM;
+               }
+
+               print_param_value(hosttbl[i].param, hosttbl[i].value,
+                                 hosttbl[i].type);
+       }
+
+       return 0;
+}
+
+static inline void iscsi_session_clear_param(struct iscsi_session *session,
+                                            int param)
+{
+       session->param_mask &= ~(1ULL << param);
+}
+
+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;
+       int i, rc;
+       uint32_t zero = 0;
+       struct connparam {
+               int param;
+               int type;
+               void *value;
+               int conn_only;
+       } conntbl[MAX_SESSION_NEG_PARAMS] = {
+               {
+                       .param = ISCSI_PARAM_MAX_RECV_DLENGTH,
+                       .value = &conn->max_recv_dlength,
+                       .type = ISCSI_INT,
+                       .conn_only = 0,
+               }, {
+                       .param = ISCSI_PARAM_MAX_XMIT_DLENGTH,
+                       .value = &conn->max_xmit_dlength,
+                       .type = ISCSI_INT,
+                       .conn_only = 0,
+               }, {
+                       .param = ISCSI_PARAM_HDRDGST_EN,
+                       .value = &conn->hdrdgst_en,
+                       .type = ISCSI_INT,
+                       .conn_only = 0,
+               }, {
+                       .param = ISCSI_PARAM_DATADGST_EN,
+                       .value = &conn->datadgst_en,
+                       .type = ISCSI_INT,
+                       .conn_only = 1,
+               }, {
+                       .param = ISCSI_PARAM_INITIAL_R2T_EN,
+                       .value = &session->initial_r2t_en,
+                       .type = ISCSI_INT,
+                       .conn_only = 0,
+               }, {
+                       .param = ISCSI_PARAM_MAX_R2T,
+                       .value = &session->max_r2t,
+                       .type = ISCSI_INT,
+                       .conn_only = 0,
+               }, {
+                       .param = ISCSI_PARAM_IMM_DATA_EN,
+                       .value = &session->imm_data_en,
+                       .type = ISCSI_INT,
+                       .conn_only = 0,
+               }, {
+                       .param = ISCSI_PARAM_FIRST_BURST,
+                       .value = &session->first_burst,
+                       .type = ISCSI_INT,
+                       .conn_only = 0,
+               }, {
+                       .param = ISCSI_PARAM_MAX_BURST,
+                       .value = &session->max_burst,
+                       .type = ISCSI_INT,
+                       .conn_only = 0,
+               }, {
+                       .param = ISCSI_PARAM_PDU_INORDER_EN,
+                       .value = &session->pdu_inorder_en,
+                       .type = ISCSI_INT,
+                       .conn_only = 0,
+               }, {
+                       .param =ISCSI_PARAM_DATASEQ_INORDER_EN,
+                       .value = &session->dataseq_inorder_en,
+                       .type = ISCSI_INT,
+                       .conn_only = 0,
+               }, {
+                       .param = ISCSI_PARAM_ERL,
+                       .value = &zero, /* FIXME: session->erl */
+                       .type = ISCSI_INT,
+                       .conn_only = 0,
+               }, {
+                       .param = ISCSI_PARAM_IFMARKER_EN,
+                       .value = &zero,/* FIXME: session->ifmarker_en */
+                       .type = ISCSI_INT,
+                       .conn_only = 0,
+               }, {
+                       .param = ISCSI_PARAM_OFMARKER_EN,
+                       .value = &zero,/* FIXME: session->ofmarker_en */
+                       .type = ISCSI_INT,
+                       .conn_only = 0,
+               }, {
+                       .param = ISCSI_PARAM_EXP_STATSN,
+                       .value = &conn->exp_statsn,
+                       .type = ISCSI_UINT,
+                       .conn_only = 1,
+               }, {
+                       .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,
+                       .type = ISCSI_STRING,
+                       .conn_only = 1,
+               }, {
+                       .param = ISCSI_PARAM_PERSISTENT_PORT,
+                       .value = &session->nrec.conn[conn->id].port,
+                       .type = ISCSI_INT,
+                       .conn_only = 1,
+               }, {
+                       .param = ISCSI_PARAM_SESS_RECOVERY_TMO,
+                       .value = &session->replacement_timeout,
+                       .type = ISCSI_INT,
+                       .conn_only = 0,
+               }, {
+                       .param = ISCSI_PARAM_USERNAME,
+                       .value = session->username,
+                       .type = ISCSI_STRING,
+                       .conn_only = 0,
+               }, {
+                       .param = ISCSI_PARAM_USERNAME_IN,
+                       .value = session->username_in,
+                       .type = ISCSI_STRING,
+                       .conn_only = 0,
+               }, {
+                       .param = ISCSI_PARAM_PASSWORD,
+                       .value = session->password,
+                       .type = ISCSI_STRING,
+                       .conn_only = 0,
+               }, {
+                       .param = ISCSI_PARAM_PASSWORD_IN,
+                       .value = session->password_in,
+                       .type = ISCSI_STRING,
+                       .conn_only = 0,
+               }, {
+                       .param = ISCSI_PARAM_FAST_ABORT,
+                       .value = &session->fast_abort,
+                       .type = ISCSI_INT,
+                       .conn_only = 0,
+               }, {
+                       .param = ISCSI_PARAM_ABORT_TMO,
+                       .value = &session->abort_timeout,
+                       .type = ISCSI_INT,
+                       .conn_only = 0,
+               }, {
+                       .param = ISCSI_PARAM_LU_RESET_TMO,
+                       .value = &session->lu_reset_timeout,
+                       .type = ISCSI_INT,
+                       .conn_only = 0,
+               }, {
+                       .param = ISCSI_PARAM_TGT_RESET_TMO,
+                       .value = &session->tgt_reset_timeout,
+                       .type = ISCSI_INT,
+                       .conn_only = 0,
+               }, {
+                       .param = ISCSI_PARAM_PING_TMO,
+                       .value = &conn->noop_out_timeout,
+                       .type = ISCSI_INT,
+                       .conn_only = 1,
+               }, {
+                       .param = ISCSI_PARAM_RECV_TMO,
+                       .value = &conn->noop_out_interval,
+                       .type = ISCSI_INT,
+                       .conn_only = 1,
+               }, {
+                       .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,
+               },
+       };
+
+       iscsi_session_init_params(session);
+
+       /* some llds will send nops internally */
+       if (!iscsi_sysfs_session_supports_nop(session->id)) {
+               iscsi_session_clear_param(session, ISCSI_PARAM_PING_TMO); 
+               iscsi_session_clear_param(session, ISCSI_PARAM_RECV_TMO);
+       }
+
+       /* Entered full-feature phase! */
+       for (i = 0; i < MAX_SESSION_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;
+               }
+
+               if (rc == -ENOSYS) {
+                       switch (conntbl[i].param) {
+                       case ISCSI_PARAM_PING_TMO:
+                               /*
+                                * older kernels may not support nops
+                                * in kernel
+                                */
+                               conn->userspace_nop = 1;
+                               break;
+#if 0
+TODO handle this
+                       case ISCSI_PARAM_INITIATOR_NAME:
+                               /* use host level one instead */
+                               hosttbl[ISCSI_HOST_PARAM_INITIATOR_NAME].set = 1;
+                               break;
+#endif
+                       }
+               }
+
+               print_param_value(conntbl[i].param, conntbl[i].value,
+                                 conntbl[i].type);
+       }
+
+       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)
+{
+       struct iscsi_transport *t = session->t;
+       int rc = 0;
+       char *netdev;
+       struct host_info hinfo;
+
+       log_debug(3, "setting iface %s, dev %s, set ip %s, hw %s, "
+                 "transport %s.",
+                 iface->name, iface->netdev, iface->ipaddress,
+                 iface->hwaddress, iface->transport_name);
+
+       if (!t->template->set_host_ip)
+               return 0;
+
+       /* if we need to set the ip addr then set all the iface net settings */
+       if (!iface_is_bound_by_ipaddr(iface)) {
+               if (t->template->set_host_ip == SET_HOST_IP_REQ) {
+                       log_warning("Please set the iface.ipaddress for iface "
+                                   "%s, then retry the login command.",
+                                   iface->name);
+                       return ISCSI_ERR_INVAL;
+               } else if (t->template->set_host_ip == SET_HOST_IP_OPT) {
+                       log_info("Optional iface.ipaddress for iface %s "
+                                "not set.", iface->name);
+                       return 0;
+               } else {
+                       return ISCSI_ERR_INVAL;
+               }
+       }
+
+       /* these type of drivers need the netdev upd */
+       if (strlen(iface->netdev))
+               netdev = iface->netdev;
+       else {
+               memset(&hinfo, 0, sizeof(hinfo));
+               hinfo.host_no = session->hostno;
+               iscsi_sysfs_get_hostinfo_by_host_no(&hinfo);
+
+               netdev = hinfo.iface.netdev;
+       }
+
+       if (!t->template->no_netdev && net_ifup_netdev(netdev))
+               log_warning("Could not brining up netdev %s. Try running "
+                           "'ifup %s' first if login fails.", netdev, netdev);
+
+       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);
+       if (rc)
+               return rc;
+
+       if (iface_is_bound_by_netdev(iface)) {
+               rc = host_set_param(t, session->hostno,
+                                   ISCSI_HOST_PARAM_NETDEV_NAME,
+                                   iface->netdev, ISCSI_STRING);
+               if (rc)
+                       return rc;
+       }
+
+       if (iface_is_bound_by_hwaddr(iface)) {
+               rc = host_set_param(t, session->hostno,
+                                   ISCSI_HOST_PARAM_HWADDRESS,
+                                   iface->hwaddress, ISCSI_STRING);
+               if (rc)
+                       return rc;
+       }
+       return 0;
+}
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/io.c b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/io.c
new file mode 100644 (file)
index 0000000..a46c9f8
--- /dev/null
@@ -0,0 +1,876 @@
+/*
+ * iSCSI I/O Library
+ *
+ * Copyright (C) 2002 Cisco Systems, Inc.
+ * maintained by linux-iscsi-devel@lists.sourceforge.net
+ *
+ * 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 <stdint.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdio.h>
+#include <signal.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <sys/ioctl.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <sys/uio.h>
+
+#include "types.h"
+#include "iscsi_proto.h"
+#include "iscsi_settings.h"
+#include "initiator.h"
+#include "iscsi_ipc.h"
+#include "log.h"
+#include "transport.h"
+#include "idbm.h"
+#include "iface.h"
+#include "sysdeps.h"
+
+#define LOG_CONN_CLOSED(conn) \
+do { \
+       getnameinfo((struct sockaddr *) &conn->saddr, sizeof(conn->saddr), \
+                   conn->host, sizeof(conn->host), NULL, 0, NI_NUMERICHOST); \
+       log_error("Connection to Discovery Address %s closed", conn->host); \
+} while (0)
+
+#define LOG_CONN_FAIL(conn) \
+do { \
+       getnameinfo((struct sockaddr *) &conn->saddr, sizeof(conn->saddr), \
+                   conn->host, sizeof(conn->host), NULL, 0, NI_NUMERICHOST); \
+       log_error("Connection to Discovery Address %s failed", conn->host); \
+} while (0)
+
+static int timedout;
+
+static void
+sigalarm_handler(__attribute__((unused))int unused)
+{
+       timedout = 1;
+}
+
+static void
+set_non_blocking(int fd)
+{
+       int res = fcntl(fd, F_GETFL);
+
+       if (res != -1) {
+               res = fcntl(fd, F_SETFL, res | O_NONBLOCK);
+               if (res)
+                       log_warning("unable to set fd flags (%s)!",
+                                   strerror(errno));
+       } else
+               log_warning("unable to get fd flags (%s)!", strerror(errno));
+
+}
+
+#if 0
+/* not used by anyone */
+static int get_hwaddress_from_netdev(char *netdev, char *hwaddress)
+{
+       struct ifaddrs *ifap, *ifa;
+       struct sockaddr_in *s4;
+       struct sockaddr_in6 *s6;
+       struct ifreq if_hwaddr;
+       int found = 0, sockfd;
+       unsigned char *hwaddr;
+       char buf[INET6_ADDRSTRLEN];
+
+       if (getifaddrs(&ifap)) {
+               log_error("Could not match hwaddress %s to netdev. "
+                         "getifaddrs failed %d", hwaddress, errno);
+               return 0;
+       }
+
+       /* Open a basic socket. */
+       sockfd = socket(AF_INET, SOCK_DGRAM, 0);
+       if (sockfd < 0) {
+               log_error("Could not open socket for ioctl.");
+               goto free_ifap;
+       }
+
+       for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+               if (!ifa->ifa_addr)
+                       continue;
+
+               switch (ifa->ifa_addr->sa_family) {
+               case AF_INET:
+                       s4 = (struct sockaddr_in *)(ifa->ifa_addr);
+                       if (!inet_ntop(ifa->ifa_addr->sa_family,
+                                     (void *)&(s4->sin_addr), buf,
+                                     INET_ADDRSTRLEN))
+                               continue;
+                       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", ifa->ifa_name, buf);
+                       break;
+               default:
+                       continue;
+               }
+
+               if (strcmp(ifa->ifa_name, netdev))
+                       continue;
+
+               strncpy(if_hwaddr.ifr_name, ifa->ifa_name, IFNAMSIZ);
+               if (ioctl(sockfd, SIOCGIFHWADDR, &if_hwaddr) < 0) {
+                       log_error("Could not match %s to netdevice.",
+                                 hwaddress);
+                       continue;
+               }
+
+               /* check for ARPHRD_ETHER (ethernet) */
+               if (if_hwaddr.ifr_hwaddr.sa_family != 1)
+                       continue;
+               hwaddr = (unsigned char *)if_hwaddr.ifr_hwaddr.sa_data;
+
+               memset(hwaddress, 0, ISCSI_MAX_IFACE_LEN);
+               /* TODO should look and covert so we do not need tmp buf */
+               sprintf(hwaddress, "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x",
+                       hwaddr[0], hwaddr[1], hwaddr[2], hwaddr[3],
+                       hwaddr[4], hwaddr[5]);
+               log_debug(4, "Found hardware address %s", hwaddress);
+               found = 1;
+               break;
+       }
+
+       close(sockfd);
+free_ifap:
+       freeifaddrs(ifap);
+       return found;
+}
+#endif
+
+
+#if 0
+
+This is not supported for now, because it is not exactly what we want.
+It also turns out that targets will send packets to other interfaces
+causing all types of weird things to happen.
+
+
+static int bind_src_by_address(int sockfd, char *address)
+{
+       int rc = 0;
+       char port[NI_MAXSERV];
+       struct sockaddr_storage saddr;
+
+       memset(&saddr, 0, sizeof(struct sockaddr_storage));
+       if (resolve_address(address, port, &saddr)) {
+               log_error("Could not bind %s to conn.", address);
+               return -1;
+       }
+
+       switch (saddr.ss_family) {
+       case AF_INET:
+               rc = bind(sockfd, (struct sockaddr *)&saddr,
+                         sizeof(struct sockaddr_in));
+               break;
+       case AF_INET6:
+               rc = bind(sockfd, (struct sockaddr *)&saddr,
+                         sizeof(struct sockaddr_in6));
+               break;
+       default:
+               rc = -1;
+       }
+       if (rc)
+               log_error("Could not bind %s to %d.", address, sockfd);
+       else
+               log_debug(4, "Bound %s to socket fd %d", address, sockfd);
+       return rc;
+}
+#endif
+
+static int bind_conn_to_iface(iscsi_conn_t *conn, struct iface_rec *iface)
+{
+       struct iscsi_session *session = conn->session;
+
+       if (strcmp(iface->transport_name, DEFAULT_TRANSPORT))
+               return 0;
+
+       memset(session->netdev, 0, IFNAMSIZ);
+       if (iface_is_bound_by_hwaddr(iface)) {
+               if (net_get_netdev_from_hwaddress(iface->hwaddress,
+                                                 session->netdev)) {
+                       log_error("Cannot match %s to net/scsi interface.",
+                                 iface->hwaddress);
+                       return -1;
+               }
+       } else if (iface_is_bound_by_netdev(iface)) {
+               strcpy(session->netdev, iface->netdev);
+       } else if (iface_is_bound_by_ipaddr(iface)) {
+               /*
+                * we never supported this but now with offload having to
+                * set the ip address in the iface, useris may forget to
+                * set the offload's transport type and we end up here by
+                * accident.
+                */
+               log_error("Cannot bind %s to net/scsi interface. This is not "
+                         "supported with software iSCSI (iscsi_tcp).",
+                          iface->ipaddress);
+               return -1;
+       }
+
+       if (strlen(session->netdev)) {
+               struct ifreq ifr;
+
+               log_debug(4, "Binding session %d to %s", session->id,
+                         session->netdev);
+               memset(&ifr, 0, sizeof(ifr));
+               strlcpy(ifr.ifr_name, session->netdev, IFNAMSIZ);
+
+               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",
+                                 conn->id, session->netdev);
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
+int
+iscsi_io_tcp_connect(iscsi_conn_t *conn, int non_blocking)
+{
+       int rc, onearg;
+       struct sockaddr_storage *ss = &conn->saddr;
+       char serv[NI_MAXSERV];
+
+       /* create a socket */
+       conn->socket_fd = socket(ss->ss_family, SOCK_STREAM, IPPROTO_TCP);
+
+       /* the trasport ep handle is used to bind with */
+       conn->transport_ep_handle = conn->socket_fd;
+
+       if (conn->socket_fd < 0) {
+               log_error("cannot create TCP socket");
+               return -1;
+       }
+
+       if (bind_conn_to_iface(conn, &conn->session->nrec.iface))
+               return -1;
+
+       onearg = 1;
+       rc = setsockopt(conn->socket_fd, IPPROTO_TCP, TCP_NODELAY, &onearg,
+                       sizeof (onearg));
+       if (rc < 0) {
+               log_error("cannot set TCP_NODELAY option on socket");
+               close(conn->socket_fd);
+               conn->socket_fd = -1;
+               return rc;
+       }
+
+       /* optionally set the window sizes */
+       if (conn->tcp_window_size) {
+               int window_size = conn->tcp_window_size;
+               socklen_t arglen = sizeof (window_size);
+
+               if (setsockopt(conn->socket_fd, SOL_SOCKET, SO_RCVBUF,
+                      (char *) &window_size, sizeof (window_size)) < 0) {
+                       log_warning("failed to set TCP recv window size "
+                                   "to %u", window_size);
+               } else {
+                       if (getsockopt(conn->socket_fd, SOL_SOCKET, SO_RCVBUF,
+                                      (char *) &window_size, &arglen) >= 0) {
+                               log_debug(4, "set TCP recv window size to %u, "
+                                         "actually got %u",
+                                         conn->tcp_window_size, window_size);
+                       }
+               }
+
+               window_size = conn->tcp_window_size;
+               arglen = sizeof (window_size);
+
+               if (setsockopt(conn->socket_fd, SOL_SOCKET, SO_SNDBUF,
+                      (char *) &window_size, sizeof (window_size)) < 0) {
+                       log_warning("failed to set TCP send window size "
+                                   "to %u", window_size);
+               } else {
+                       if (getsockopt(conn->socket_fd, SOL_SOCKET, SO_SNDBUF,
+                                      (char *) &window_size, &arglen) >= 0) {
+                               log_debug(4, "set TCP send window size to %u, "
+                                         "actually got %u",
+                                         conn->tcp_window_size, window_size);
+                       }
+               }
+       }
+
+       /*
+        * Build a TCP connection to the target
+        */
+       getnameinfo((struct sockaddr *) ss, sizeof(*ss),
+                   conn->host, sizeof(conn->host), serv, sizeof(serv),
+                   NI_NUMERICHOST|NI_NUMERICSERV);
+
+       log_debug(1, "connecting to %s:%s", conn->host, serv);
+       if (non_blocking)
+               set_non_blocking(conn->socket_fd);
+       rc = connect(conn->socket_fd, (struct sockaddr *) ss, sizeof (*ss));
+       return rc;
+}
+
+int
+iscsi_io_tcp_poll(iscsi_conn_t *conn, int timeout_ms)
+{
+       int rc;
+       struct pollfd pdesc;
+       char serv[NI_MAXSERV], lserv[NI_MAXSERV];
+       struct sockaddr_storage ss;
+       socklen_t len;
+
+       pdesc.fd = conn->socket_fd;
+       pdesc.events = POLLOUT;
+       rc = poll(&pdesc, 1, timeout_ms);
+       if (rc == 0)
+               return 0;
+
+       if (rc < 0) {
+               getnameinfo((struct sockaddr *) &conn->saddr,
+                           sizeof(conn->saddr),
+                           conn->host, sizeof(conn->host), serv, sizeof(serv),
+                           NI_NUMERICHOST|NI_NUMERICSERV);
+
+               log_error("cannot make connection to %s:%s (%s)",
+                         conn->host, serv, strerror(errno));
+               return rc;
+       }
+
+       len = sizeof(int);
+       if (getsockopt(conn->socket_fd, SOL_SOCKET, SO_ERROR,
+                       (char *) &rc, &len) < 0) {
+               log_error("getsockopt for connect poll failed");
+               return -1;
+       }
+       if (rc) {
+               getnameinfo((struct sockaddr *) &conn->saddr,
+                           sizeof(conn->saddr),
+                           conn->host, sizeof(conn->host), serv, sizeof(serv),
+                           NI_NUMERICHOST|NI_NUMERICSERV);
+
+               log_error("connect to %s:%s failed (%s)",
+                         conn->host, serv, strerror(rc));
+               return -rc;
+       }
+
+       len = sizeof(ss);
+       if (log_level > 0 &&
+           getsockname(conn->socket_fd, (struct sockaddr *) &ss, &len) >= 0) {
+               getnameinfo((struct sockaddr *) &conn->saddr,
+                           sizeof(conn->saddr), conn->host,
+                           sizeof(conn->host), serv, sizeof(serv),
+                           NI_NUMERICHOST|NI_NUMERICSERV);
+
+               getnameinfo((struct sockaddr *) &ss, sizeof(ss),
+                            NULL, 0, lserv, sizeof(lserv), NI_NUMERICSERV);
+
+               log_debug(1, "connected local port %s to %s:%s",
+                         lserv, conn->host, serv);
+       }
+       return 1;
+}
+
+void
+iscsi_io_tcp_disconnect(iscsi_conn_t *conn)
+{
+       struct linger so_linger = { .l_onoff = 1, .l_linger = 0 };
+
+       if (conn->socket_fd >= 0) {
+               log_debug(1, "disconnecting conn %p, fd %d", conn,
+                        conn->socket_fd);
+
+               /* If the state is not IN_LOGOUT, this isn't a clean shutdown
+                * and there's some sort of error handling going on. In that
+                * case, set a 0 SO_LINGER to force an abortive close (RST) and
+                * free whatever is sitting in the TCP transmit queue. This is
+                * done to prevent stale data from being sent should the
+                * network connection be restored before TCP times out.
+                */
+               if (conn->state != ISCSI_CONN_STATE_IN_LOGOUT) {
+                       setsockopt(conn->socket_fd, SOL_SOCKET, SO_LINGER,
+                                  &so_linger, sizeof(so_linger));
+               }
+
+               close(conn->socket_fd);
+               conn->socket_fd = -1;
+       }
+}
+
+int
+iscsi_io_connect(iscsi_conn_t *conn)
+{
+       int rc, ret;
+       struct sigaction action;
+       struct sigaction old;
+
+       /* set a timeout, since the socket calls may take a long time to
+        * timeout on their own
+        */
+       memset(&action, 0, sizeof (struct sigaction));
+       memset(&old, 0, sizeof (struct sigaction));
+       action.sa_sigaction = NULL;
+       action.sa_flags = 0;
+       action.sa_handler = sigalarm_handler;
+       sigaction(SIGALRM, &action, &old);
+       timedout = 0;
+       alarm(conn->login_timeout);
+
+       /* perform blocking TCP connect operation when no async request
+        * associated. SendTargets Discovery know to work in such a mode.
+        */
+       rc = iscsi_io_tcp_connect(conn, 0);
+       if (timedout) {
+               log_error("connect to %s timed out", conn->host);
+                         
+               log_debug(1, "socket %d connect timed out", conn->socket_fd);
+               ret = 0;
+               goto done;
+       } else if (rc < 0) {
+               log_error("cannot make connection to %s: %s",
+                         conn->host, strerror(errno));
+               close(conn->socket_fd);
+               ret = 0;
+               goto done;
+       } else if (log_level > 0) {
+               struct sockaddr_storage ss;
+               char lserv[NI_MAXSERV];
+               char serv[NI_MAXSERV];
+               socklen_t salen = sizeof(ss);
+
+               if (getsockname(conn->socket_fd, (struct sockaddr *) &ss,
+                               &salen) >= 0) {
+                       getnameinfo((struct sockaddr *) &conn->saddr,
+                                   sizeof(conn->saddr),
+                                   conn->host, sizeof(conn->host), serv,
+                                   sizeof(serv), NI_NUMERICHOST|NI_NUMERICSERV);
+
+                       getnameinfo((struct sockaddr *) &ss,
+                                   sizeof(ss),
+                                   NULL, 0, lserv, sizeof(lserv),
+                                   NI_NUMERICSERV);
+
+                       log_debug(1, "connected local port %s to %s:%s",
+                                 lserv, conn->host, serv);
+               }
+       }
+
+       ret = 1;
+
+done:
+       alarm(0);
+       sigaction(SIGALRM, &old, NULL);
+       return ret;
+}
+
+void
+iscsi_io_disconnect(iscsi_conn_t *conn)
+{
+       iscsi_io_tcp_disconnect(conn);
+}
+
+static void
+iscsi_log_text(struct iscsi_hdr *pdu, char *data)
+{
+       int dlength = ntoh24(pdu->dlength);
+       char *text = data;
+       char *end = text + dlength;
+
+       while (text && (text < end)) {
+               log_debug(4, ">    %s", text);
+               text += strlen(text);
+               while ((text < end) && (*text == '\0'))
+                       text++;
+       }
+}
+
+int
+iscsi_io_send_pdu(iscsi_conn_t *conn,
+                 struct iscsi_hdr *hdr,
+                 __attribute__((unused))int hdr_digest,
+                 char *data,
+                 __attribute__((unused))int data_digest,
+                 int timeout)
+{
+       int rc, ret = 0;
+       char *header = (char *) hdr;
+       char *end;
+       char pad[4];
+       struct iovec vec[3];
+       int pad_bytes;
+       int pdu_length = sizeof (*hdr) + hdr->hlength + ntoh24(hdr->dlength);
+       int remaining;
+       struct sigaction action;
+       struct sigaction old;
+       iscsi_session_t *session = conn->session;
+
+       /* set a timeout, since the socket calls may take a long time
+        * to timeout on their own
+        */
+       if (!session->use_ipc) {
+               memset(&action, 0, sizeof (struct sigaction));
+               memset(&old, 0, sizeof (struct sigaction));
+               action.sa_sigaction = NULL;
+               action.sa_flags = 0;
+               action.sa_handler = sigalarm_handler;
+               sigaction(SIGALRM, &action, &old);
+               timedout = 0;
+               alarm(timeout);
+       }
+
+       memset(&pad, 0, sizeof (pad));
+       memset(&vec, 0, sizeof (vec));
+
+       switch (hdr->opcode & ISCSI_OPCODE_MASK) {
+       case ISCSI_OP_LOGIN:{
+               struct iscsi_login *login_hdr = (struct iscsi_login *) hdr;
+
+               log_debug(4, "sending login PDU with current stage "
+                        "%d, next stage %d, transit 0x%x, isid"
+                        " 0x%02x%02x%02x%02x%02x%02x exp_statsn %u",
+                        ISCSI_LOGIN_CURRENT_STAGE(login_hdr->flags),
+                        ISCSI_LOGIN_NEXT_STAGE(login_hdr->flags),
+                        login_hdr->flags & ISCSI_FLAG_LOGIN_TRANSIT,
+                        login_hdr->isid[0], login_hdr->isid[1],
+                        login_hdr->isid[2], login_hdr->isid[3],
+                        login_hdr->isid[4], login_hdr->isid[5],
+                        ntohl(login_hdr->exp_statsn));
+
+                       iscsi_log_text(hdr, data);
+               break;
+       }
+       case ISCSI_OP_TEXT:{
+               struct iscsi_text *text_hdr = (struct iscsi_text *) hdr;
+
+               log_debug(4, "sending text pdu with CmdSN %x, exp_statsn %u",
+                        ntohl(text_hdr->cmdsn), ntohl(text_hdr->cmdsn));
+               iscsi_log_text(hdr, data);
+               break;
+       }
+       case ISCSI_OP_NOOP_OUT:{
+               struct iscsi_nopout *nopout_hdr = (struct iscsi_nopout *) hdr;
+
+               log_debug(4, "sending Nop-out pdu with ttt %x, CmdSN %x:",
+                        ntohl(nopout_hdr->ttt), ntohl(nopout_hdr->cmdsn));
+               iscsi_log_text(hdr, data);
+               break;
+       }
+       default:
+               log_debug(4, "sending pdu opcode 0x%x:", hdr->opcode);
+               break;
+       }
+
+       /* send the PDU header */
+       header = (char *) hdr;
+       end = header + sizeof (*hdr) + hdr->hlength;
+
+       /* send all the data and any padding */
+       if (pdu_length % ISCSI_PAD_LEN)
+               pad_bytes = ISCSI_PAD_LEN - (pdu_length % ISCSI_PAD_LEN);
+       else
+               pad_bytes = 0;
+
+       if (session->use_ipc)
+               ipc->send_pdu_begin(session->t->handle, session->id,
+                                   conn->id, end - header,
+                                   ntoh24(hdr->dlength) + pad_bytes);
+
+       while (header < end) {
+               vec[0].iov_base = header;
+               vec[0].iov_len = end - header;
+
+               if (!session->use_ipc)
+                       rc = writev(conn->socket_fd, vec, 1);
+               else
+                       rc = ipc->writev(0, vec, 1);
+               if (timedout) {
+                       log_error("socket %d write timed out",
+                              conn->socket_fd);
+                       ret = 0;
+                       goto done;
+               } else if ((rc <= 0) && (errno != EAGAIN)) {
+                       LOG_CONN_FAIL(conn);
+                       ret = 0;
+                       goto done;
+               } else if (rc > 0) {
+                       log_debug(4, "wrote %d bytes of PDU header", rc);
+                       header += rc;
+               }
+       }
+
+       end = data + ntoh24(hdr->dlength);
+       remaining = ntoh24(hdr->dlength) + pad_bytes;
+
+       while (remaining > 0) {
+               vec[0].iov_base = data;
+               vec[0].iov_len = end - data;
+               vec[1].iov_base = (void *) &pad;
+               vec[1].iov_len = pad_bytes;
+
+               if (!session->use_ipc)
+                       rc = writev(conn->socket_fd, vec, 2);
+               else
+                       rc = ipc->writev(0, vec, 2);
+               if (timedout) {
+                       log_error("socket %d write timed out",
+                                 conn->socket_fd);
+                       ret = 0;
+                       goto done;
+               } else if ((rc <= 0) && (errno != EAGAIN)) {
+                       LOG_CONN_FAIL(conn);
+                       ret = 0;
+                       goto done;
+               } else if (rc > 0) {
+                       log_debug(4, "wrote %d bytes of PDU data", rc);
+                       remaining -= rc;
+                       if (data < end) {
+                               data += rc;
+                               if (data > end)
+                                       data = end;
+                       }
+               }
+       }
+
+       if (session->use_ipc) {
+               if (ipc->send_pdu_end(session->t->handle, session->id,
+                                     conn->id, &rc)) {
+                       ret = 0;
+                       goto done;
+               }
+       }
+
+       ret = 1;
+
+      done:
+       if (!session->use_ipc) {
+               alarm(0);
+               sigaction(SIGALRM, &old, NULL);
+               timedout = 0;
+       }
+       return ret;
+}
+
+int
+iscsi_io_recv_pdu(iscsi_conn_t *conn,
+                 struct iscsi_hdr *hdr,
+                 __attribute__((unused))int hdr_digest,
+                 char *data,
+                 int max_data_length,
+                 __attribute__((unused))int data_digest,
+                 int timeout)
+{
+       uint32_t h_bytes = 0;
+       uint32_t ahs_bytes = 0;
+       uint32_t d_bytes = 0;
+       uint32_t ahslength = 0;
+       uint32_t dlength = 0;
+       uint32_t pad = 0;
+       int rlen = 0;
+       int failed = 0;
+       char *header = (char *) hdr;
+       char *end = data + max_data_length;
+       struct sigaction action;
+       struct sigaction old;
+       iscsi_session_t *session = conn->session;
+
+       memset(data, 0, max_data_length);
+
+       /* set a timeout, since the socket calls may take a long
+        * time to timeout on their own
+        */
+       if (!session->use_ipc) {
+               memset(&action, 0, sizeof (struct sigaction));
+               memset(&old, 0, sizeof (struct sigaction));
+               action.sa_sigaction = NULL;
+               action.sa_flags = 0;
+               action.sa_handler = sigalarm_handler;
+               sigaction(SIGALRM, &action, &old);
+               timedout = 0;
+               alarm(timeout);
+       } else {
+               failed = ipc->recv_pdu_begin(conn);
+               if (failed == -EAGAIN)
+                       return -EAGAIN;
+               else if (failed < 0) {
+                       failed = 1;
+                       goto done;
+               }
+       }
+
+       /* read a response header */
+       do {
+               if (!session->use_ipc)
+                       rlen = read(conn->socket_fd, header,
+                                       sizeof (*hdr) - h_bytes);
+               else
+                       rlen = ipc->read(header, sizeof (*hdr) - h_bytes);
+               if (timedout) {
+                       log_error("socket %d header read timed out",
+                                 conn->socket_fd);
+                       failed = 1;
+                       goto done;
+               } else if (rlen == 0) {
+                       LOG_CONN_CLOSED(conn);
+                       failed = 1;
+                       goto done;
+               } else if ((rlen < 0) && (errno != EAGAIN)) {
+                       LOG_CONN_FAIL(conn);
+                       failed = 1;
+                       goto done;
+               } else if (rlen > 0) {
+                       log_debug(4, "read %d bytes of PDU header", rlen);
+                       header += rlen;
+                       h_bytes += rlen;
+               }
+       } while (h_bytes < sizeof (*hdr));
+
+       log_debug(4, "read %d PDU header bytes, opcode 0x%x, dlength %u, "
+                "data %p, max %u", h_bytes, hdr->opcode & ISCSI_OPCODE_MASK,
+                ntoh24(hdr->dlength), data, max_data_length);
+
+       /* check for additional headers */
+       ahslength = hdr->hlength;       /* already includes padding */
+       if (ahslength) {
+               log_warning("additional header segment length %u not supported",
+                      ahslength);
+               failed = 1;
+               goto done;
+       }
+
+       /* read exactly what we expect, plus padding */
+       dlength = hdr->dlength[0] << 16;
+       dlength |= hdr->dlength[1] << 8;
+       dlength |= hdr->dlength[2];
+
+       /* if we only expected to receive a header, exit */
+       if (dlength == 0)
+               goto done;
+
+       if (data + dlength > end) {
+               log_warning("buffer size %u too small for data length %u",
+                      max_data_length, dlength);
+               failed = 1;
+               goto done;
+       }
+
+       /* read the rest into our buffer */
+       d_bytes = 0;
+       while (d_bytes < dlength) {
+               if (!session->use_ipc)
+                       rlen = read(conn->socket_fd, data + d_bytes,
+                                       dlength - d_bytes);
+               else
+                       rlen = ipc->read(data + d_bytes, dlength - d_bytes);
+               if (timedout) {
+                       log_error("socket %d data read timed out",
+                                 conn->socket_fd);
+                       failed = 1;
+                       goto done;
+               } else if (rlen == 0) {
+                       LOG_CONN_CLOSED(conn);
+                       failed = 1;
+                       goto done;
+               } else if ((rlen < 0 && errno != EAGAIN)) {
+                       LOG_CONN_FAIL(conn);
+                       failed = 1;
+                       goto done;
+               } else if (rlen > 0) {
+                       log_debug(4, "read %d bytes of PDU data", rlen);
+                       d_bytes += rlen;
+               }
+       }
+
+       /* handle PDU data padding.
+        * data is padded in case of kernel_io */
+       pad = dlength % ISCSI_PAD_LEN;
+       if (pad && !session->use_ipc) {
+               int pad_bytes = pad = ISCSI_PAD_LEN - pad;
+               char bytes[ISCSI_PAD_LEN];
+
+               while (pad_bytes > 0) {
+                       rlen = read(conn->socket_fd, &bytes, pad_bytes);
+                       if (timedout) {
+                               log_error("socket %d pad read timed out",
+                                         conn->socket_fd);
+                               failed = 1;
+                               goto done;
+                       } else if (rlen == 0) {
+                               LOG_CONN_CLOSED(conn);
+                               failed = 1;
+                               goto done;
+                       } else if ((rlen < 0 && errno != EAGAIN)) {
+                               LOG_CONN_FAIL(conn);
+                               failed = 1;
+                               goto done;
+                       } else if (rlen > 0) {
+                               log_debug(4, "read %d pad bytes", rlen);
+                               pad_bytes -= rlen;
+                       }
+               }
+       }
+
+       switch (hdr->opcode) {
+       case ISCSI_OP_TEXT_RSP:
+               log_debug(4, "finished reading text PDU, %u hdr, %u "
+                        "ah, %u data, %u pad",
+                        h_bytes, ahs_bytes, d_bytes, pad);
+               iscsi_log_text(hdr, data);
+               break;
+       case ISCSI_OP_LOGIN_RSP:{
+               struct iscsi_login_rsp *login_rsp =
+                           (struct iscsi_login_rsp *) hdr;
+
+               log_debug(4, "finished reading login PDU, %u hdr, "
+                        "%u ah, %u data, %u pad",
+                         h_bytes, ahs_bytes, d_bytes, pad);
+               log_debug(4, "login current stage %d, next stage "
+                        "%d, transit 0x%x",
+                        ISCSI_LOGIN_CURRENT_STAGE(login_rsp->flags),
+                        ISCSI_LOGIN_NEXT_STAGE(login_rsp->flags),
+                        login_rsp->flags & ISCSI_FLAG_LOGIN_TRANSIT);
+               iscsi_log_text(hdr, data);
+               break;
+       }
+       case ISCSI_OP_ASYNC_EVENT:
+               /* FIXME: log the event info */
+               break;
+       default:
+               break;
+       }
+
+done:
+       if (!session->use_ipc) {
+               alarm(0);
+               sigaction(SIGALRM, &old, NULL);
+       } else {
+               /* finalyze receive transaction */
+               if (ipc->recv_pdu_end(conn)) {
+                       failed = 1;
+               }
+       }
+
+       if (timedout || failed) {
+               timedout = 0;
+               return -EIO;
+       }
+
+       return h_bytes + ahs_bytes + d_bytes;
+}
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/iscsi_err.c b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/iscsi_err.c
new file mode 100644 (file)
index 0000000..b1cfa7a
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * iSCSI error helpers
+ *
+ * Copyright (C) 2011 Mike Christie
+ * Copyright (C) 2011 Red Hat, Inc. All rights reserved.
+ * 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 "stdlib.h"
+#include "iscsi_err.h"
+#include "log.h"
+
+enum iscsi_error_list iscsi_err;
+
+static char *iscsi_err_msgs[] = {
+       /* 0 */ "",
+       /* 1 */ "unknown error",
+       /* 2 */ "session not found",
+       /* 3 */ "no available memory",
+       /* 4 */ "encountered connection failure",
+       /* 5 */ "encountered iSCSI login failure",
+       /* 6 */ "encountered iSCSI database failure",
+       /* 7 */ "invalid parameter",
+       /* 8 */ "connection timed out",
+       /* 9 */ "internal error",
+       /* 10 */ "encountered iSCSI logout failure",
+       /* 11 */ "iSCSI PDU timed out",
+       /* 12 */ "iSCSI driver not found. Please make sure it is loaded, and retry the operation",
+       /* 13 */ "daemon access denied",
+       /* 14 */ "iSCSI driver does not support requested capability.",
+       /* 15 */ "session exists",
+       /* 16 */ "Unknown request",
+       /* 17 */ "iSNS service not supported",
+       /* 18 */ "could not communicate to iscsid",
+       /* 19 */ "encountered non-retryable iSCSI login failure",
+       /* 20 */ "could not connect to iscsid",
+       /* 21 */ "no objects found",
+       /* 22 */ "sysfs lookup failure",
+       /* 23 */ "host not found",
+       /* 24 */ "iSCSI login failed due to authorization failure",
+       /* 25 */ "iSNS query failed",
+       /* 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",
+       /* 31 */ "child process terminated",
+       /* 32 */ "target likely not connected",
+       /* 33 */ "iscsid request timed out",
+};
+
+char *iscsi_err_to_str(int err)
+{
+       if (err >= ISCSI_MAX_ERR_VAL || err < 0) {
+               log_error("invalid error code %d", err);
+               return NULL;
+       }
+
+       return iscsi_err_msgs[err];
+}
+
+void iscsi_err_print_msg(int err)
+{
+       if (err >= ISCSI_MAX_ERR_VAL || err < 0) {
+               log_error("invalid error code %d", err);
+               return;
+       }
+       log_error("initiator reported error (%d - %s)", err,
+                 iscsi_err_msgs[err]);
+}
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/iscsi_ipc.h b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/iscsi_ipc.h
new file mode 100644 (file)
index 0000000..78bd29a
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ * User/Kernel Transport IPC API Ioctl/NETLINK/etc
+ *
+ * Copyright (C) 2005 Dmitry Yusupov, Alex Aizman
+ * 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.
+ *
+ * NOTE: OSes must implement this API in terms of user's control-plane re-use.
+ */
+
+#ifndef ISCSI_IPC_H
+#define ISCSI_IPC_H
+
+#include "iscsi_if.h"
+
+enum {
+       ISCSI_INT,
+       ISCSI_UINT,
+       ISCSI_STRING,
+};
+
+struct iscsi_conn;
+struct iscsi_ev_context;
+
+/*
+ * When handling async events, the initiator may not be able to
+ * handle the event in the same context, so this allows the interface
+ * code to call into the initiator to shedule handling.
+ */
+struct iscsi_ipc_ev_clbk {
+       void (*create_session) (uint32_t host_no, uint32_t sid);
+       void (*destroy_session) (uint32_t host_no, uint32_t sid);
+
+       struct iscsi_ev_context *(*get_ev_context) (struct iscsi_conn *conn,
+                                                   int ev_size);
+       void (*put_ev_context) (struct iscsi_ev_context *ev_context);
+       int (*sched_ev_context) (struct iscsi_ev_context *ev_context,
+                                struct iscsi_conn *conn,
+                                unsigned long tmo, int event);
+};
+
+extern void ipc_register_ev_callback(struct iscsi_ipc_ev_clbk *ipc_ev_clbk);
+
+enum iscsi_ipc_auth_type {
+       /* UID must have valid entry in user db */
+       ISCSI_IPC_AUTH_DEFAULT = 0,
+
+       /* Check only that UID==0 */
+       ISCSI_IPC_AUTH_UID,
+
+       /* Must be last */
+       ISCSI_IPC_AUTH_MAX,
+};
+
+/**
+ * struct iscsi_ipc - Open-iSCSI Interface for Kernel IPC
+ *
+ * All functions allowed to return POSIX kind of error. i.e. 0 - OK, non-zero
+ * means IPC error and errno set.
+ */
+struct iscsi_ipc {
+       char *name;
+
+       int ctldev_bufmax;
+
+       enum iscsi_ipc_auth_type auth_type;
+
+       int (*ctldev_open) (void);
+
+       void (*ctldev_close) (void);
+
+       int (*ctldev_handle) (void);
+
+       int (*sendtargets) (uint64_t transport_handle, uint32_t host_no,
+                           struct sockaddr *addr);
+
+       int (*create_session) (uint64_t transport_handle, uint64_t ep_handle,
+                              uint32_t initial_cmdsn, uint16_t cmds_max,
+                              uint16_t qdepth, uint32_t *out_sid,
+                              uint32_t *hostno);
+
+       int (*destroy_session) (uint64_t transport_handle, uint32_t sid);
+
+       int (*unbind_session) (uint64_t transport_handle, uint32_t sid);
+
+       int (*create_conn) (uint64_t transport_handle,
+                           uint32_t sid, uint32_t cid, uint32_t *out_cid);
+
+       int (*destroy_conn) (uint64_t transport_handle, uint32_t sid,
+                            uint32_t cid);
+
+       int (*bind_conn) (uint64_t transport_handle, uint32_t sid,
+                         uint32_t cid, uint64_t transport_eph,
+                         int is_leading, int *retcode);
+
+       int (*set_param) (uint64_t transport_handle, uint32_t sid,
+                         uint32_t cid, enum iscsi_param param,
+                         void *value, int type);
+
+       int (*set_host_param) (uint64_t transport_handle, uint32_t host_no,
+                              enum iscsi_host_param param,
+                              void *value, int type);
+
+       /* not implemented yet */
+       int (*get_param) (uint64_t transport_handle, uint32_t sid,
+                         uint32_t cid, enum iscsi_param param,
+                         uint32_t *value, int *retcode);
+
+       int (*get_stats) (uint64_t transport_handle, uint32_t sid,
+                         uint32_t cid, char *statsbuf, int statsbuf_max);
+
+       int (*start_conn) (uint64_t transport_handle, uint32_t sid,
+                          uint32_t cid, int *retcode);
+
+       int (*stop_conn) (uint64_t transport_handle, uint32_t sid,
+                         uint32_t cid, int flag);
+
+       int (*read) (char *data, int count);
+
+       void (*send_pdu_begin) (uint64_t transport_handle, uint32_t sid,
+                               uint32_t cid, int hdr_size, int data_size);
+
+       int (*send_pdu_end) (uint64_t transport_handle, uint32_t sid,
+                            uint32_t cid, int *retcode);
+
+       int (*writev) (enum iscsi_uevent_e type, struct iovec *iovp, int count);
+
+       int (*recv_pdu_begin) (struct iscsi_conn *conn);
+
+       int (*recv_pdu_end) (struct iscsi_conn *conn);
+
+       int (*set_net_config) (uint64_t transport_handle, uint32_t host_no,
+                              struct iovec *iovs, uint32_t param_count);
+
+       int (*recv_conn_state) (struct iscsi_conn *conn, uint32_t *state);
+
+       int (*exec_ping) (uint64_t transport_handle, uint32_t host_no,
+                         struct sockaddr *addr, uint32_t iface_num,
+                         uint32_t iface_type, uint32_t size, uint32_t *status);
+
+       int (*get_chap) (uint64_t transport_handle, uint32_t host_no,
+                        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/pkgs/open-iscsi/open-iscsi-2.1.8/usr/iscsi_net_util.c b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/iscsi_net_util.c
new file mode 100644 (file)
index 0000000..10e6fa6
--- /dev/null
@@ -0,0 +1,465 @@
+/*
+ * net helpers
+ *
+ * Copyright (C) 2010 Mike Christie
+ * Copyright (C) 2010 Red Hat, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <net/if.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <net/route.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <linux/sockios.h>
+#include <linux/if_vlan.h>
+#include <net/if_arp.h>
+#include <linux/if_ether.h>
+
+#include "sysdeps.h"
+#include "ethtool-copy.h"
+#include "iscsi_net_util.h"
+#include "log.h"
+
+struct iscsi_net_driver {
+       const char *net_drv_name;
+       const char *iscsi_transport;
+};
+
+static struct iscsi_net_driver net_drivers[] = {
+       {"cxgb3", "cxgb3i" },
+       {"cxgb4", "cxgb4i" },
+       {"bnx2", "bnx2i" },
+       {"bnx2x", "bnx2i"},
+       {NULL, NULL}
+};
+
+/**
+ * net_get_transport_name_from_netdev - get name of transport to use for iface
+ * @netdev: netdev iface name
+ * @transport: buffer to hold transport name
+ *
+ * transport buffer should be ISCSI_TRANSPORT_NAME_MAXLEN bytes
+ */
+int net_get_transport_name_from_netdev(char *netdev, char *transport)
+{
+       struct ethtool_drvinfo drvinfo;
+       struct ifreq ifr;
+       int err, fd, i;
+
+       memset(&ifr, 0, sizeof(ifr));
+       strcpy(ifr.ifr_name, netdev);
+
+       fd = socket(AF_INET, SOCK_DGRAM, 0);
+       if (fd < 0) {
+               log_error("Could not open socket for ioctl.");
+               return errno;
+       }
+
+       drvinfo.cmd = ETHTOOL_GDRVINFO;
+       ifr.ifr_data = (caddr_t)&drvinfo;
+       err = ioctl(fd, SIOCETHTOOL, &ifr);
+       if (err < 0) {
+               log_error("Could not get driver %s.", netdev);
+               err = errno;
+               goto close_sock;
+       }
+
+       /*
+       * iSCSI hardware offload for bnx2{,x} is only supported if the
+       * iscsiuio executable is available.
+       */
+       if (!strcmp(drvinfo.driver, "bnx2x") ||
+           !strcmp(drvinfo.driver, "bnx2")) {
+               struct stat buf;
+
+               if (stat(ISCSIUIO_PATH, &buf)) {
+                       log_debug(1, "ISCSI offload not supported "
+                                    "(%s not found).", ISCSIUIO_PATH);
+                       err = ENODEV;
+                       goto close_sock;
+                       }
+       }
+
+       for (i = 0; net_drivers[i].net_drv_name != NULL; i++) {
+               struct iscsi_net_driver *net_driver = &net_drivers[i];
+
+               if (!strcmp(net_driver->net_drv_name, drvinfo.driver)) {
+                       strcpy(transport, net_driver->iscsi_transport);
+                       err = 0;
+                       goto close_sock;
+               }
+       }
+       err = ENODEV;
+
+close_sock:
+       close(fd);
+       return err;
+}
+
+/**
+ * net_get_netdev_from_hwaddress - given a hwaddress return the ethX
+ * @hwaddress: hw address no larger than ISCSI_HWADDRESS_BUF_SIZE
+ * @netdev: buffer of IFNAMSIZ size that will hold the ethX
+ *
+ * Does not support interfaces like a bond or alias because
+ * multiple interfaces will have the same hwaddress.
+ */
+int net_get_netdev_from_hwaddress(char *hwaddress, char *netdev)
+{
+       struct if_nameindex *ifni;
+       struct ifreq if_hwaddr;
+       int found = 0, sockfd, i = 0;
+       unsigned char *hwaddr;
+       char tmp_hwaddress[ISCSI_HWADDRESS_BUF_SIZE];
+
+       ifni = if_nameindex();
+       if (ifni == NULL) {
+               log_error("Could not match hwaddress %s to netdev. "
+                         "getifaddrs failed %d", hwaddress, errno);
+               return errno;
+       }
+
+       /* Open a basic socket. */
+       sockfd = socket(AF_INET, SOCK_DGRAM, 0);
+       if (sockfd < 0) {
+               log_error("Could not open socket for ioctl.");
+               goto free_ifni;
+       }
+
+       for (i = 0; ifni[i].if_index && ifni[i].if_name; i++) {
+               struct if_nameindex *n = &ifni[i];
+
+               strlcpy(if_hwaddr.ifr_name, n->if_name, IFNAMSIZ);
+               if (ioctl(sockfd, SIOCGIFHWADDR, &if_hwaddr) < 0) {
+                       log_error("Could not match %s to netdevice.",
+                                 hwaddress);
+                       continue;
+               }
+
+               /* check for ARPHRD_ETHER (ethernet) */
+               if (if_hwaddr.ifr_hwaddr.sa_family != 1)
+                       continue;
+               hwaddr = (unsigned char *)if_hwaddr.ifr_hwaddr.sa_data;
+
+               memset(tmp_hwaddress, 0, ISCSI_HWADDRESS_BUF_SIZE);
+               /* TODO should look and covert so we do not need tmp buf */
+               sprintf(tmp_hwaddress, "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x",
+                       hwaddr[0], hwaddr[1], hwaddr[2], hwaddr[3],
+                       hwaddr[4], hwaddr[5]);
+               log_debug(4, "Found hardware address %s", tmp_hwaddress);
+               if (!strcasecmp(tmp_hwaddress, hwaddress)) {
+                       log_debug(4, "Matches %s to %s", hwaddress,
+                                 n->if_name);
+                       memset(netdev, 0, IFNAMSIZ); 
+                       strlcpy(netdev, n->if_name, IFNAMSIZ);
+                       found = 1;
+                       break;
+               }
+       }
+
+       close(sockfd);
+free_ifni:
+       if_freenameindex(ifni);
+       if (!found)
+               return ENODEV;
+       return 0;
+}
+
+static char *find_vlan_dev(char *netdev, int vlan_id) {
+       struct ifreq if_hwaddr;
+       struct ifreq vlan_hwaddr;
+       struct vlan_ioctl_args vlanrq = { .cmd = GET_VLAN_VID_CMD, };
+       struct if_nameindex *ifni;
+       char *vlan = NULL;
+       int sockfd, i, rc;
+
+       sockfd = socket(AF_INET, SOCK_DGRAM, 0);
+       if (sockfd < 0) {
+               log_error("Could not open socket for ioctl.");
+               return NULL;
+       }
+
+       strlcpy(if_hwaddr.ifr_name, netdev, IFNAMSIZ);
+       ioctl(sockfd, SIOCGIFHWADDR, &if_hwaddr);
+
+       if (if_hwaddr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
+               close(sockfd);
+               return NULL;
+       }
+
+       ifni = if_nameindex();
+       if (!ifni) {
+               log_error("Failed to find netdev:%s", strerror(errno));
+               close(sockfd);
+               return NULL;
+       }
+
+       for (i = 0; ifni[i].if_index && ifni[i].if_name; i++) {
+               strlcpy(vlan_hwaddr.ifr_name, ifni[i].if_name, IFNAMSIZ);
+               ioctl(sockfd, SIOCGIFHWADDR, &vlan_hwaddr);
+
+               if (vlan_hwaddr.ifr_hwaddr.sa_family != ARPHRD_ETHER)
+                       continue;
+
+               if (!memcmp(if_hwaddr.ifr_hwaddr.sa_data, vlan_hwaddr.ifr_hwaddr.sa_data, ETH_ALEN)) {
+                       strlcpy(vlanrq.device1, ifni[i].if_name, IFNAMSIZ);
+                       rc = ioctl(sockfd, SIOCGIFVLAN, &vlanrq);
+                       if ((rc == 0) && (vlanrq.u.VID == vlan_id)) {
+                               vlan = strdup(vlanrq.device1);
+                               break;
+                       }
+               }
+       }
+       if_freenameindex(ifni);
+
+       close(sockfd);
+       return vlan;
+}
+
+/**
+ * net_setup_netdev - bring up NIC
+ * @netdev: network device name
+ * @local: ip address for netdev
+ * @mask: net mask
+ * @gateway: gateway
+ * @remote_ip: target portal ip
+ * @needs_bringup: bool indicating if the netdev needs to be started
+ *
+ * Bring up required NIC and use routing
+ * to force iSCSI traffic through correct NIC.
+ */
+int net_setup_netdev(char *netdev, char *local_ip, char *mask, char *gateway,
+                    char *vlan, char *remote_ip, int needs_bringup)
+{
+       struct sockaddr_in sk_ipaddr = { .sin_family = AF_INET };
+       struct sockaddr_in sk_netmask = { .sin_family = AF_INET };
+       struct sockaddr_in sk_hostmask = { .sin_family = AF_INET };
+       struct sockaddr_in sk_gateway = { .sin_family = AF_INET };
+       struct sockaddr_in sk_tgt_ipaddr = { .sin_family = AF_INET };
+       struct rtentry rt;
+       struct ifreq ifr;
+       char *physdev = NULL;
+       int sock;
+       int ret;
+       int vlan_id;
+
+       if (!strlen(netdev)) {
+               log_error("No netdev name in fw entry.");
+               return EINVAL;
+       }               
+
+       vlan_id = atoi(vlan);
+
+       if (vlan_id != 0) {
+               physdev = netdev;
+               netdev = find_vlan_dev(physdev, vlan_id);
+       }
+
+       if (vlan_id && !netdev) {
+               /* TODO: create vlan if not found */
+               log_error("No matching vlan found for fw entry.");
+               return EINVAL;
+       }
+
+       /* Create socket for making networking changes */
+       if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
+               log_error("Could not open socket to manage network "
+                         "(err %d - %s)", errno, strerror(errno));
+               ret = errno;
+               goto done;
+       }
+
+       /* Bring up NIC with correct address  - unless it
+        * 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");
+               ret = EINVAL;
+               goto done;
+       }
+
+       if (!inet_aton(mask, &sk_netmask.sin_addr)) {
+               log_error("Invalid or missing netmask in fw entry");
+               ret = EINVAL;
+               goto done;
+       }
+
+       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");
+               ret = EINVAL;
+               goto done;
+       }
+
+       /* Only set IP/NM if this is a new interface */
+       if (needs_bringup) {
+
+               if (physdev) {
+                       /* Bring up interface */
+                       memset(&ifr, 0, sizeof(ifr));
+                       strlcpy(ifr.ifr_name, physdev, IFNAMSIZ);
+                       ifr.ifr_flags = IFF_UP | IFF_RUNNING;
+                       if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0) {
+                               log_error("Could not bring up netdev %s (err %d - %s)",
+                                         physdev, errno, strerror(errno));
+                               ret = errno;
+                               goto done;
+                       }
+               }
+
+               /* Bring up interface */
+               memset(&ifr, 0, sizeof(ifr));
+               strlcpy(ifr.ifr_name, netdev, IFNAMSIZ);
+               ifr.ifr_flags = IFF_UP | IFF_RUNNING;
+               if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0) {
+                       log_error("Could not bring up netdev %s (err %d - %s)",
+                                 netdev, errno, strerror(errno));
+                       ret = errno;
+                       goto done;
+               }
+               /* Set IP address */
+               memset(&ifr, 0, sizeof(ifr));
+               strlcpy(ifr.ifr_name, netdev, IFNAMSIZ);
+               memcpy(&ifr.ifr_addr, &sk_ipaddr, sizeof(struct sockaddr));
+               if (ioctl(sock, SIOCSIFADDR, &ifr) < 0) {
+                       log_error("Could not set ip for %s (err %d - %s)",
+                                 netdev, errno, strerror(errno));
+                       ret = errno;
+                       goto done;
+               }
+
+               /* Set netmask */
+               memset(&ifr, 0, sizeof(ifr));
+               strlcpy(ifr.ifr_name, netdev, IFNAMSIZ);
+               memcpy(&ifr.ifr_addr, &sk_netmask, sizeof(struct sockaddr));
+               if (ioctl(sock, SIOCSIFNETMASK, &ifr) < 0) {
+                       log_error("Could not set ip for %s (err %d - %s)",
+                                 netdev, errno, strerror(errno));
+                       ret = errno;
+                       goto done;
+               }
+       }
+
+       /* Set static route to target via this interface */
+       memset((char *) &rt, 0, sizeof(rt));
+       memcpy(&rt.rt_dst, &sk_tgt_ipaddr, sizeof(sk_tgt_ipaddr));
+       memcpy(&rt.rt_genmask, &sk_hostmask, sizeof(sk_hostmask));
+       rt.rt_flags = RTF_UP | RTF_HOST;
+       rt.rt_dev = netdev;
+
+       if ((sk_tgt_ipaddr.sin_addr.s_addr & sk_netmask.sin_addr.s_addr) == 
+               (sk_ipaddr.sin_addr.s_addr & sk_netmask.sin_addr.s_addr)) {
+               /* Same subnet */
+               if (ioctl(sock, SIOCADDRT, &rt) < 0) {
+                       if (errno != EEXIST) {
+                               log_error("Could not set ip for %s "
+                                         "(err %d - %s)", netdev,
+                                          errno, strerror(errno));
+                               ret = errno;
+                               goto done;
+                       }
+               }
+       } else {
+               /* Different subnet.  Use gateway */
+               rt.rt_flags |= RTF_GATEWAY;
+               if (!inet_aton(gateway, &sk_gateway.sin_addr)) {
+                       log_error("Invalid or missing gateway for %s "
+                                 "(err %d - %s)",
+                                 netdev, errno, strerror(errno));
+                       ret = errno;
+                       goto done;
+               }
+               memcpy(&rt.rt_gateway, &sk_gateway, sizeof(sk_gateway));
+               if (ioctl(sock, SIOCADDRT, &rt) < 0) {
+                       if (errno != EEXIST) {
+                               log_error("Could not set gateway for %s "
+                                         "(err %d - %s)", netdev,
+                                         errno, strerror(errno));
+                               ret = errno;
+                               goto done;
+                       }
+               }
+       }
+       ret = 0;
+
+done:
+       if (sock >= 0)
+               close(sock);
+       if (vlan_id)
+               free(netdev);
+       return ret;
+}
+
+/**
+ * net_ifup_netdev - bring up network interface
+ * @netdev: netdevice to bring up.
+ */
+int net_ifup_netdev(char *netdev)
+{
+       struct ifreq ifr;
+       int sock;
+       int ret = 0;
+
+       if (!strlen(netdev)) {
+               log_error("No netdev name in fw entry.");
+               return EINVAL;
+       }               
+
+       /* Create socket for making networking changes */
+       if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
+               log_error("Could not open socket to manage network "
+                         "(err %d - %s)", errno, strerror(errno));
+               return errno;
+       }
+
+       memset(&ifr, 0, sizeof(ifr));
+       strlcpy(ifr.ifr_name, netdev, IFNAMSIZ);
+       if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) {
+               log_error("Could not bring up netdev %s (err %d - %s)",
+                         netdev, errno, strerror(errno));
+               ret = errno;
+               goto done;
+       }
+
+       if (ifr.ifr_flags & IFF_UP) {
+               log_debug(3, "%s up", netdev);
+               goto done;
+       }
+
+       log_debug(3, "bringing %s up", netdev);
+
+       /* Bring up interface */
+       memset(&ifr, 0, sizeof(ifr));
+       strlcpy(ifr.ifr_name, netdev, IFNAMSIZ);
+       ifr.ifr_flags = IFF_UP;
+       if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0) {
+               log_error("Could not bring up netdev %s (err %d - %s)",
+                         netdev, errno, strerror(errno));
+               ret = errno;
+               goto done;
+       }
+done:
+       close(sock);
+       return ret;
+}
+
+
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/iscsi_netlink.h b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/iscsi_netlink.h
new file mode 100644 (file)
index 0000000..25b41db
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * iSCSI Netlink attr helpers
+ *
+ * Copyright (C) 2011 Red Hat, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * See the file COPYING included with this distribution for more details.
+ */
+
+#ifndef ISCSI_NLA_H
+#define ISCSI_NLA_H
+
+#include <linux/netlink.h>
+
+struct iovec;
+
+#define ISCSI_NLA_HDRLEN       ((int) NLA_ALIGN(sizeof(struct nlattr)))
+#define ISCSI_NLA_DATA(nla)    ((void *)((char*)(nla) + ISCSI_NLA_HDRLEN))
+#define ISCSI_NLA_LEN(len)     ((len) + NLA_ALIGN(ISCSI_NLA_HDRLEN))
+#define ISCSI_NLA_TOTAL_LEN(len) (NLA_ALIGN(ISCSI_NLA_LEN(len)))
+
+extern struct nlattr *iscsi_nla_alloc(uint16_t type, uint16_t len);
+
+#endif
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/iscsi_settings.h b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/iscsi_settings.h
new file mode 100644 (file)
index 0000000..a4e54a9
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Default initiator settings. These may not be the same as
+ * in the RFC. See iscsi_proto.h for those.
+ */
+/* timeouts in seconds */
+#define DEF_LOGIN_TIMEO                30
+#define DEF_LOGOUT_TIMEO       15
+#define DEF_NOOP_OUT_INTERVAL  5
+#define DEF_NOOP_OUT_TIMEO     5
+#define DEF_REPLACEMENT_TIMEO  120
+
+#define DEF_ABORT_TIMEO                15
+#define DEF_LU_RESET_TIMEO     30
+#define DEF_TGT_RESET_TIMEO    30
+#define DEF_HOST_RESET_TIMEO   60
+
+/* session reopen max retries */
+#define        DEF_SESSION_REOPEN_MAX  0
+
+/* q depths */
+#define CMDS_MAX       128
+#define QUEUE_DEPTH    32
+
+/* system */
+#define XMIT_THREAD_PRIORITY   -20
+
+/* interface */
+#define UNKNOWN_VALUE          "<empty>"
+#define DEFAULT_IFACENAME      "default"
+#define DEFAULT_NETDEV         "default"
+#define DEFAULT_IPADDRESS      "default"
+#define DEFAULT_HWADDRESS      "default"
+#define DEFAULT_TRANSPORT      "tcp"
+
+#define PORTAL_GROUP_TAG_UNKNOWN -1
+
+/* default window size */
+#define TCP_WINDOW_SIZE (512 * 1024)
+
+/* default iSCSI port number */
+#define ISCSI_DEFAULT_PORT 3260
+
+/* data and segment lengths in bytes */
+#define DEF_INI_FIRST_BURST_LEN                262144
+#define DEF_INI_MAX_BURST_LEN          16776192
+#define DEF_INI_MAX_RECV_SEG_LEN       262144
+#define DEF_INI_DISC_MAX_RECV_SEG_LEN  32768
+
+/* login retries */
+#define DEF_INITIAL_LOGIN_RETRIES_MAX  4
+
+/* autoscan enabled */
+#define DEF_INITIAL_SCAN       1
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/iscsi_sysfs.c b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/iscsi_sysfs.c
new file mode 100644 (file)
index 0000000..9a591be
--- /dev/null
@@ -0,0 +1,2029 @@
+/*
+ * iSCSI sysfs
+ *
+ * Copyright (C) 2006 Mike Christie
+ * Copyright (C) 2006 Red Hat, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <errno.h>
+#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"
+#include "iscsi_settings.h"
+#include "iface.h"
+#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
+ *  is done in sysfs.c.
+ */
+#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.
+ */
+
+static int num_transports;
+LIST_HEAD(transports);
+
+void free_transports(void)
+{
+       struct iscsi_transport *t, *tmp;
+
+       list_for_each_entry_safe(t, tmp, &transports, list) {
+               list_del(&t->list);
+               free(t);
+       }
+}
+
+static int trans_filter(const struct dirent *dir)
+{
+       return strcmp(dir->d_name, ".") && strcmp(dir->d_name, "..");
+}
+
+static int read_transports(void)
+{
+       struct dirent **namelist;
+       int i, n, found;
+       struct iscsi_transport *t;
+
+       log_debug(7, "in %s", __FUNCTION__);
+
+       n = scandir(ISCSI_TRANSPORT_DIR, &namelist, trans_filter,
+                   alphasort);
+       if (n < 0) {
+               log_error("Could not scan %s.", ISCSI_TRANSPORT_DIR);
+               return n;
+       }
+
+       for (i = 0; i < n; i++) {
+               found = 0;
+
+               list_for_each_entry(t, &transports, list) {
+                       if (!strcmp(t->name, namelist[i]->d_name)) {
+                               found = 1;
+                               break;
+                       }
+               }
+
+               if (!found) {
+                       /* copy new transport */
+                       t = malloc(sizeof(*t));
+                       if (!t)
+                               continue;
+                       log_debug(7, "Adding new transport %s",
+                                 namelist[i]->d_name);
+
+                       INIT_LIST_HEAD(&t->sessions);
+                       INIT_LIST_HEAD(&t->list);
+                       strlcpy(t->name, namelist[i]->d_name,
+                               ISCSI_TRANSPORT_NAME_MAXLEN);
+                       if (set_transport_template(t)) {
+                               free(t);
+                               return -1;
+                       }
+               } else
+                       log_debug(7, "Updating transport %s",
+                                 namelist[i]->d_name);
+
+               if (sysfs_get_uint64(t->name, ISCSI_TRANSPORT_SUBSYS,
+                                    "handle", &t->handle)) {
+                       if (list_empty(&t->list))
+                               free(t);
+                       else
+                               log_error("Could not update %s.",
+                                         t->name);
+                       continue;
+               }
+
+               if (sysfs_get_uint(t->name, ISCSI_TRANSPORT_SUBSYS,
+                                 "caps", &t->caps)) {
+                       if (list_empty(&t->list))
+                               free(t);
+                       else
+                               log_error("Could not update %s.",
+                                         t->name);
+                       continue;
+               }
+               /*
+                * tmp hack for qla4xx compat
+                */
+               if (!strcmp(t->name, "qla4xxx")) {
+                       t->caps |= CAP_DATA_PATH_OFFLOAD;
+               }
+
+               if (list_empty(&t->list))
+                       list_add_tail(&t->list, &transports);
+       }
+
+       for (i = 0; i < n; i++)
+               free(namelist[i]);
+       free(namelist);
+       num_transports = n;
+
+       return 0;
+}
+
+/* caller must check lengths */
+void iscsi_sysfs_get_auth_conf(int sid, struct iscsi_auth_config *conf)
+{
+       char id[NAME_SIZE];
+
+       memset(conf, 0, sizeof(*conf));
+       snprintf(id, sizeof(id), ISCSI_SESSION_ID, sid);
+
+       sysfs_get_str(id, ISCSI_SESSION_SUBSYS, "username", conf->username,
+                     sizeof(conf->username));
+       sysfs_get_str(id, ISCSI_SESSION_SUBSYS, "username_in",
+                     conf->username_in, sizeof(conf->username_in));
+
+       sysfs_get_str(id, ISCSI_SESSION_SUBSYS, "password",
+                     (char *)conf->password, sizeof(conf->password));
+       if (strlen((char *)conf->password))
+               conf->password_length = strlen((char *)conf->password);
+
+       sysfs_get_str(id, ISCSI_SESSION_SUBSYS, "password_in",
+                     (char *)conf->password_in, sizeof(conf->password_in));
+       if (strlen((char *)conf->password_in))
+               conf->password_in_length = strlen((char *)conf->password_in);
+}
+
+/* called must check for -1=invalid value */
+void iscsi_sysfs_get_negotiated_conn_conf(int sid,
+                               struct iscsi_conn_operational_config *conf)
+{
+       char id[NAME_SIZE];
+
+       memset(conf, 0, sizeof(*conf));
+       snprintf(id, sizeof(id), ISCSI_CONN_ID, sid);
+
+       sysfs_get_int(id, ISCSI_CONN_SUBSYS, "data_digest", &conf->DataDigest);
+       sysfs_get_int(id, ISCSI_CONN_SUBSYS, "header_digest",
+                     &conf->HeaderDigest);
+       sysfs_get_int(id, ISCSI_CONN_SUBSYS, "max_xmit_dlength",
+                     &conf->MaxXmitDataSegmentLength);
+       sysfs_get_int(id, ISCSI_CONN_SUBSYS, "max_recv_dlength",
+                      &conf->MaxRecvDataSegmentLength);
+}
+
+/* called must check for -1=invalid value */
+void iscsi_sysfs_get_negotiated_session_conf(int sid,
+                               struct iscsi_session_operational_config *conf)
+{
+       char id[NAME_SIZE];
+
+       memset(conf, 0, sizeof(*conf));
+       snprintf(id, sizeof(id), ISCSI_SESSION_ID, sid);
+
+       sysfs_get_int(id, ISCSI_SESSION_SUBSYS, "data_pdu_in_order",
+                     &conf->DataPDUInOrder);
+       sysfs_get_int(id, ISCSI_SESSION_SUBSYS, "data_seq_in_order",
+                     &conf->DataSequenceInOrder);
+       sysfs_get_int(id, ISCSI_SESSION_SUBSYS, "erl", &conf->ERL);
+       sysfs_get_int(id, ISCSI_SESSION_SUBSYS, "first_burst_len",
+                      &conf->FirstBurstLength);
+       sysfs_get_int(id, ISCSI_SESSION_SUBSYS, "max_burst_len",
+                     &conf->MaxBurstLength);
+       sysfs_get_int(id, ISCSI_SESSION_SUBSYS, "immediate_data",
+                     &conf->ImmediateData);
+       sysfs_get_int(id, ISCSI_SESSION_SUBSYS, "initial_r2t",
+                     &conf->InitialR2T);
+       sysfs_get_int(id, ISCSI_SESSION_SUBSYS, "max_outstanding_r2t",
+                     &conf->MaxOutstandingR2T);
+}
+
+/*
+ * iscsi_sysfs_session_user_created - return if session was setup by userspace
+ * @sid: id of session to test
+ *
+ * Returns -1 if we could not tell due to kernel not supporting the
+ * feature. 0 is returned if kernel created it. And 1 is returned
+ * if userspace created it.
+ */
+int iscsi_sysfs_session_user_created(int sid)
+{
+       char id[NAME_SIZE];
+       pid_t pid;
+
+       snprintf(id, sizeof(id), ISCSI_SESSION_ID, sid);
+       if (sysfs_get_int(id, ISCSI_SESSION_SUBSYS, "creator", &pid))
+               return -1;
+
+       if (pid == -1)
+               return 0;
+       else
+               return 1;
+}
+
+uint32_t iscsi_sysfs_get_host_no_from_sid(uint32_t sid, int *err)
+{
+       struct sysfs_device *session_dev, *host_dev;
+       char devpath[PATH_SIZE];
+       char id[NAME_SIZE];
+
+       *err = 0;
+       snprintf(id, sizeof(id), "session%u", sid);
+       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.", id);
+               *err = ISCSI_ERR_SYSFS_LOOKUP;
+               return 0;
+       }
+
+       session_dev = sysfs_device_get(devpath);
+       if (!session_dev) {
+               log_error("Could not get dev for %s. Possible sysfs "
+                         "incompatibility.", id);
+               *err = ISCSI_ERR_SYSFS_LOOKUP;
+               return 0;
+       }
+
+       /*
+        * 2.6.27 moved from scsi_host to scsi for the subsys when
+        * sysfs compat is not on.
+        */
+       host_dev = sysfs_device_get_parent_with_subsystem(session_dev,
+                                                         SCSI_SUBSYS);
+       if (!host_dev) {
+               struct sysfs_device *dev_parent;
+
+               dev_parent = sysfs_device_get_parent(session_dev);
+               while (dev_parent != NULL) {
+                       if (strncmp(dev_parent->kernel, "host", 4) == 0) {
+                               host_dev = dev_parent;
+                               break;
+                       }
+                       dev_parent = sysfs_device_get_parent(dev_parent);
+               }
+
+               if (!host_dev) {
+                       log_error("Could not get host dev for %s. Possible "
+                                 "sysfs incompatibility.", id);
+                       *err = ISCSI_ERR_SYSFS_LOOKUP;
+                       return 0;
+               }
+       }
+
+       return atol(host_dev->kernel_number);
+}
+
+/* TODO: merge and make macro */
+static int __get_host_no_from_netdev(void *data, struct host_info *info)
+{
+       struct host_info *ret_info = data;
+
+       if (!strcmp(ret_info->iface.netdev, info->iface.netdev)) {
+               ret_info->host_no = info->host_no;
+               return 1;
+       }
+       return 0;
+}
+
+static uint32_t get_host_no_from_netdev(char *netdev, int *rc)
+{
+       uint32_t host_no = -1;
+       struct host_info *info;
+       int nr_found, local_rc;
+
+       *rc = 0;
+
+       info = calloc(1, sizeof(*info));
+       if (!info) {
+               *rc = ISCSI_ERR_NOMEM;
+               return -1;
+       }
+       strcpy(info->iface.netdev, netdev);
+
+       local_rc = iscsi_sysfs_for_each_host(info, &nr_found,
+                                            __get_host_no_from_netdev);
+       if (local_rc == 1)
+               host_no = info->host_no;
+       else
+               *rc = ISCSI_ERR_HOST_NOT_FOUND;
+       free(info);
+       return host_no;
+}
+
+static int __get_host_no_from_hwaddress(void *data, struct host_info *info)
+{
+       struct host_info *ret_info = data;
+
+       if (!strcasecmp(ret_info->iface.hwaddress, info->iface.hwaddress)) {
+               ret_info->host_no = info->host_no;
+               return 1;
+       }
+       return 0;
+}
+
+uint32_t iscsi_sysfs_get_host_no_from_hwaddress(char *hwaddress, int *rc)
+{
+       uint32_t host_no = -1;
+       struct host_info *info;
+       int nr_found, local_rc;
+
+       *rc = 0;
+
+       info = calloc(1, sizeof(*info));
+       if (!info) {
+               log_debug(4, "No memory for host info");
+               *rc = ISCSI_ERR_NOMEM;
+               return -1;
+       }
+       /* make sure there is room for the MAC address plus NULL terminator */
+       if (strlen(hwaddress) > (ISCSI_HWADDRESS_BUF_SIZE - 1)) {
+               log_debug(4, "HW Address \"%s\" too long (%d max)",
+                               hwaddress, ISCSI_HWADDRESS_BUF_SIZE-1);
+               *rc = ISCSI_ERR_INVAL;
+               goto dun;
+       }
+       strncpy(info->iface.hwaddress, hwaddress, ISCSI_HWADDRESS_BUF_SIZE-1);
+
+       local_rc = iscsi_sysfs_for_each_host(info, &nr_found,
+                                       __get_host_no_from_hwaddress);
+       if (local_rc == 1)
+               host_no = info->host_no;
+       else {
+               log_debug(4, "Host not found from HW Address \"%s\"",
+                               hwaddress);
+               *rc = ISCSI_ERR_HOST_NOT_FOUND;
+       }
+dun:
+       free(info);
+       return host_no;
+}
+
+static int __get_host_no_from_ipaddress(void *data, struct host_info *info)
+{
+       struct host_info *ret_info = data;
+
+       if (!strcmp(ret_info->iface.ipaddress, info->iface.ipaddress)) {
+               ret_info->host_no = info->host_no;
+               return 1;
+       }
+       return 0;
+}
+
+static uint32_t get_host_no_from_ipaddress(char *address, int *rc)
+{
+       uint32_t host_no = -1;
+       struct host_info *info;
+       int nr_found;
+       int local_rc;
+
+       *rc = 0;
+
+       info = calloc(1, sizeof(*info));
+       if (!info) {
+               *rc = ISCSI_ERR_NOMEM;
+               return -1;
+       }
+       strcpy(info->iface.ipaddress, address);
+
+       local_rc = iscsi_sysfs_for_each_host(info, &nr_found,
+                                            __get_host_no_from_ipaddress);
+       if (local_rc == 1)
+               host_no = info->host_no;
+       else
+               *rc = ISCSI_ERR_HOST_NOT_FOUND;
+       free(info);
+       return host_no;
+}
+
+uint32_t iscsi_sysfs_get_host_no_from_hwinfo(struct iface_rec *iface, int *rc)
+{
+       int tmp_rc;
+       uint32_t host_no = -1;
+
+       if (strlen(iface->hwaddress) &&
+           strcasecmp(iface->hwaddress, DEFAULT_HWADDRESS))
+               host_no = iscsi_sysfs_get_host_no_from_hwaddress(
+                                               iface->hwaddress, &tmp_rc);
+       else if (strlen(iface->netdev) &&
+               strcasecmp(iface->netdev, DEFAULT_NETDEV))
+               host_no = get_host_no_from_netdev(iface->netdev, &tmp_rc);
+       else if (strlen(iface->ipaddress) &&
+                strcasecmp(iface->ipaddress, DEFAULT_IPADDRESS))
+               host_no = get_host_no_from_ipaddress(iface->ipaddress, &tmp_rc);
+       else
+               tmp_rc = ISCSI_ERR_INVAL;
+
+       *rc = tmp_rc;
+       return host_no;
+}
+
+/*
+ * 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
+               strlcpy(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);
+
+       if (sysfs_get_str(boot_nic, boot_root, "gateway",
+                         iface->gateway, NI_MAXHOST))
+               log_debug(5, "could not read %s/%s/gateway", 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
+ * qla4xxx.
+ */
+static int iscsi_sysfs_read_iface(struct iface_rec *iface, int host_no,
+                                 char *session, char *iface_kern_id)
+{
+       uint32_t tmp_host_no, iface_num;
+       char host_id[NAME_SIZE];
+       struct iscsi_transport *t;
+       int ret, iface_type;
+
+       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
+               strcpy(iface->transport_name, t->name);
+
+       snprintf(host_id, sizeof(host_id), ISCSI_HOST_ID, host_no);
+       /*
+        * backward compat
+        * If we cannot get the address we assume we are doing the old
+        * style and use default.
+        */
+       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", host_no);
+
+       if (iface_kern_id)
+               ret = sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS,
+                                   "ipaddress",
+                                   iface->ipaddress, sizeof(iface->ipaddress));
+       else
+               /* if not found just print out default */
+               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",
+                         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", host_no);
+
+       /*
+        * For drivers like qla4xxx we can only set the iname at the
+        * host level because we cannot create different initiator ports
+        * (cannot set isid either). The LLD also exports the iname at the
+        * hba level so apps can see it, but we no longer set the iname for
+        * each iscsid controlled host since bnx2i cxgbi can support multiple
+        * initiator names and of course software iscsi can support anything.
+        */
+       ret = 1;
+       memset(iface->iname, 0, sizeof(iface->iname));
+       if (session) {
+               ret = sysfs_get_str(session, ISCSI_SESSION_SUBSYS,
+                                   "initiatorname",
+                                   iface->iname, sizeof(iface->iname));
+               /*
+                * qlaxxx will not set this at the session level so we
+                * always drop down for it.
+                *
+                * And.
+                *
+                * For older kernels/tools (2.6.26 and below and 2.0.870)
+                * we will not have a session level initiator name, so
+                * we will drop down.
+                */
+       }
+
+       if (ret) {
+               ret = sysfs_get_str(host_id, ISCSI_HOST_SUBSYS, "initiatorname",
+                                   iface->iname, sizeof(iface->iname));
+               if (ret)
+                       /*
+                        * default iname is picked up later from
+                        * initiatorname.iscsi if software/partial-offload.
+                        *
+                        * TODO: we should make it easier to get the
+                        * global iname so we can just fill it in here.
+                        */
+                       log_debug(7, "Could not read initiatorname for "
+                                 "host%d", host_no);
+               /* optional so do not return error */
+               ret = 0;
+       }
+
+       sysfs_get_str(host_id, ISCSI_HOST_SUBSYS, "port_state",
+                     iface->port_state, sizeof(iface->port_state));
+
+       sysfs_get_str(host_id, ISCSI_HOST_SUBSYS, "port_speed",
+                     iface->port_speed, sizeof(iface->port_speed));
+
+       /*
+        * this is on the session, because we support multiple bindings
+        * per device.
+        */
+       memset(iface->name, 0, sizeof(iface->name));
+       if (session) {
+               /*
+                * this was added after 2.0.869 so we could be doing iscsi_tcp
+                * session binding, but there may not be an ifacename set
+                * if binding is not used.
+                */
+               ret = sysfs_get_str(session, ISCSI_SESSION_SUBSYS, "ifacename",
+                                   iface->name, sizeof(iface->name));
+               if (ret) {
+                       log_debug(7, "could not read iface name for "
+                                 "session %s", session);
+                       /*
+                        * if the ifacename file is not there then we are
+                        * using a older kernel and can try to find the
+                        * binding by the net info which was used on these
+                        * older kernels.
+                        */
+                       if (iface_get_by_net_binding(iface, iface))
+                               log_debug(7, "Could not find iface for session "
+                                         "bound to:" iface_fmt "",
+                                         iface_str(iface));
+               }
+       }
+
+       if (session && t && t->template->use_boot_info)
+               iscsi_sysfs_read_boot(iface, session);
+
+       if (!iface_kern_id)
+               goto done;
+
+       strlcpy(iface->name, iface_kern_id, sizeof(iface->name));
+
+       if (!strncmp(iface_kern_id, "ipv4", 4)) {
+               sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, "bootproto",
+                             iface->bootproto, sizeof(iface->bootproto));
+
+               sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, "gateway",
+                             iface->gateway, sizeof(iface->gateway));
+
+               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",
+                             iface->ipv6_autocfg, sizeof(iface->ipv6_autocfg));
+
+               sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS,
+                             "link_local_addr", iface->ipv6_linklocal,
+                             sizeof(iface->ipv6_linklocal));
+
+               sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS,
+                             "link_local_autocfg", iface->linklocal_autocfg,
+                             sizeof(iface->linklocal_autocfg));
+
+               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",
+                            &iface->port))
+               iface->port = 0;
+       if (sysfs_get_uint16(iface_kern_id, ISCSI_IFACE_SUBSYS, "mtu",
+                            &iface->mtu))
+               iface->mtu = 0;
+       if (sysfs_get_uint16(iface_kern_id, ISCSI_IFACE_SUBSYS, "vlan_id",
+                            &iface->vlan_id))
+               iface->vlan_id = UINT16_MAX;
+
+       if (sysfs_get_uint8(iface_kern_id, ISCSI_IFACE_SUBSYS, "vlan_priority",
+                           &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;
+
+done:
+       if (ret)
+               return ISCSI_ERR_SYSFS_LOOKUP;
+       else
+               return 0;
+}
+
+int iscsi_sysfs_get_hostinfo_by_host_no(struct host_info *hinfo)
+{
+       return iscsi_sysfs_read_iface(&hinfo->iface, hinfo->host_no, NULL,
+                                     NULL);
+}
+
+int iscsi_sysfs_for_each_host(void *data, int *nr_found,
+                             iscsi_sysfs_host_op_fn *fn)
+{
+       struct dirent **namelist;
+       int rc = 0, i, n;
+       struct host_info *info;
+
+       info = malloc(sizeof(*info));
+       if (!info)
+               return ISCSI_ERR_NOMEM;
+
+       n = scandir(ISCSI_HOST_DIR, &namelist, trans_filter,
+                   alphasort);
+       if (n <= 0)
+               goto free_info;
+
+       for (i = 0; i < n; i++) {
+               memset(info, 0, sizeof(*info));
+               if (sscanf(namelist[i]->d_name, "host%u", &info->host_no) !=
+                          1) {
+                       log_error("Invalid iscsi host dir: %s",
+                                 namelist[i]->d_name);
+                       break;
+               }
+
+               iscsi_sysfs_get_hostinfo_by_host_no(info);
+               rc = fn(data, info);
+               if (rc != 0)
+                       break;
+               (*nr_found)++;
+       }
+
+       for (i = 0; i < n; i++)
+               free(namelist[i]);
+       free(namelist);
+
+free_info:
+       free(info);
+       return rc;
+}
+
+int iscsi_sysfs_for_each_iface_on_host(void *data, uint32_t host_no,
+                                      int *nr_found,
+                                      iscsi_sysfs_iface_op_fn *fn)
+{
+       struct dirent **namelist;
+       int rc = 0, i, n;
+       struct iface_rec iface;
+        char devpath[PATH_SIZE];
+        char sysfs_dev_iscsi_iface_path[PATH_SIZE];
+        char id[NAME_SIZE];
+
+        snprintf(id, sizeof(id), "host%u", host_no);
+        if (!sysfs_lookup_devpath_by_subsys_id(devpath, sizeof(devpath),
+                                               SCSI_SUBSYS, id)) {
+                log_error("Could not look up host's ifaces via scsi bus.");
+                return ISCSI_ERR_SYSFS_LOOKUP;
+        }
+
+       sprintf(sysfs_dev_iscsi_iface_path, "/sys");
+       strlcat(sysfs_dev_iscsi_iface_path, devpath, sizeof(sysfs_dev_iscsi_iface_path));
+       strlcat(sysfs_dev_iscsi_iface_path, "/iscsi_iface", sizeof(sysfs_dev_iscsi_iface_path));
+
+       n = scandir(sysfs_dev_iscsi_iface_path, &namelist, trans_filter, alphasort);
+       if (n <= 0)
+               /* older kernels or some drivers will not have ifaces */
+               return 0;
+
+       for (i = 0; i < n; i++) {
+               memset(&iface, 0, sizeof(iface));
+
+               iscsi_sysfs_read_iface(&iface, host_no, NULL,
+                                      namelist[i]->d_name);
+               rc = fn(data, &iface);
+               if (rc != 0)
+                       break;
+               (*nr_found)++;
+       }
+
+       for (i = 0; i < n; i++)
+               free(namelist[i]);
+       free(namelist);
+       return rc;
+}
+
+/**
+ * sysfs_session_has_leadconn - checks if session has lead conn in kernel
+ * @sid: session id
+ *
+ * return 1 if session has lead conn and 0 if not.
+ */
+int iscsi_sysfs_session_has_leadconn(uint32_t sid)
+{
+       char devpath[PATH_SIZE];
+       char id[NAME_SIZE];
+
+       snprintf(id, sizeof(id), "connection%u:0", sid);
+       return sysfs_lookup_devpath_by_subsys_id(devpath, sizeof(devpath),
+                                                ISCSI_CONN_SUBSYS, id);
+}
+
+/*
+ * iscsi_sysfs_get_sid_from_path - parse a string for the sid
+ * @session: session path
+ *
+ * Given sysfs_device is a directory name of the form:
+ *
+ * /sys/devices/platform/hostH/sessionS/targetH:B:I/H:B:I:L
+ * /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 converted
+ * to an int.
+ */
+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_error("%s is an invalid session ID or path", session);
+               exit(1);
+       }
+
+       if (!S_ISDIR(statb.st_mode) && !S_ISLNK(statb.st_mode)) {
+               log_error("%s is not a directory", session);
+               exit(1);
+       }
+
+       if (!strncmp(session, "/sys", 4))
+               strlcpy(devpath, session + 4, sizeof(devpath));
+       else
+               strlcpy(devpath, session, sizeof(devpath));
+
+       dev = sysfs_device_get(devpath);
+       if (!dev) {
+               log_error("Could not get dev for %s. Possible sysfs "
+                         "incompatibility.", devpath);
+               return -1;
+       }
+
+       if (!strncmp(dev->kernel, "session", 7))
+               return atoi(dev->kernel_number);
+
+       dev_parent = sysfs_device_get_parent(dev);
+       while (dev_parent != NULL) {
+               if (strncmp(dev_parent->kernel, "session", 7) == 0)
+                       return atoi(dev_parent->kernel_number);
+               dev_parent = sysfs_device_get_parent(dev_parent);
+       }
+
+       log_error("Unable to find sid in path %s", session);
+       return -1;
+}
+
+int iscsi_sysfs_get_sessioninfo_by_id(struct session_info *info, char *session)
+{
+       char id[NAME_SIZE];
+       int ret, pers_failed = 0;
+       uint32_t host_no;
+
+       if (sscanf(session, "session%d", &info->sid) != 1) {
+               log_error("invalid session '%s'", session);
+               return ISCSI_ERR_INVAL;
+       }
+
+       ret = sysfs_get_str(session, ISCSI_SESSION_SUBSYS, "targetname",
+                           info->targetname, sizeof(info->targetname));
+       if (ret) {
+               log_error("could not read session targetname: %d", ret);
+               return ISCSI_ERR_SYSFS_LOOKUP;
+       }
+
+       ret = sysfs_get_str(session, ISCSI_SESSION_SUBSYS, "username",
+                               (info->chap).username,
+                               sizeof((info->chap).username));
+       if (ret)
+               log_debug(5, "could not read username: %d", ret);
+
+       ret = sysfs_get_str(session, ISCSI_SESSION_SUBSYS, "password",
+                               (info->chap).password,
+                               sizeof((info->chap).password));
+       if (ret)
+               log_debug(5, "could not read password: %d", ret);
+
+       ret = sysfs_get_str(session, ISCSI_SESSION_SUBSYS, "username_in",
+                               (info->chap).username_in,
+                               sizeof((info->chap).username_in));
+       if (ret)
+               log_debug(5, "could not read username in: %d", ret);
+
+       ret = sysfs_get_str(session, ISCSI_SESSION_SUBSYS, "password_in",
+                               (info->chap).password_in,
+                               sizeof((info->chap).password_in));
+       if (ret)
+               log_debug(5, "could not read password in: %d", ret);
+
+       ret = sysfs_get_int(session, ISCSI_SESSION_SUBSYS, "recovery_tmo",
+                               &((info->tmo).recovery_tmo));
+       if (ret)
+               (info->tmo).recovery_tmo = -1;
+
+       ret = sysfs_get_int(session, ISCSI_SESSION_SUBSYS, "lu_reset_tmo",
+                               &((info->tmo).lu_reset_tmo));
+       if (ret)
+               (info->tmo).lu_reset_tmo = -1;
+
+       ret = sysfs_get_int(session, ISCSI_SESSION_SUBSYS, "tgt_reset_tmo",
+                               &((info->tmo).tgt_reset_tmo));
+       if (ret)
+               (info->tmo).lu_reset_tmo = -1;
+
+       sysfs_get_int(session, ISCSI_SESSION_SUBSYS, "abort_tmo",
+                               &((info->tmo).abort_tmo));
+       if (ret)
+               (info->tmo).abort_tmo = -1;
+
+       ret = sysfs_get_int(session, ISCSI_SESSION_SUBSYS, "tpgt",
+                           &info->tpgt);
+       if (ret) {
+               log_error("could not read session tpgt: %d", ret);
+               return ISCSI_ERR_SYSFS_LOOKUP;
+       }
+
+       snprintf(id, sizeof(id), ISCSI_CONN_ID, info->sid);
+       /* some HW drivers do not export addr and port */
+       memset(info->persistent_address, 0, NI_MAXHOST);
+       ret = sysfs_get_str(id, ISCSI_CONN_SUBSYS, "persistent_address",
+                           info->persistent_address,
+                           sizeof(info->persistent_address));
+       if (ret) {
+               pers_failed = 1;
+               /* older qlogic does not support this */
+               log_debug(5, "could not read pers conn addr: %d", ret);
+       }
+
+       memset(info->address, 0, NI_MAXHOST);
+       ret = sysfs_get_str(id, ISCSI_CONN_SUBSYS, "address",
+                           info->address, sizeof(info->address));
+       if (ret) {
+               log_debug(5, "could not read curr addr: %d", ret);
+               /* iser did not export this */
+               if (!pers_failed)
+                       strcpy(info->address, info->persistent_address);
+       } else if (pers_failed)
+               /*
+                * for qla if we could not get the persistent addr
+                * we will use the current for both addrs
+                */
+               strcpy(info->persistent_address, info->address);
+       pers_failed = 0;
+
+       info->persistent_port = -1;
+       ret = sysfs_get_int(id, ISCSI_CONN_SUBSYS, "persistent_port",
+                           &info->persistent_port);
+       if (ret) {
+               pers_failed = 1;
+               log_debug(5, "Could not read pers conn port %d", ret);
+       }
+
+       info->port = -1;
+       ret = sysfs_get_int(id, ISCSI_CONN_SUBSYS, "port", &info->port);
+       if (ret) {
+               /* iser did not export this */
+               if (!pers_failed)
+                       info->port = info->persistent_port;
+               log_debug(5, "Could not read curr conn port %d", ret);
+       } else if (pers_failed)
+               /*
+                * for qla if we could not get the persistent addr
+                * we will use the current for both addrs
+                */
+               info->persistent_port = info->port;
+
+       ret = 0;
+       host_no = iscsi_sysfs_get_host_no_from_sid(info->sid, &ret);
+       if (ret) {
+               log_error("could not get host_no for session%d: %s.",
+                         info->sid, iscsi_err_to_str(ret));
+               return ret;
+       }
+
+       iscsi_sysfs_read_iface(&info->iface, host_no, session, NULL);
+
+       log_debug(7, "found targetname %s address %s pers address %s port %d "
+                "pers port %d driver %s iface name %s ipaddress %s "
+                "netdev %s hwaddress %s iname %s",
+                 info->targetname, info->address[0] ? info->address : "NA",
+                 info->persistent_address[0] ? info->persistent_address : "NA",
+                 info->port, info->persistent_port, info->iface.transport_name,
+                 info->iface.name, info->iface.ipaddress,
+                 info->iface.netdev, info->iface.hwaddress,
+                 info->iface.iname);
+       return 0;
+}
+
+int iscsi_sysfs_for_each_session(void *data, int *nr_found,
+                                iscsi_sysfs_session_op_fn *fn,
+                                int in_parallel)
+{
+       struct dirent **namelist;
+       int rc = 0, n, i, chldrc = 0;
+       struct session_info *info;
+       pid_t pid = 0;
+
+       info = calloc(1, sizeof(*info));
+       if (!info)
+               return ISCSI_ERR_NOMEM;
+
+       info->iscsid_req_tmo = ISCSID_RESP_POLL_TIMEOUT;
+       n = scandir(ISCSI_SESSION_DIR, &namelist, trans_filter,
+                   alphasort);
+       if (n <= 0)
+               goto free_info;
+
+       for (i = 0; i < n; i++) {
+               rc = iscsi_sysfs_get_sessioninfo_by_id(info,
+                                                      namelist[i]->d_name);
+               if (rc) {
+                       log_error("could not find session info for %s",
+                                  namelist[i]->d_name);
+                       /* raced. session was shutdown while looping */
+                       rc = 0;
+                       continue;
+               }
+
+               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 (!WIFEXITED(chldrc)) {
+                               /*
+                                * abnormal termination (signal, exception, etc.)
+                                *
+                                * The non-parallel code path returns the first
+                                * error so this keeps the same semantics.
+                                */
+                               if (rc == 0)
+                                       rc = ISCSI_ERR_CHILD_TERMINATED;
+                       } else if ((WEXITSTATUS(chldrc) != 0) &&
+                                  (WEXITSTATUS(chldrc) != 255)) {
+                               /*
+                                * 0 is success
+                                * 255 is a truncated return code from exit(-1)
+                                *     and means no match
+                                * anything else (this case) is an error
+                                */
+                               if (rc == 0)
+                                       rc = WEXITSTATUS(chldrc);
+                       } else if (WEXITSTATUS(chldrc) == 0) {
+                               /* success */
+                               (*nr_found)++;
+                       }
+               }
+       }
+
+       for (i = 0; i < n; i++)
+               free(namelist[i]);
+       free(namelist);
+
+free_info:
+       free(info);
+       return rc;
+}
+
+/*
+ * count the number of sessions -- a much-simplified
+ * version of iscsi_sysfs_for_each_session
+ *
+ * TODO: return an array of the session info we find, for use
+ * by iscsi_sysfs_for_each_session(), so it doesn't have to
+ * do it all over again
+ */
+int iscsi_sysfs_count_sessions(void)
+{
+       struct dirent **namelist = NULL;
+       int n, i;
+       struct session_info *info;
+
+
+       info = calloc(1, sizeof(*info));
+       if (!info)
+               /* no sessions found */
+               return 0;
+       info->iscsid_req_tmo = -1;
+
+       n = scandir(ISCSI_SESSION_DIR, &namelist, trans_filter, alphasort);
+       if (n <= 0)
+               /* no sessions found */
+               goto free_info;
+
+       /*
+        * try to get session info for each session found, but ignore
+        * errors if any since it may be a race condition
+        */
+       for (i = 0; i < n; i++)
+               if (iscsi_sysfs_get_sessioninfo_by_id(info,
+                                       namelist[i]->d_name) != 0)
+                       log_warning("could not find session info for %s",
+                                       namelist[i]->d_name);
+
+       for (i = 0; i < n; i++)
+               free(namelist[i]);
+       free(namelist);
+
+free_info:
+       free(info);
+       return n;
+}
+
+int iscsi_sysfs_get_session_state(char *state, int sid)
+{
+       char id[NAME_SIZE];
+
+       snprintf(id, sizeof(id), ISCSI_SESSION_ID, sid);
+       if (sysfs_get_str(id, ISCSI_SESSION_SUBSYS, "state", state,
+                         SCSI_MAX_STATE_VALUE))
+               return ISCSI_ERR_SYSFS_LOOKUP;
+       return 0;
+}
+
+int iscsi_sysfs_get_host_state(char *state, int host_no)
+{
+       char id[NAME_SIZE];
+
+       snprintf(id, sizeof(id), ISCSI_HOST_ID, host_no);
+       if (sysfs_get_str(id, SCSI_HOST_SUBSYS, "state", state,
+                         SCSI_MAX_STATE_VALUE))
+               return ISCSI_ERR_SYSFS_LOOKUP;
+       return 0;
+}
+
+int iscsi_sysfs_get_device_state(char *state, int host_no, int target, int lun)
+{
+       char id[NAME_SIZE];
+
+       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", id);
+               return ISCSI_ERR_SYSFS_LOOKUP;
+       }
+
+       return 0;
+}
+
+char *iscsi_sysfs_get_blockdev_from_lun(int host_no, int target, int lun)
+{
+       char devpath[PATH_SIZE];
+       char path_full[PATH_SIZE];
+       char id[NAME_SIZE];
+       DIR *dirfd;
+       struct dirent *dent;
+       size_t sysfs_len;
+       struct stat statbuf;
+       char *blockdev, *blockdup = NULL;
+
+       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",
+                         SCSI_SUBSYS, id);
+               return NULL;
+       }
+
+       sysfs_len = strlcpy(path_full, sysfs_path, sizeof(path_full));
+       if (sysfs_len >= sizeof(path_full))
+               sysfs_len = sizeof(path_full) - 1;
+       strlcat(path_full, devpath, sizeof(path_full));
+
+       dirfd = opendir(path_full);
+       if (!dirfd)
+               return NULL;
+
+       while ((dent = readdir(dirfd))) {
+               if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
+                       continue;
+
+               /* not sure what tape looks like */
+               if (strncmp(dent->d_name, "block:", 5))
+                       continue;
+
+               strlcat(path_full, "/", sizeof(path_full));
+               strlcat(path_full, dent->d_name, sizeof(path_full));
+               /*
+                * 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",
+                                 path_full, errno);
+                       break;
+               }
+
+               if (S_ISLNK(statbuf.st_mode)) {
+                       blockdev = strchr(dent->d_name, ':');
+                       if (!blockdev)
+                               break;
+                       /* increment past colon */
+                       blockdev++;
+                       blockdup = strdup(blockdev);
+               } else if (S_ISDIR(statbuf.st_mode)) {
+                       DIR *blk_dirfd;
+                       struct dirent *blk_dent;
+
+                       /* 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",
+                                         path_full);
+                               break;
+                       }
+
+                       while ((blk_dent = readdir(blk_dirfd))) {
+                               if (!strcmp(blk_dent->d_name, ".") ||
+                                   !strcmp(blk_dent->d_name, ".."))
+                                       continue;
+                               blockdup = strdup(blk_dent->d_name);
+                               break;
+                       }
+                       closedir(blk_dirfd);
+               }
+
+               break;
+       }
+       closedir(dirfd);
+       return blockdup;
+}
+
+static uint32_t get_target_no_from_sid(uint32_t sid, int *err)
+{
+       char devpath[PATH_SIZE];
+       char path_full[PATH_SIZE];
+       char id[NAME_SIZE];
+       DIR *dirfd;
+       struct dirent *dent;
+       uint32_t host, bus, target = 0;
+       size_t sysfs_len;
+
+       *err = ISCSI_ERR_SESS_NOT_FOUND;
+
+       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",
+                         ISCSI_SESSION_SUBSYS, id);
+               return 0;
+       }
+
+       /*
+        * This does not seem safe from future changes, but we currently
+        * want /devices/platform/hostY/sessionX, but we come from the
+        * /class/iscsi_session/sessionX/device.
+        */
+       sysfs_len = strlcpy(path_full, sysfs_path, sizeof(path_full));
+       if (sysfs_len >= sizeof(path_full))
+               sysfs_len = sizeof(path_full) - 1;
+       strlcat(path_full, devpath, sizeof(path_full));
+       strlcat(path_full, "/device", sizeof(devpath));
+
+       dirfd = opendir(path_full);
+       if (!dirfd)
+               return 0;
+
+       while ((dent = readdir(dirfd))) {
+               if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
+                       continue;
+
+               if (strncmp(dent->d_name, "target", 6))
+                       continue;
+
+               if (sscanf(dent->d_name, "target%u:%u:%u",
+                          &host, &bus, &target) != 3)
+                       break;
+
+               *err = 0;
+               break;
+
+       }
+       closedir(dirfd);
+       return target;
+
+}
+
+int iscsi_sysfs_is_transport_loaded(char *transport_name)
+{
+       struct iscsi_transport *t;
+
+       /* sync up kernel and userspace */
+       read_transports();
+
+       /* check if the transport is loaded and matches */
+       list_for_each_entry(t, &transports, list) {
+               if (t->handle && !strncmp(t->name, transport_name,
+                                         ISCSI_TRANSPORT_NAME_MAXLEN))
+                       return 1;
+       }
+
+       return 0;
+}
+
+struct iscsi_transport *iscsi_sysfs_get_transport_by_name(char *transport_name)
+{
+       struct iscsi_transport *t;
+       int retry = 0;
+
+retry:
+       /* sync up kernel and userspace */
+       read_transports();
+
+       /* check if the transport is loaded and matches */
+       list_for_each_entry(t, &transports, list) {
+               if (t->handle && !strncmp(t->name, transport_name,
+                                         ISCSI_TRANSPORT_NAME_MAXLEN))
+                       return t;
+       }
+
+       if (retry < 1) {
+               retry++;
+               if (!transport_load_kmod(transport_name))
+                       goto retry;
+       }
+
+       return NULL;
+}
+
+/* TODO: replace the following functions with some decent sysfs links */
+struct iscsi_transport *iscsi_sysfs_get_transport_by_hba(uint32_t host_no)
+{
+       char name[ISCSI_TRANSPORT_NAME_MAXLEN];
+       char id[NAME_SIZE];
+       int rc;
+
+       if (host_no > MAX_HOST_NO)
+               return NULL;    /* not set? */
+
+       snprintf(id, sizeof(id), ISCSI_HOST_ID, host_no);
+       rc = sysfs_get_str(id, SCSI_HOST_SUBSYS, "proc_name", name,
+                          ISCSI_TRANSPORT_NAME_MAXLEN);
+       if (rc) {
+               log_error("Could not read proc_name for host%u rc %d.",
+                         host_no, rc);
+               return NULL;
+       }
+
+       /*
+        * stupid, stupid. We named the transports tcp or iser, but the
+        * the modules are named iscsi_tcp and iscsi_iser
+        */
+       if (strstr(name, "iscsi_"))
+               return iscsi_sysfs_get_transport_by_name(name + 6);
+       else
+               return iscsi_sysfs_get_transport_by_name(name);
+}
+
+struct iscsi_transport *iscsi_sysfs_get_transport_by_sid(uint32_t sid)
+{
+       uint32_t host_no;
+       int err;
+
+       host_no = iscsi_sysfs_get_host_no_from_sid(sid, &err);
+       if (err)
+               return NULL;
+       return iscsi_sysfs_get_transport_by_hba(host_no);
+}
+
+/*
+ * For connection reinstatement we need to send the exp_statsn from
+ * the previous connection
+ *
+ * This is only called when the connection is halted so exp_statsn is safe
+ * to read without racing.
+ */
+int iscsi_sysfs_get_exp_statsn(int sid)
+{
+       char id[NAME_SIZE];
+       uint32_t exp_statsn = 0;
+
+       snprintf(id, sizeof(id), ISCSI_CONN_ID, sid);
+       if (sysfs_get_uint(id, ISCSI_CONN_SUBSYS, "exp_statsn",
+                          &exp_statsn)) {
+               log_error("Could not read expstatsn for sid %d. "
+                         "Using zero for exp_statsn.", sid);
+               exp_statsn = 0;
+       }
+       return exp_statsn;
+}
+
+int iscsi_sysfs_session_supports_nop(int sid)
+{
+       char id[NAME_SIZE];
+       uint32_t ping_tmo = 0;
+
+       snprintf(id, sizeof(id), ISCSI_CONN_ID, sid);
+       if (sysfs_get_uint(id, ISCSI_CONN_SUBSYS, "ping_tmo",
+                          &ping_tmo)) {
+               return 0;
+       }
+       return 1;
+}
+
+int iscsi_sysfs_for_each_device(void *data, int host_no, uint32_t sid,
+                               void (* fn)(void *data, int host_no,
+                                           int target, int lun))
+{
+       struct dirent **namelist;
+       int h, b, t, l, i, n, err = 0, target;
+       char devpath[PATH_SIZE];
+       char id[NAME_SIZE];
+       char path_full[3*PATH_SIZE];
+
+       target = get_target_no_from_sid(sid, &err);
+       if (err)
+               return 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",
+                         ISCSI_SESSION_SUBSYS, id);
+               return ISCSI_ERR_SYSFS_LOOKUP;
+       }
+
+       snprintf(path_full, sizeof(path_full), "%s%s/device/target%d:0:%d",
+                sysfs_path, devpath, host_no, target);
+
+       if (strlen(path_full) > PATH_SIZE) {
+               log_debug(3, "Could not lookup devpath for %s %s (too long)",
+                         ISCSI_SESSION_SUBSYS, id);
+               return ISCSI_ERR_SYSFS_LOOKUP;
+       }
+
+       n = scandir(path_full, &namelist, trans_filter,
+                   alphasort);
+       if (n <= 0)
+               return 0;
+
+       for (i = 0; i < n; i++) {
+               if (sscanf(namelist[i]->d_name, "%d:%d:%d:%d\n",
+                          &h, &b, &t, &l) != 4)
+                       continue;
+               fn(data, h, t, l);
+       }
+
+       for (i = 0; i < n; i++)
+               free(namelist[i]);
+       free(namelist);
+
+       return 0;
+}
+
+void iscsi_sysfs_set_queue_depth(void *data, int hostno, int target, int lun)
+{
+       char id[NAME_SIZE];
+       char write_buf[20];
+       int err, qdepth = *((int *)data);
+
+       snprintf(id, sizeof(id), "%d:0:%d:%d", hostno, target, lun);
+       snprintf(write_buf, sizeof(write_buf), "%d", qdepth);
+       log_debug(4, "set queue depth for %s to %s", id, write_buf);
+
+       err = sysfs_set_param(id, SCSI_SUBSYS, "queue_depth", write_buf,
+                             strlen(write_buf));
+       if (err && err != EINVAL)
+               log_error("Could not queue depth for LUN %d err %d.", lun, err);
+}
+
+void iscsi_sysfs_set_device_online(__attribute__((unused))void *data,
+                                  int hostno, int target, int lun)
+{
+       char *write_buf = "running\n", *state;
+       char id[NAME_SIZE];
+       int err;
+
+       snprintf(id, sizeof(id), "%d:0:%d:%d", hostno, target, lun);
+       log_debug(4, "online device %s", id);
+
+       state = sysfs_get_value(id, SCSI_SUBSYS, "state");
+       if (!state) {
+               log_error("Could not read state for LUN %s\n", id);
+               goto set_state;
+       }
+
+       if (!strcmp(state, "running"))
+               goto done;
+       /*
+        * The kernel can start to perform session level recovery cleanup
+        * any time after the conn start call, so we only want to change the
+        * state if we are in one of the offline states.
+        */
+       if (strcmp(state, "offline") && strcmp(state, "transport-offline")) {
+               log_debug(4, "Dev not offline. Skip onlining %s", id);
+               goto done;
+       }
+
+set_state:
+       err = sysfs_set_param(id, SCSI_SUBSYS, "state", write_buf,
+                             strlen(write_buf));
+       if (err && err != EINVAL)
+               /* we should read the state */
+               log_error("Could not online LUN %d err %d.", lun, err);
+
+done:
+       if (state)
+               free(state);
+}
+
+void iscsi_sysfs_rescan_device(__attribute__((unused))void *data,
+                              int hostno, int target, int lun)
+{
+       char *write_buf = "1";
+       char id[NAME_SIZE];
+
+       snprintf(id, sizeof(id), "%d:0:%d:%d", hostno, target, lun);
+       log_debug(4, "rescanning device %s", id);
+       sysfs_set_param(id, SCSI_SUBSYS, "rescan", write_buf,
+                       strlen(write_buf));
+}
+
+pid_t iscsi_sysfs_scan_host(int hostno, int async, int autoscan)
+{
+       char id[NAME_SIZE];
+       char *write_buf = "- - -";
+       pid_t pid = 0;
+
+       if (async)
+               pid = fork();
+
+       if (pid >= 0 && !autoscan) {
+               if (pid)
+                       log_debug(4, "host%d in manual scan mode, skipping scan", hostno);
+       } else if (pid == 0) {
+               /* child */
+               log_debug(4, "scanning host%d", hostno);
+
+               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", hostno);
+       } else if (pid > 0) {
+               log_debug(4, "scanning host%d from pid %d", hostno, pid);
+       } else
+               /*
+                * Session is fine, so log the error and let the user
+                * scan by hand
+                 */
+               log_error("Could not start scanning process for host %d "
+                         "err %d. Try scanning through sysfs.", hostno,
+                         errno);
+       return pid;
+}
+
+struct iscsi_transport *iscsi_sysfs_get_transport_by_session(char *sys_session)
+{
+       uint32_t sid;
+
+        if (sscanf(sys_session, "session%u", &sid) != 1) {
+                log_error("invalid session '%s'.", sys_session);
+                return NULL;
+        }
+
+       return iscsi_sysfs_get_transport_by_sid(sid);
+}
+
+char *iscsi_sysfs_get_iscsi_kernel_version(void)
+{
+       return sysfs_attr_get_value("/module/scsi_transport_iscsi", "version");
+}
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/iscsi_sysfs.h b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/iscsi_sysfs.h
new file mode 100644 (file)
index 0000000..9575c65
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * iSCSI sysfs
+ *
+ * Copyright (C) 2006 Mike Christie
+ * Copyright (C) 2006 Red Hat, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+#ifndef ISCSI_SYSFS_H
+#define ISCSI_SYSFS_H
+
+#include <sys/types.h>
+
+#include "sysfs.h"
+#include "types.h"
+#include "iscsi_proto.h"
+#include "config.h"
+
+struct session_info;
+struct host_info;
+struct iscsi_session;
+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
+#define ISCSID_RESP_POLL_TIMEOUT 60000
+
+extern void free_transports(void);
+extern char *iscsi_sysfs_get_iscsi_kernel_version(void);
+extern int iscsi_sysfs_get_sessioninfo_by_id(struct session_info *info,
+                                            char *sys_session);
+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,
+                                       int in_parallel);
+extern int iscsi_sysfs_count_sessions(void);
+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);
+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);
+
+static inline int is_valid_operational_value(int value)
+{
+       return value != -1;
+}
+
+extern void iscsi_sysfs_get_auth_conf(int sid, struct iscsi_auth_config *conf);
+extern void iscsi_sysfs_get_negotiated_session_conf(int sid,
+                               struct iscsi_session_operational_config *conf);
+extern void iscsi_sysfs_get_negotiated_conn_conf(int sid,
+                               struct iscsi_conn_operational_config *conf);
+extern pid_t iscsi_sysfs_scan_host(int hostno, int async, int autoscan);
+extern int iscsi_sysfs_get_session_state(char *state, int sid);
+extern int iscsi_sysfs_get_host_state(char *state, int host_no);
+extern int iscsi_sysfs_get_device_state(char *state, int host_no, int target,
+                                       int lun);
+extern int iscsi_sysfs_get_exp_statsn(int sid);
+extern void iscsi_sysfs_set_queue_depth(void *data, int hostno, int target,
+                                       int lun);
+extern void iscsi_sysfs_set_device_online(void *data, int hostno, int target,
+                                         int lun);
+extern void iscsi_sysfs_rescan_device(void *data, int hostno, int target,
+                                     int lun);
+extern int iscsi_sysfs_for_each_device(void *data, int host_no, uint32_t sid,
+                               void (* fn)(void *, int host_no, int target,
+                                           int lun));
+extern struct iscsi_transport *iscsi_sysfs_get_transport_by_hba(uint32_t host_no);
+extern struct iscsi_transport *iscsi_sysfs_get_transport_by_session(char *sys_session);
+extern struct iscsi_transport *iscsi_sysfs_get_transport_by_sid(uint32_t sid);
+extern struct iscsi_transport *iscsi_sysfs_get_transport_by_name(char *transport_name);
+extern int iscsi_sysfs_is_transport_loaded(char *transport_name);
+extern int iscsi_sysfs_session_supports_nop(int sid);
+extern int iscsi_sysfs_session_user_created(int sid);
+
+extern struct list_head transports;
+
+#endif
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/iscsi_timer.c b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/iscsi_timer.c
new file mode 100644 (file)
index 0000000..de38286
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * iSCSI timer
+ *
+ * Copyright (C) 2002 Cisco Systems, Inc.
+ *
+ * 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 <sys/time.h>
+
+void iscsi_timer_clear(struct timeval *timer)
+{
+       memset(timer, 0, sizeof (*timer));
+}
+
+/* set timer to now + seconds */
+void iscsi_timer_set(struct timeval *timer, int seconds)
+{
+       if (timer) {
+               memset(timer, 0, sizeof (*timer));
+               gettimeofday(timer, NULL);
+
+               timer->tv_sec += seconds;
+       }
+}
+
+int iscsi_timer_expired(struct timeval *timer)
+{
+       struct timeval now;
+
+       /* no timer, can't have expired */
+       if ((timer == NULL) || ((timer->tv_sec == 0) && (timer->tv_usec == 0)))
+               return 0;
+
+       memset(&now, 0, sizeof (now));
+       gettimeofday(&now, NULL);
+
+       if (now.tv_sec > timer->tv_sec)
+               return 1;
+       if ((now.tv_sec == timer->tv_sec) && (now.tv_usec >= timer->tv_usec))
+               return 1;
+       return 0;
+}
+
+int iscsi_timer_msecs_until(struct timeval *timer)
+{
+       struct timeval now;
+       int msecs;
+       long partial;
+
+       /* no timer, can't have expired, infinite time til it expires */
+       if ((timer == NULL) || ((timer->tv_sec == 0) && (timer->tv_usec == 0)))
+               return -1;
+
+       memset(&now, 0, sizeof (now));
+       gettimeofday(&now, NULL);
+
+       /* already expired? */
+       if (now.tv_sec > timer->tv_sec)
+               return 0;
+       if ((now.tv_sec == timer->tv_sec) && (now.tv_usec >= timer->tv_usec))
+               return 0;
+
+       /* not expired yet, do the math */
+       partial = timer->tv_usec - now.tv_usec;
+       if (partial < 0) {
+               partial += 1000 * 1000;
+               msecs = (partial + 500) / 1000;
+               msecs += (timer->tv_sec - now.tv_sec - 1) * 1000;
+       } else {
+               msecs = (partial + 500) / 1000;
+               msecs += (timer->tv_sec - now.tv_sec) * 1000;
+       }
+
+       return msecs;
+}
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/iscsi_timer.h b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/iscsi_timer.h
new file mode 100644 (file)
index 0000000..13e8368
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * iSCSI timer
+ *
+ * Copyright (C) 2002 Cisco Systems, Inc.
+ *
+ * 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 ISCSI_TIMER_H
+#define ISCSI_TIMER_H
+
+struct timeval;
+
+extern void iscsi_timer_clear(struct timeval *timer);
+extern void iscsi_timer_set(struct timeval *timer, int seconds);
+extern int iscsi_timer_expired(struct timeval *timer);
+extern int iscsi_timer_msecs_until(struct timeval *timer);
+
+#endif
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/iscsi_util.c b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/iscsi_util.c
new file mode 100644 (file)
index 0000000..db1dc37
--- /dev/null
@@ -0,0 +1,387 @@
+/*
+ * Misc helpers
+ *
+ * Copyright (C) 2004 Dmitry Yusupov, Alex Aizman
+ * Copyright (C) 2006 - 2010 Mike Christie
+ * Copyright (C) 2006 - 2010 Red Hat, Inc. All rights reserved.
+ * 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 <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#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;
+
+       fd = open("/dev/null", O_RDWR);
+       if (fd == -1) {
+               exit(-1);
+       }
+
+       dup2(fd, 0);
+       dup2(fd, 1);
+       dup2(fd, 2);
+       setsid();
+       if (chdir("/") < 0)
+               log_debug(1, "Could not chdir to /: %s", strerror(errno));
+       close(fd);
+}
+
+#define ISCSI_OOM_PATH_LEN 48
+
+int oom_adjust(void)
+{
+       int fd;
+       char path[ISCSI_OOM_PATH_LEN];
+       struct stat statb;
+
+       errno = 0;
+       if (nice(-10) == -1 && errno != 0)
+               log_debug(1, "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(1, "Could not set oom score to -16: %s",
+                         strerror(errno));
+       if (write(fd, "-17", 3) < 0) /* for Andrea's patch */
+               log_debug(1, "Could not set oom score to -17: %s",
+                         strerror(errno));
+       close(fd);
+       return 0;
+}
+
+char*
+str_to_ipport(char *str, int *port, int *tpgt)
+{
+       char *stpgt, *sport = str, *ip = str;
+
+       if (!strchr(ip, '.')) {
+               if (*ip == '[') {
+                       /* IPv6 with [] */
+                       if (!(sport = strchr(ip, ']')))
+                               return NULL;
+                       *sport++ = '\0';
+                       ip++;
+                       str = sport;
+               } else {
+                       /* hostname or ipv6 */
+                       sport = strchr(ip, ':');
+                       if (sport) {
+                               if (strchr(sport + 1, ':'))
+                                       /* ipv6 */
+                                       sport = NULL;
+                               else
+                                       /* hostname:port */
+                                       str = sport;
+                       }
+               }
+       }
+
+       if (sport && (sport = strchr(str, ':'))) {
+               *sport++ = '\0';
+               *port = strtoul(sport, NULL, 10);
+               str = sport;
+       }
+
+       if ((stpgt = strchr(str, ','))) {
+               *stpgt++ = '\0';
+               *tpgt = strtoul(stpgt, NULL, 10);
+       } else
+               *tpgt = PORTAL_GROUP_TAG_UNKNOWN;
+
+       log_debug(2, "ip %s, port %d, tgpt %d", ip, *port, *tpgt);
+       return ip;
+}
+
+#define ISCSI_MAX_FILES 16384
+
+int increase_max_files(void)
+{
+       struct rlimit rl;
+       int err;
+
+       err = getrlimit(RLIMIT_NOFILE, &rl);
+       if (err) {
+               log_debug(1, "Could not get file limit (err %d)", errno);
+               return errno;
+       }
+       log_debug(1, "Max file limits %lu %lu",
+                       (long unsigned)rl.rlim_cur,
+                       (long unsigned)rl.rlim_max);
+
+       if (rl.rlim_cur < ISCSI_MAX_FILES)
+               rl.rlim_cur = ISCSI_MAX_FILES;
+       if (rl.rlim_max < ISCSI_MAX_FILES)
+               rl.rlim_max = ISCSI_MAX_FILES;
+
+       err = setrlimit(RLIMIT_NOFILE, &rl);
+       if (err) {
+               log_debug(1, "Could not set file limit to %lu/%lu (err %d)",
+                         (long unsigned)rl.rlim_cur,
+                         (long unsigned)rl.rlim_max, errno);
+               return errno;
+       }
+
+       return 0;
+}
+
+/*
+ * from linux kernel
+ */
+char *strstrip(char *s)
+{
+       size_t size;
+       char *end;
+
+       size = strlen(s);
+       if (!size)
+               return s;
+
+       end = s + size - 1;
+       while (end >= s && isspace(*end))
+               end--;
+       *(end + 1) = '\0';
+
+       while (*s && isspace(*s))
+               s++;
+
+       return s;
+}
+
+/**
+ * cfg_get_string_param - return param value
+ * @pathname: pathname and filename of config file
+ * @key: param name
+ *
+ * Assumes the delim is a "=". "#" comments a line, but if
+ * the "#" is after the key= then it is a valid value.
+*/
+char *cfg_get_string_param(char *pathname, const char *key)
+{
+       FILE *f = NULL;
+       char *line, buffer[1024];
+       char *value = NULL, *param, *comment;
+
+       if (!pathname) {
+               log_error("No pathname to load %s from", key);
+               return NULL;
+       }
+
+       if ((f = fopen(pathname, "r"))) {
+               while ((line = fgets(buffer, sizeof (buffer), f))) {
+                       param = strstr(line, key);
+                       if (!param)
+                               continue;
+
+                       /* make sure it is not commented out */
+                       comment = strchr(line, '#');
+                       if (comment) {
+                               if (comment < param)
+                                       continue;
+                       }
+
+                       param = strchr(param, '=');
+                       if (!param) {
+                               log_error("Invalid config line for %s. "
+                                         "Missing '='.", key);
+                               continue;
+                       }
+
+                       param++;
+                       if (!strlen(param)) {
+                               log_error("Invalid config line for %s. "
+                                         "Missing value", key);
+                               continue;
+                       }
+
+                       param = strstrip(param);
+                       if (!strlen(param)) {
+                               log_error("Invalid config line for %s. "
+                                         "Missing value", key);
+                               continue;
+                       }
+
+                       value = strdup(param);
+                       break;
+               }
+               fclose(f);
+               if (value)
+                       log_debug(5, "%s=%s", key, value);
+       } else
+               log_error("can't open %s configuration file %s", key, pathname);
+
+       return value;
+}
+
+/**
+ * iscsi_addr_match - check if the addrs are to the same ip
+ * @address1: pattern
+ * @address2: address to check
+ *
+ * If address1 is blank then it matches any string passed in.
+ */
+static int iscsi_addr_match(char *address1, char *address2)
+{
+       struct addrinfo hints1, hints2, *res1, *res2;
+       int rc;
+
+       if (!strlen(address1))
+               return 1;
+
+       if (!strcmp(address1, address2))
+               return 1;
+
+       memset(&hints1, 0, sizeof(struct addrinfo));
+       hints1.ai_family = AF_UNSPEC;
+       hints1.ai_socktype = SOCK_STREAM;
+
+       memset(&hints2, 0, sizeof(struct addrinfo));
+       hints2.ai_family = AF_UNSPEC;
+       hints2.ai_socktype = SOCK_STREAM;
+
+       /*
+        * didn't match so we have to resolve to see if one is a dnsname
+        * that matches an ip address.
+        */
+       rc = getaddrinfo(address1, NULL, &hints1, &res1);
+       if (rc) {
+               log_debug(1, "Match error. Could not resolve %s: %s", address1,
+                         gai_strerror(rc));
+               return 0;
+
+       }
+
+       rc = getaddrinfo(address2, NULL, &hints2, &res2);
+       if (rc) {
+               log_debug(1, "Match error. Could not resolve %s: %s", address2,
+                         gai_strerror(rc));
+               rc = 0;
+               goto free_res1;
+       }
+
+       if ((res1->ai_addrlen != res2->ai_addrlen) ||
+           memcmp(res1->ai_addr, res2->ai_addr, res2->ai_addrlen))
+               rc = 0;
+       else
+               rc = 1;
+
+       freeaddrinfo(res2);
+free_res1:
+       freeaddrinfo(res1);
+       return rc;
+}
+
+int __iscsi_match_session(node_rec_t *rec, char *targetname,
+                         char *address, int port, struct iface_rec *iface,
+                         unsigned sid)
+{
+       if (!rec) {
+               log_debug(6, "no rec info to match");
+               return 1;
+       }
+
+       log_debug(6, "match session [%s,%s,%d][%s %s,%s,%s]:%u",
+                 rec->name, rec->conn[0].address, rec->conn[0].port,
+                 rec->iface.name, rec->iface.transport_name,
+                 rec->iface.hwaddress, rec->iface.ipaddress,
+                 rec->session.sid);
+
+       if (iface)
+               log_debug(6, "to [%s,%s,%d][%s %s,%s,%s]:%u",
+                         targetname, address, port, iface->name,
+                         iface->transport_name, iface->hwaddress,
+                         iface->ipaddress, sid);
+
+       if (rec->session.sid && sid && rec->session.sid != sid)
+               return 0;
+
+       if (strlen(rec->name) && strcmp(rec->name, targetname))
+               return 0;
+
+       if (!iscsi_addr_match(rec->conn[0].address, address))
+               return 0;
+
+       if (rec->conn[0].port != -1 && port != rec->conn[0].port)
+               return 0;
+
+       if (!iface_match(&rec->iface, iface))
+               return 0;
+
+       return 1;
+}
+
+int iscsi_match_session(void *data, struct session_info *info)
+{
+       return __iscsi_match_session(data, info->targetname,
+                                    info->persistent_address,
+                                    info->persistent_port, &info->iface,
+                                    info->sid);
+}
+
+int iscsi_match_session_count(void *data, struct session_info *info)
+{
+       /*
+        * iscsi_sysfs_for_each_session expects:
+        *   0==match -1==nomatch >0==error
+        * but iscsi_match_session returns:
+        *   1==match 0==nomatch
+        */
+       if (iscsi_match_session(data, info))
+               return 0;
+       return -1;
+}
+
+int iscsi_match_target(void *data, struct session_info *info)
+{
+       return __iscsi_match_session(data, info->targetname,
+                                    info->persistent_address,
+                                    info->persistent_port, NULL,
+                                    MATCH_ANY_SID);
+}
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/iscsi_util.h b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/iscsi_util.h
new file mode 100644 (file)
index 0000000..ff725eb
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef ISCSI_UTIL_H
+#define ISCSI_UTIL_H
+
+#include <stdint.h>
+
+struct node_rec;
+struct iface_rec;
+struct session_info;
+
+extern int oom_adjust(void);
+extern void daemon_init(void);
+extern int increase_max_files(void);
+
+extern char *str_to_ipport(char *str, int *port, int *tgpt);
+
+extern int iscsi_match_session(void *data, struct session_info *info);
+extern int iscsi_match_target(void *data, struct session_info *info);
+extern int iscsi_match_session_count(void *data, struct session_info *info);
+extern int __iscsi_match_session(struct node_rec *rec, char *targetname,
+                                char *address, int port,
+                                struct iface_rec *iface,
+                                unsigned sid);
+
+#define MATCH_ANY_SID 0
+
+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/pkgs/open-iscsi/open-iscsi-2.1.8/usr/iscsiadm.c b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/iscsiadm.c
new file mode 100644 (file)
index 0000000..862bcb6
--- /dev/null
@@ -0,0 +1,4147 @@
+/*
+ * iSCSI Administration Utility
+ *
+ * Copyright (C) 2004 Dmitry Yusupov, Alex Aizman
+ * Copyright (C) 2006 Mike Christie
+ * Copyright (C) 2006 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2011 Dell Inc.
+ * 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 <getopt.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <signal.h>
+#include <time.h>
+#include <sys/stat.h>
+#include <inttypes.h>
+
+#include <libopeniscsiusr/libopeniscsiusr.h>
+
+#include "initiator.h"
+#include "discovery.h"
+#include "log.h"
+#include "mgmt_ipc.h"
+#include "idbm.h"
+#include "iscsi_util.h"
+#include "transport.h"
+#include "version.h"
+#include "iscsi_sysfs.h"
+#include "list.h"
+#include "iscsi_settings.h"
+#include "fw_context.h"
+#include "iface.h"
+#include "session_info.h"
+#include "host.h"
+#include "sysdeps.h"
+#include "idbm_fields.h"
+#include "session_mgmt.h"
+#include "iscsid_req.h"
+#include <libisns/isns-proto.h>
+#include "iscsi_err.h"
+#include "iscsi_ipc.h"
+#include "iscsi_timer.h"
+#include "flashnode.h"
+
+#define _good(rc, rc_val, out) \
+       do { \
+               rc_val = rc; \
+               if (rc_val != LIBISCSI_OK) \
+                       goto out; \
+       } while(0)
+
+static char program_name[] = "iscsiadm";
+static char config_file[TARGET_NAME_MAXLEN];
+extern struct iscsi_ipc *ipc;
+
+enum iscsiadm_mode {
+       MODE_DISCOVERY,
+       MODE_DISCOVERYDB,
+       MODE_NODE,
+       MODE_SESSION,
+       MODE_HOST,
+       MODE_IFACE,
+       MODE_FW,
+       MODE_PING,
+       MODE_CHAP,
+       MODE_FLASHNODE,
+       MODE_HOST_STATS
+};
+
+enum iscsiadm_op {
+       OP_NOOP                 = 0x0,
+       OP_NEW                  = 0x1,
+       OP_DELETE               = 0x2,
+       OP_UPDATE               = 0x4,
+       OP_SHOW                 = 0x8,
+       OP_NONPERSISTENT        = 0x10,
+       OP_APPLY                = 0x20,
+       OP_APPLY_ALL            = 0x40,
+       OP_LOGIN                = 0x80,
+       OP_LOGOUT               = 0x100
+};
+
+enum _print_node_tree_mode {
+       _PRINT_MODE_IFACE,
+       _PRINT_MODE_NODE,
+};
+
+struct verify_mode_t {
+       char *mode;
+       char *allowed;
+       int skip_m;
+};
+
+static const struct verify_mode_t mode_paras[] = {
+       [MODE_DISCOVERY] = {"discovery", "DSIPdmntplov", 0},
+       [MODE_DISCOVERYDB] = {"discovery", "DSIPdmntplov", 0},
+       [MODE_NODE] = {"node", "RsPIdmlSonvupTULW", 0},
+       [MODE_SESSION] = {"session", "PiRdrmusonuSv", 1},
+       [MODE_HOST] = {"host", "CHdmPotnvxA", 0},
+       [MODE_IFACE] = {"iface", "HIdnvmPoCabci", 0},
+       [MODE_FW] = {"fw", "dmlWnv", 0},
+};
+
+static struct option const long_options[] =
+{
+       {"mode", required_argument, NULL, 'm'},
+       {"portal", required_argument, NULL, 'p'},
+       {"targetname", required_argument, NULL, 'T'},
+       {"interface", required_argument, NULL, 'I'},
+       {"op", required_argument, NULL, 'o'},
+       {"type", required_argument, NULL, 't'},
+       {"name", required_argument, NULL, 'n'},
+       {"value", required_argument, NULL, 'v'},
+       {"host", required_argument, NULL, 'H'},
+       {"sid", required_argument, NULL, 'r'},
+       {"rescan", no_argument, NULL, 'R'},
+       {"print", required_argument, NULL, 'P'},
+       {"discover", no_argument, NULL, 'D'},
+       {"login", no_argument, NULL, 'l'},
+       {"loginall", required_argument, NULL, 'L'},
+       {"logout", no_argument, NULL, 'u'},
+       {"logoutall", required_argument, NULL, 'U'},
+       {"stats", no_argument, NULL, 's'},
+       {"killiscsid", required_argument, NULL, 'k'},
+       {"debug", required_argument, NULL, 'd'},
+       {"show", no_argument, NULL, 'S'},
+       {"version", no_argument, NULL, 'V'},
+       {"help", no_argument, NULL, 'h'},
+       {"submode", required_argument, NULL, 'C'},
+       {"ip", required_argument, NULL, 'a'},
+       {"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'},
+       {"no_wait", no_argument, NULL, 'W'},
+       {NULL, 0, NULL, 0},
+};
+static char *short_options = "RlDVhm:a:b:c:C:p:P:T:H:i:I:U:k:L:d:r:n:v:o:sSt:ux:A:W";
+
+static void usage(int status)
+{
+       if (status != 0)
+               fprintf(stderr, "Try `%s --help' for more information.\n",
+                       program_name);
+       else {
+               printf("\
+iscsiadm -m discoverydb [-hV] [-d debug_level] [-P printlevel] [-t type -p ip:port -I ifaceN ... [-Dl]] | [[-p ip:port -t type] \
+[-o operation] [-n name] [-v value] [-lD]] \n\
+iscsiadm -m discovery [-hV] [-d debug_level] [-P printlevel] [-t type -p ip:port -I ifaceN ... [-l]] | [[-p ip:port] [-l | -D]] [-W]\n\
+iscsiadm -m node [-hV] [-d debug_level] [-P printlevel] [-L all,manual,automatic,onboot] [-W] [-U all,manual,automatic,onboot] [-S] [[-T targetname -p ip:port -I ifaceN] [-l | -u | -R | -s]] \
+[[-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 [-d debug_level] [-l] [-W] [[-n name] [-v value]]\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);
+}
+
+static int
+str_to_op(char *str)
+{
+       int op;
+
+       if (!strcmp("new", str))
+               op = OP_NEW;
+       else if (!strcmp("delete", str))
+               op = OP_DELETE;
+       else if (!strcmp("update", str))
+               op = OP_UPDATE;
+       else if (!strcmp("show", str))
+               op = OP_SHOW;
+       else if (!strcmp("nonpersistent", str))
+               op = OP_NONPERSISTENT;
+       else if (!strcmp("apply", 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;
+
+       return op;
+}
+
+static int
+str_to_mode(char *str)
+{
+       int mode;
+
+       if (!strcmp("discovery", str))
+               mode = MODE_DISCOVERY;
+       else if (!strcmp("discoverydb", str))
+               mode = MODE_DISCOVERYDB;
+       else if (!strcmp("node", str))
+               mode = MODE_NODE;
+       else if (!strcmp("session", str))
+               mode = MODE_SESSION;
+       else if (!strcmp("iface", str))
+               mode = MODE_IFACE;
+       else if (!strcmp("fw", str))
+               mode = MODE_FW;
+       else if (!strcmp("host", str))
+               mode = MODE_HOST;
+       else
+               mode = -1;
+
+       return mode;
+}
+
+static int
+str_to_submode(char *str)
+{
+       int sub_mode;
+
+       if (!strcmp("ping", 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;
+
+       return sub_mode;
+}
+
+static int
+str_to_type(char *str)
+{
+       int type;
+
+       if (!strcmp("sendtargets", str) ||
+           !strcmp("st", str))
+               type = DISCOVERY_TYPE_SENDTARGETS;
+       else if (!strcmp("slp", str))
+               type = DISCOVERY_TYPE_SLP;
+       else if (!strcmp("isns", str))
+               type = DISCOVERY_TYPE_ISNS;
+       else if (!strcmp("fw", str))
+               type = DISCOVERY_TYPE_FW;
+       else
+               type = -1;
+
+       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, int tmo)
+{
+       iscsiadm_req_t req;
+       iscsiadm_rsp_t rsp;
+       int rc;
+
+       /*
+        * We only support SIGTERM like stoppage of iscsid for now.
+        * In the future we can do something where we try go finish
+        * up operations like login, error handling, etc, before
+        * iscsid is stopped, and we can add different values to indicate
+        * that the user wants iscsid to log out existing sessions before
+        * exiting.
+        */
+       if (priority != 0) {
+               log_error("Invalid iscsid priority %d. Priority must be 0.",
+                         priority);
+               return;
+       }
+
+       memset(&req, 0, sizeof(req));
+       req.command = MGMT_IPC_IMMEDIATE_STOP;
+       rc = iscsid_exec_req(&req, &rsp, 0, tmo);
+       if (rc) {
+               iscsi_err_print_msg(rc);
+               log_error("Could not stop iscsid. Trying sending iscsid "
+                         "SIGTERM or SIGKILL signals manually");
+       }
+}
+
+static int
+match_startup_mode(node_rec_t *rec, char *mode)
+{
+       if ((!strcmp(mode, "automatic") &&
+           rec->startup == ISCSI_STARTUP_AUTOMATIC) ||
+           (!strcmp(mode, "onboot") &&
+           rec->startup == ISCSI_STARTUP_ONBOOT) ||
+           (!strcmp(mode, "manual") &&
+           rec->startup == ISCSI_STARTUP_MANUAL) ||
+           !strcmp(mode, "all"))
+               return 0;
+
+       /* support conn or session startup params */
+       if ((!strcmp(mode, "automatic") &&
+           rec->conn[0].startup == ISCSI_STARTUP_AUTOMATIC) ||
+           (!strcmp(mode, "onboot") &&
+           rec->conn[0].startup == ISCSI_STARTUP_ONBOOT) ||
+           (!strcmp(mode, "manual") &&
+           rec->conn[0].startup == ISCSI_STARTUP_MANUAL) ||
+           !strcmp(mode, "all"))
+               return 0;
+
+       return -1;
+}
+
+static int
+for_each_session(struct node_rec *rec, iscsi_sysfs_session_op_fn *fn,
+                int in_parallel)
+{
+       int err, num_found = 0;
+
+       if (rec && rec->session.info) {
+               num_found = 1;
+               err = fn(rec, rec->session.info);
+       } else {
+               err = iscsi_sysfs_for_each_session(rec, &num_found, fn,
+                                                  in_parallel);
+       }
+       if (err)
+               log_error("Could not execute operation on all sessions: %s",
+                         iscsi_err_to_str(err));
+       else if (!num_found) {
+               log_error("No session found.");
+               err = ISCSI_ERR_NO_OBJS_FOUND;
+       }
+
+       return err;
+}
+
+static int link_recs(void *data, struct node_rec *rec)
+{
+       struct list_head *list = data;
+       struct node_rec *rec_copy;
+
+       rec_copy = calloc(1, sizeof(*rec_copy));
+       if (!rec_copy)
+               return ISCSI_ERR_NOMEM;
+       memcpy(rec_copy, rec, sizeof(*rec_copy));
+       INIT_LIST_HEAD(&rec_copy->list);
+       list_add_tail(&rec_copy->list, list);
+       return 0;
+}
+
+static int
+__logout_by_startup(void *data, struct list_head *list,
+                   struct session_info *info)
+{
+       char *mode = data;
+       node_rec_t rec;
+
+       memset(&rec, 0, sizeof(node_rec_t));
+       if (idbm_rec_read(&rec, info->targetname, info->tpgt,
+                         info->persistent_address,
+                         info->persistent_port, &info->iface, false)) {
+               /*
+                * 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]",
+                         info->targetname, info->persistent_address,
+                         info->persistent_port);
+               return -1;
+       }
+
+       /* multiple drivers could be connected to the same portal */
+       if (strcmp(rec.iface.transport_name, info->iface.transport_name))
+               return -1;
+       /*
+        * we always skip on boot because if the user killed this on
+        * they would not be able to do anything
+        */
+       if (rec.startup == ISCSI_STARTUP_ONBOOT)
+               return -1;
+
+       if (rec.disc_type == DISCOVERY_TYPE_FW)
+               return -1;
+
+       if (match_startup_mode(&rec, mode))
+               return -1;
+
+       return iscsi_logout_portal(info, list);
+}
+
+static int
+logout_by_startup(char *mode)
+{
+       int nr_found;
+       int rc;
+
+       if (!mode || !(!strcmp(mode, "automatic") || !strcmp(mode, "all") ||
+           !strcmp(mode,"manual"))) {
+               log_error("Invalid logoutall option %s.", mode);
+               usage(ISCSI_ERR_INVAL);
+               return ISCSI_ERR_INVAL;
+       }
+
+       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;
+}
+
+struct startup_data {
+       char *mode;
+       struct list_head all_logins;
+       struct list_head leading_logins;
+};
+
+static int link_startup_recs(void *data, struct node_rec *rec)
+{
+       struct startup_data *startup = data;
+       struct node_rec *rec_copy;
+
+       if (match_startup_mode(rec, startup->mode))
+               return -1;
+
+       rec_copy = calloc(1, sizeof(*rec_copy));
+       if (!rec_copy)
+               return ISCSI_ERR_NOMEM;
+       memcpy(rec_copy, rec, sizeof(*rec_copy));
+       INIT_LIST_HEAD(&rec_copy->list);
+
+       if (rec_copy->leading_login)
+               list_add_tail(&rec_copy->list, &startup->leading_logins);
+       else
+               list_add_tail(&rec_copy->list, &startup->all_logins);
+       return 0;
+}
+
+static int
+__do_leading_login(void *data, struct list_head *list, struct node_rec *rec)
+{
+       struct iface_rec *pattern_iface = data;
+       int nr_found;
+
+       log_debug(1, "doing leading login using iface: %s", pattern_iface->name);
+
+       /* Skip any records that do not match the pattern iface */
+       if (!iface_match(pattern_iface, &rec->iface))
+               return -1;
+
+       /*
+        * 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, 0)) {
+               log_debug(1, "Skipping %s: Already a session for that target",
+                         rec->name);
+               return -1;
+       }
+
+       /* No existing session: Attempt a login. */
+       return iscsi_login_portal(NULL, list, rec);
+}
+
+static int
+login_by_startup(char *mode, bool wait)
+{
+       int nr_found = 0, err, rc;
+       struct startup_data startup;
+
+       if (!mode || !(!strcmp(mode, "automatic") || !strcmp(mode, "all") ||
+                      !strcmp(mode,"manual") || !strcmp(mode, "onboot"))) {
+               log_error("Invalid loginall option %s.", mode);
+               usage(ISCSI_ERR_INVAL);
+               return ISCSI_ERR_INVAL;
+       }
+
+       /*
+        * Filter all node records that match the given 'mode' into 2 lists:
+        * Those with leading_login enabled, and those without.
+        */
+       startup.mode = mode;
+       INIT_LIST_HEAD(&startup.all_logins);
+       INIT_LIST_HEAD(&startup.leading_logins);
+       err = idbm_for_each_rec(&nr_found, &startup, link_startup_recs, false);
+       if (err && (!list_empty(&startup.all_logins) ||
+                   !list_empty(&startup.leading_logins)))
+               /* log msg and try to log into what we found */
+               log_error("Could not read all records: %s",
+                         iscsi_err_to_str(err));
+       else if (list_empty(&startup.all_logins) &&
+                list_empty(&startup.leading_logins)) {
+               if (err) {
+                       log_error("Could not read node DB: %s.",
+                                 iscsi_err_to_str(err));
+               } else {
+                       log_error("No records found");
+                       err = ISCSI_ERR_NO_OBJS_FOUND;
+               }
+               return err;
+       }
+       rc = err;
+
+       if (!list_empty(&startup.all_logins)) {
+               log_debug(1, "Logging into normal (non-leading-login) portals");
+               /* Login all regular (non-leading-login) portals first */
+               err = iscsi_login_portals(NULL, &nr_found, wait,
+                               &startup.all_logins, iscsi_login_portal);
+               if (err)
+                       log_error("Could not log into all portals");
+               if (err && !rc)
+                       rc = err;
+       }
+
+       if (!list_empty(&startup.leading_logins)) {
+               /*
+                * For each iface in turn, try to login all portals on that
+                * iface that do not already have a session present.
+                */
+               struct iface_rec *pattern_iface, *tmp_iface;
+               struct node_rec *rec, *tmp_rec;
+               LIST_HEAD(iface_list);
+               int missed_leading_login = 0;
+               log_debug(1, "Logging into leading-login portals");
+               iface_link_ifaces(&iface_list);
+               list_for_each_entry_safe(pattern_iface, tmp_iface, &iface_list,
+                                        list) {
+                       log_debug(1, "Establishing leading-logins via iface %s",
+                                 pattern_iface->name);
+                       err = iscsi_login_portals_safe(pattern_iface, &nr_found,
+                                                      1,
+                                                      &startup.leading_logins,
+                                                      __do_leading_login);
+                       if (err)
+                               log_error("Could not log into all portals on "
+                                         "%s, trying next interface",
+                                         pattern_iface->name);
+
+                       /*
+                        * Note: We always try all iface records in case there
+                        * are targets that are associated with only a subset
+                        * of iface records.  __do_leading_login already
+                        * prevents duplicate sessions if an iface has succeeded
+                        * for a particular target.
+                        */
+               }
+               /*
+                * Double-check that all leading-login portals have at least
+                * one session
+                */
+               list_for_each_entry_safe(rec, tmp_rec, &startup.leading_logins,
+                                        list) {
+                       if (!iscsi_sysfs_for_each_session(rec, &nr_found,
+                                                         iscsi_match_target, 0))
+                               missed_leading_login++;
+                       /*
+                        * Cleanup the list, since 'iscsi_login_portals_safe'
+                        * does not
+                        */
+                       list_del(&rec->list);
+                       free(rec);
+               }
+               if (missed_leading_login) {
+                       log_error("Could not login all leading-login portals");
+                       if (!rc)
+                               rc = ISCSI_ERR_FATAL_LOGIN;
+               }
+       }
+
+       return rc;
+}
+
+/**
+ * iscsi_logout_matched_portal - logout of targets matching the rec info
+ * @data: record to session with
+ * @list: list to add logout rec to
+ * @info: session to match with rec
+ */
+static int iscsi_logout_matched_portal(void *data, struct list_head *list,
+                                      struct session_info *info)
+{
+       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)
+               return -1;
+
+       if (!iscsi_match_session(pattern_rec, info))
+               return -1;
+
+       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)
+{
+       struct rec_op_data *op_data = data;
+
+       if (!__iscsi_match_session(op_data->match_rec, rec->name,
+                                  rec->conn[0].address, rec->conn[0].port,
+                                  &rec->iface, rec->session.sid))
+               return -1;
+       return op_data->fn(op_data->data, rec);
+}
+
+static int __for_each_matched_rec(int verbose, struct node_rec *rec,
+                                 void *data, idbm_iface_op_fn *fn)
+{
+       struct rec_op_data op_data;
+       int nr_found = 0, rc;
+
+       memset(&op_data, 0, sizeof(struct rec_op_data));
+       op_data.data = data;
+       op_data.match_rec = rec;
+       op_data.fn = fn;
+
+       rc = idbm_for_each_rec(&nr_found, &op_data, rec_match_fn, true);
+       if (rc) {
+               if (verbose)
+                       log_error("Could not execute operation on all "
+                                 "records: %s", iscsi_err_to_str(rc));
+       } else if (!nr_found) {
+               if (verbose)
+                       log_error("No records found");
+               rc = ISCSI_ERR_NO_OBJS_FOUND;
+       }
+
+       return rc;
+}
+
+static int for_each_matched_rec(struct node_rec *rec, void *data,
+                               idbm_iface_op_fn *fn)
+{
+       return __for_each_matched_rec(1, rec, data, fn);
+}
+
+
+static int login_portals(struct node_rec *pattern_rec, bool wait)
+{
+       LIST_HEAD(rec_list);
+       int nr_found, rc, err;
+
+       err = for_each_matched_rec(pattern_rec, &rec_list, link_recs);
+       if (err == ISCSI_ERR_NO_OBJS_FOUND)
+               return err;
+       else if (err && list_empty(&rec_list))
+               return err;
+
+       rc = err;
+       /* if there is an err but some recs then try to login to what we have */
+
+       err = iscsi_login_portals(pattern_rec, &nr_found, wait ? 1 : 0, &rec_list,
+                                 iscsi_login_portal);
+       if (err)
+               log_error("Could not log into all portals");
+
+       if (err && !rc)
+               rc = err;
+
+       return rc;
+}
+
+static void print_node_flat(struct iscsi_node *node)
+{
+               printf("%s,%" PRIu16 " %s\n",
+                      iscsi_node_portal_get(node),
+                      iscsi_node_tpgt_get(node),
+                      iscsi_node_target_name_get(node));
+}
+
+static void print_nodes_tree(struct iscsi_node **nodes, uint32_t node_count,
+                            enum _print_node_tree_mode print_mode)
+{
+       unsigned int i;
+       struct iscsi_node *cur_node = NULL;
+       struct iscsi_node *prev_node = NULL;
+       const char *prefix = NULL;
+
+       if (print_mode == _PRINT_MODE_IFACE)
+               prefix = "\t";
+       else
+               prefix = "";
+
+       // According to libopeniscsiusr document, nodes are sorted. There
+       // is no need to create hash table for this.
+       for (i = 0; i < node_count; ++i) {
+               cur_node = nodes[i];
+               /*
+                * Print the target line if this is our first pass, or
+                * if if it does not match the prevous target. Always print
+                * the Portal line. The original code seemed to want to
+                * suppres duplicates here, as well, but it evidently
+                * didn't work that way, so let's not regress output format
+                */
+               if (!prev_node || strcmp(iscsi_node_target_name_get(prev_node),
+                                        iscsi_node_target_name_get(cur_node)))
+                       printf("%sTarget: %s\n", prefix,
+                              iscsi_node_target_name_get(cur_node));
+               printf("%s\tPortal: %s,%d\n", prefix,
+                      iscsi_node_portal_get(cur_node),
+                      iscsi_node_tpgt_get(cur_node));
+               if (print_mode == _PRINT_MODE_NODE)
+                       printf("\t\tIface Name: %s\n",
+                              iscsi_node_iface_name_get(cur_node));
+               prev_node = cur_node;
+       }
+}
+
+static int print_nodes(struct iscsi_context *ctx, int info_level)
+{
+       struct iscsi_node **nodes = NULL;
+       uint32_t node_count = 0;
+       uint32_t i = 0;
+       int rc = 0;
+
+       if ((info_level != 0) && (info_level != -1) && (info_level != 1)) {
+               log_error("Invalid info level %d. Try 0 or 1.", info_level);
+               rc = ISCSI_ERR_INVAL;
+               goto out;
+       }
+
+       rc = iscsi_nodes_get(ctx, &nodes, &node_count);
+       if (rc != LIBISCSI_OK)
+               goto out;
+
+       if (!node_count) {
+               log_error("No records found");
+               rc = ISCSI_ERR_NO_OBJS_FOUND;
+               goto out;
+       }
+
+       if (info_level == 1)
+               print_nodes_tree(nodes, node_count, _PRINT_MODE_NODE);
+       else
+               for (i = 0; i < node_count; ++i)
+                       print_node_flat(nodes[i]);
+
+out:
+       iscsi_nodes_free(nodes, node_count);
+       return rc;
+}
+
+static int print_nodes_config(struct iscsi_context *ctx, bool show_secret,
+                             const char *target_name, const char *address,
+                             int32_t port, const char *iface_name)
+{
+       int rc = 0;
+       struct iscsi_node **nodes = NULL;
+       struct iscsi_node *node = NULL;
+       uint32_t node_count = 0;
+       uint32_t i = 0;
+       bool match = false;
+       bool has_match = false;
+
+       rc = iscsi_nodes_get(ctx, &nodes, &node_count);
+       if (rc != LIBISCSI_OK)
+               return rc;
+
+       for (i = 0; i < node_count; ++i) {
+               node = nodes[i];
+               match = true;
+               if ((target_name != NULL) &&
+                   (strlen(target_name) != 0) &&
+                   (strcmp(target_name,
+                           iscsi_node_target_name_get(node)) != 0))
+                       match = false;
+               if ((address != NULL) &&
+                   (strlen(address) != 0) &&
+                   (strcmp(address, iscsi_node_conn_address_get(node)) != 0))
+                       match = false;
+               if ((port != -1) && (port != (int32_t)iscsi_node_conn_port_get(node)))
+                       match = false;
+               if ((iface_name != NULL) &&
+                   (strlen(iface_name) != 0) &&
+                   (strcmp(iface_name, iscsi_node_iface_name_get(node)) != 0))
+                       match = false;
+
+               if (match == true) {
+                       iscsi_node_print_config(node, show_secret);
+                       has_match = true;
+               }
+       }
+
+       iscsi_nodes_free(nodes, node_count);
+
+       if (has_match == false) {
+               log_error("No records found");
+               rc = ISCSI_ERR_NO_OBJS_FOUND;
+       }
+       return rc;
+}
+
+static char *get_config_file(void)
+{
+       int rc;
+       iscsiadm_req_t req;
+       iscsiadm_rsp_t rsp;
+
+       memset(&req, 0, sizeof(req));
+       req.command = MGMT_IPC_CONFIG_FILE;
+
+       rc = iscsid_exec_req(&req, &rsp, 1, ISCSID_REQ_TIMEOUT);
+       if (rc)
+               return NULL;
+
+       if (rsp.u.config.var[0] != '\0') {
+               strcpy(config_file, rsp.u.config.var);
+               return config_file;
+       }
+
+       return NULL;
+}
+
+static int rescan_portal(void *data, struct session_info *info)
+{
+       int host_no, err;
+
+       if (!iscsi_match_session(data, info))
+               return -1;
+
+       printf("Rescanning session [sid: %d, target: %s, portal: "
+               "%s,%d]\n", info->sid, info->targetname,
+               info->persistent_address, info->port);
+
+       host_no = iscsi_sysfs_get_host_no_from_sid(info->sid, &err);
+       if (err) {
+               log_error("Could not rescan session sid %d.", info->sid);
+               return err;
+       }
+       /* rescan each device to pick up size changes */
+       iscsi_sysfs_for_each_device(NULL, host_no, info->sid,
+                                   iscsi_sysfs_rescan_device);
+       /* now scan for new devices */
+       iscsi_sysfs_scan_host(host_no, 0, 1);
+       return 0;
+}
+
+static int
+session_stats(void *data, struct session_info *info)
+{
+       int rc, i;
+       iscsiadm_req_t req;
+       iscsiadm_rsp_t rsp;
+
+       if (!iscsi_match_session(data, info))
+               return -1;
+
+       memset(&req, 0, sizeof(req));
+       req.command = MGMT_IPC_SESSION_STATS;
+       req.u.session.sid = info->sid;
+
+       rc = iscsid_exec_req(&req, &rsp, 1, info->iscsid_req_tmo);
+       if (rc)
+               return rc;
+
+       printf("Stats for session [sid: %d, target: %s, portal: "
+               "%s,%d]\n",
+               info->sid, info->targetname, info->persistent_address,
+               info->port);
+
+       printf( "iSCSI SNMP:\n"
+
+               "\ttxdata_octets: %lld\n"
+               "\trxdata_octets: %lld\n"
+
+               "\tnoptx_pdus: %u\n"
+               "\tscsicmd_pdus: %u\n"
+               "\ttmfcmd_pdus: %u\n"
+               "\tlogin_pdus: %u\n"
+               "\ttext_pdus: %u\n"
+               "\tdataout_pdus: %u\n"
+               "\tlogout_pdus: %u\n"
+               "\tsnack_pdus: %u\n"
+
+               "\tnoprx_pdus: %u\n"
+               "\tscsirsp_pdus: %u\n"
+               "\ttmfrsp_pdus: %u\n"
+               "\ttextrsp_pdus: %u\n"
+               "\tdatain_pdus: %u\n"
+               "\tlogoutrsp_pdus: %u\n"
+               "\tr2t_pdus: %u\n"
+               "\tasync_pdus: %u\n"
+               "\trjt_pdus: %u\n"
+
+               "\tdigest_err: %u\n"
+               "\ttimeout_err: %u\n",
+               (unsigned long long)rsp.u.getstats.stats.txdata_octets,
+               (unsigned long long)rsp.u.getstats.stats.rxdata_octets,
+
+               rsp.u.getstats.stats.noptx_pdus,
+               rsp.u.getstats.stats.scsicmd_pdus,
+               rsp.u.getstats.stats.tmfcmd_pdus,
+               rsp.u.getstats.stats.login_pdus,
+               rsp.u.getstats.stats.text_pdus,
+               rsp.u.getstats.stats.dataout_pdus,
+               rsp.u.getstats.stats.logout_pdus,
+               rsp.u.getstats.stats.snack_pdus,
+
+               rsp.u.getstats.stats.noprx_pdus,
+               rsp.u.getstats.stats.scsirsp_pdus,
+               rsp.u.getstats.stats.tmfrsp_pdus,
+               rsp.u.getstats.stats.textrsp_pdus,
+               rsp.u.getstats.stats.datain_pdus,
+               rsp.u.getstats.stats.logoutrsp_pdus,
+               rsp.u.getstats.stats.r2t_pdus,
+               rsp.u.getstats.stats.async_pdus,
+               rsp.u.getstats.stats.rjt_pdus,
+
+               rsp.u.getstats.stats.digest_err,
+               rsp.u.getstats.stats.timeout_err);
+
+       if (rsp.u.getstats.stats.custom_length)
+               printf( "iSCSI Extended:\n");
+
+       for (i = 0; i < (int)rsp.u.getstats.stats.custom_length; i++) {
+               printf("\t%s: %llu\n", rsp.u.getstats.stats.custom[i].desc,
+                     (unsigned long long)rsp.u.getstats.stats.custom[i].value);
+       }
+
+       return 0;
+}
+
+static int add_static_rec(int *found, char *targetname, int tpgt,
+                         char *ip, int port, struct iface_rec *iface)
+{
+       node_rec_t *rec;
+       discovery_rec_t *drec;
+       int rc;
+
+       rec = calloc(1, sizeof(*rec));
+       if (!rec) {
+               log_error("Could not allocate memory for node addition");
+               rc = ISCSI_ERR_NOMEM;
+               goto done;
+       }
+
+       drec = calloc(1, sizeof(*drec));
+       if (!drec) {
+               log_error("Could not allocate memory for node addition");
+               rc = ISCSI_ERR_NOMEM;
+               goto free_rec;
+       }
+       drec->type = DISCOVERY_TYPE_STATIC;
+
+       idbm_node_setup_from_conf(rec);
+       strlcpy(rec->name, targetname, TARGET_NAME_MAXLEN);
+       rec->tpgt = tpgt;
+       rec->conn[0].port = port;
+       strlcpy(rec->conn[0].address, ip, NI_MAXHOST);
+
+       if (iface) {
+               rc = iface_conf_read(iface);
+               if (rc) {
+                       log_error("Could not read iface %s. Error %d",
+                                 iface->name, rc);
+                       goto free_drec;
+               }
+
+               iface_copy(&rec->iface, iface);
+       }
+
+       rc = idbm_add_node(rec, drec, 1);
+       if (!rc) {
+               (*found)++;
+               printf("New iSCSI node [%s:" iface_fmt " %s,%d,%d %s] added\n",
+                       rec->iface.transport_name, iface_str(&rec->iface),
+                       ip, port, tpgt, targetname);
+       }
+free_drec:
+       free(drec);
+free_rec:
+       free(rec);
+done:
+       return rc;
+}
+
+static int add_static_portal(int *found, void *data, char *targetname,
+                            int tpgt, char *ip, int port,
+                            __attribute__((unused))bool ruw_lock)
+{
+       node_rec_t *rec = data;
+
+       if (strlen(rec->conn[0].address) &&
+           strcmp(rec->conn[0].address, ip))
+               return -1;
+
+       if (rec->conn[0].port != -1 && rec->conn[0].port != port)
+               return -1;
+
+       return add_static_rec(found, targetname, tpgt, ip, port,
+                             &rec->iface);
+}
+
+static int add_static_node(int *found, void *data, char *targetname,
+                          __attribute__((unused))bool ruw_lock)
+{
+       node_rec_t *rec = data;
+
+       if (!strlen(rec->name))
+               goto search;
+
+       if (strcmp(rec->name, targetname))
+               return -1;
+
+       if (!strlen(rec->conn[0].address))
+               goto search;
+
+       return add_static_rec(found, targetname, rec->tpgt,
+                             rec->conn[0].address,
+                             rec->conn[0].port, &rec->iface);
+search:
+       return idbm_for_each_portal(found, data, add_static_portal,
+                                   targetname, false);
+}
+
+static int add_static_recs(struct node_rec *rec)
+{
+       int rc, nr_found = 0;
+
+       rc = idbm_for_each_node(&nr_found, rec, add_static_node, false);
+       if (rc)
+               goto done;
+       /* success */
+       if (nr_found > 0)
+               return 0;
+
+       /* brand new target */
+       if (strlen(rec->name) && strlen(rec->conn[0].address)) {
+               rc = add_static_rec(&nr_found, rec->name, rec->tpgt,
+                                   rec->conn[0].address, rec->conn[0].port,
+                                   &rec->iface);
+               if (!rc)
+                       return 0;
+       }
+done:
+       log_error("Error while adding record: %s", iscsi_err_to_str(rc));
+       return rc;
+}
+
+/*
+ * start sendtargets discovery process based on the
+ * particular config
+ */
+static int
+do_offload_sendtargets(discovery_rec_t *drec, int host_no, int do_login)
+{
+       drec->type = DISCOVERY_TYPE_OFFLOAD_SENDTARGETS;
+       return discovery_offload_sendtargets(host_no, do_login, drec);
+}
+
+static int delete_node(__attribute__((unused))void *data,
+                      struct node_rec *rec)
+{
+       if (iscsi_check_for_running_session(rec)) {
+               /*
+                * We could log out the session for the user, but if
+                * the session is being used the user may get something
+                * they were not expecting (FS errors and a read only
+                * remount).
+                */
+               log_error("This command will remove the record [iface: %s, "
+                         "target: %s, portal: %s,%d], but a session is "
+                         "using it. Logout session then rerun command to "
+                         "remove record.", rec->iface.name, rec->name,
+                         rec->conn[0].address, rec->conn[0].port);
+               return ISCSI_ERR_SESS_EXISTS;
+       }
+
+       return idbm_delete_node(rec);
+}
+
+static int delete_stale_rec(void *data, struct node_rec *rec)
+{
+       struct list_head *new_rec_list = data;
+       struct node_rec *new_rec;
+
+       list_for_each_entry(new_rec, new_rec_list, list) {
+               /*
+                * We could also move this to idbm.c and instead of looping
+                * over every node just loop over disc to node links.
+                */
+               if (rec->disc_type != new_rec->disc_type ||
+                   rec->disc_port != new_rec->disc_port ||
+                   strcmp(rec->disc_address, new_rec->disc_address))
+                       /*
+                        * if we are not from the same discovery source
+                        * ignore it
+                        */
+                       return -1;
+
+               if (__iscsi_match_session(rec,
+                                         new_rec->name,
+                                         new_rec->conn[0].address,
+                                         new_rec->conn[0].port,
+                                         &new_rec->iface,
+                                         new_rec->session.sid))
+                       return -1;
+       }
+       /* if there is a error we can continue on */
+       return delete_node(NULL, rec);
+}
+
+static int
+exec_disc_op_on_recs(discovery_rec_t *drec, struct list_head *rec_list,
+                    int info_level, int do_login, int op)
+{
+       int rc = 0, err, found = 0;
+       struct node_rec *new_rec, tmp_rec;
+
+       /* clean up node db */
+       if (op & OP_DELETE)
+               idbm_for_each_rec(&found, rec_list, delete_stale_rec, false);
+
+       if (op & OP_NEW || op & OP_UPDATE) {
+               /* now add/update records */
+               list_for_each_entry(new_rec, rec_list, list) {
+                       rc = idbm_add_node(new_rec, drec, op & OP_UPDATE);
+                       if (rc)
+                               log_error("Could not add/update "
+                                         "[%s:" iface_fmt " %s,%d,%d %s]",
+                                          new_rec->iface.transport_name,
+                                          iface_str(&new_rec->iface),
+                                          new_rec->conn[0].address,
+                                          new_rec->conn[0].port,
+                                          new_rec->tpgt, new_rec->name);
+               }
+       }
+
+       memset(&tmp_rec, 0, sizeof(node_rec_t));
+       list_for_each_entry(new_rec, rec_list, list) {
+               switch (info_level) {
+               case 0:
+               case -1:
+                       idbm_print_node_flat(NULL, new_rec);
+                       break;
+               case 1:
+                       idbm_print_node_and_iface_tree(&tmp_rec, new_rec);
+               }
+
+       }
+
+       if (!do_login)
+               return 0;
+
+       err = iscsi_login_portals(NULL, &found, 1, rec_list,
+                                 iscsi_login_portal);
+       if (err && !rc)
+               rc = err;
+       return rc;
+}
+
+static int
+do_software_sendtargets(discovery_rec_t *drec, struct list_head *ifaces,
+                       int info_level, int do_login, int op, int sync_drec)
+{
+       LIST_HEAD(rec_list);
+       struct node_rec *rec, *tmp;
+       int rc;
+
+       /*
+        * 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_SENDTARGETS;
+       /*
+        * we will probably want to know how a specific iface and discovery
+        * DB lined up, but for now just put all the targets found from
+        * a discovery portal in one place
+        */
+       if ((!(op & OP_NONPERSISTENT)) && sync_drec) {
+               rc = idbm_add_discovery(drec);
+               if (rc) {
+                       log_error("Could not add new discovery record.");
+                       return rc;
+               }
+       }
+
+       rc = idbm_bind_ifaces_to_nodes(discovery_sendtargets, drec, ifaces,
+                                      &rec_list);
+       if (rc) {
+               log_error("Could not perform SendTargets 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_isns(discovery_rec_t *drec, struct list_head *ifaces,
+                  int info_level, int do_login, int op)
+{
+       LIST_HEAD(rec_list);
+       struct node_rec *rec, *tmp;
+       int rc;
+
+       /*
+        * 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_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_discovery;
+       }
+
+       /* we allow users to mix hw and sw iscsi so we have to sort it out */
+       list_for_each_entry_safe(iface, tmp, ifaces, list) {
+               rc = iface_conf_read(iface);
+               if (rc) {
+                       log_error("Could not read iface info for %s. "
+                                 "Make sure an iface config with the file "
+                                 "name and iface.iscsi_ifacename %s is in %s.",
+                                 iface->name, iface->name, IFACE_CONFIG_DIR);
+                       list_del(&iface->list);
+                       free(iface);
+                       continue;
+               }
+               /* check for transport name first to make sure it is loaded */
+               t = iscsi_sysfs_get_transport_by_name(iface->transport_name);
+               if (!t) {
+                       log_error("Could not load transport %s."
+                                 "Dropping interface %s.",
+                                  iface->transport_name, iface->name);
+                       list_del(&iface->list);
+                       free(iface);
+                       continue;
+               }
+
+               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));
+                       /* try software iscsi */
+                       continue;
+               }
+
+               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_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;
+       }
+}
+
+
+static int
+verify_mode_params(int argc, char **argv, enum iscsiadm_mode mode)
+{
+       int ch, longindex;
+       int ret = ISCSI_SUCCESS;
+       char *allowed;
+       int skip_m;
+       int tmp = optind;
+
+       if (mode > MODE_FW || mode < MODE_DISCOVERY) {
+               log_error("mode %d is not yet supported", mode);
+               return ISCSI_ERR_INVAL;
+       }
+
+       allowed = mode_paras[mode].allowed;
+       skip_m = mode_paras[mode].skip_m;
+
+       optind = 0;
+
+       while ((ch = getopt_long(argc, argv, short_options,
+                                long_options, &longindex)) >= 0) {
+               if (!strchr(allowed, ch)) {
+                       if (ch == 'm' && skip_m)
+                               continue;
+                       log_error("%s mode: option '-%c' is not "
+                                 "allowed/supported",
+                                 mode_paras[mode].mode, ch);
+                       ret = ISCSI_ERR_INVAL;
+                       break;
+               }
+       }
+       optind = tmp;
+
+       return ret;
+}
+
+static void catch_sigint(__attribute__((unused))int signo) {
+       log_warning("caught SIGINT, exiting...");
+       exit(1);
+}
+
+static int iface_apply_net_config(struct iface_rec *iface, int op)
+{
+       int rc = ISCSI_ERR;
+       uint32_t host_no;
+       int param_count;
+       int param_used;
+       int iface_all = 0;
+       int i;
+       struct iovec *iovs = NULL;
+       struct iovec *iov = NULL;
+       struct iscsi_transport *t = NULL;
+       int fd;
+
+       log_debug(8, "Calling iscsid, to apply net config for"
+                 "iface.name = %s", iface->name);
+
+       if (op == OP_APPLY_ALL)
+               iface_all = 1;
+
+       param_count = iface_get_param_count(iface, iface_all);
+       if (!param_count) {
+               log_error("Nothing to configure.");
+               return ISCSI_SUCCESS;
+       }
+
+       /*
+        * TODO: create a nicer interface where the caller does not have
+        * know the packet/hdr details
+        */
+
+       /* +2 for event and nlmsghdr */
+       param_count += 2;
+       iovs = calloc((param_count * sizeof(struct iovec)),
+                      sizeof(char));
+       if (!iovs) {
+               log_error("Out of Memory.");
+               return ISCSI_ERR_NOMEM;
+       }
+
+       /* param_used gives actual number of iovecs used for netconfig */
+       param_used = iface_build_net_config(iface, iface_all, iovs);
+       if (!param_used) {
+               log_error("Build netconfig failed.");
+               goto free_buf;
+       }
+
+       t = iscsi_sysfs_get_transport_by_name(iface->transport_name);
+       if (!t) {
+               log_error("Can't find transport.");
+               goto free_buf;
+       }
+
+       host_no = iscsi_sysfs_get_host_no_from_hwinfo(iface, &rc);
+       if (host_no == 0) {
+               log_error("Can't find host_no.");
+               goto free_buf;
+       }
+       rc = ISCSI_ERR;
+
+       fd = ipc->ctldev_open();
+       if (fd < 0) {
+               log_error("Netlink open failed.");
+               goto free_buf;
+       }
+
+       rc = ipc->set_net_config(t->handle, host_no, iovs, param_count);
+       if (rc < 0)
+               log_error("Set net_config failed. errno=%d", errno);
+
+       ipc->ctldev_close();
+
+free_buf:
+       /* 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);
+       if (rc)
+               return ISCSI_ERR;
+       return ISCSI_SUCCESS;
+}
+
+static int get_host_chap_info(uint32_t host_no)
+{
+       struct iscsi_transport *t = NULL;
+       struct iscsi_chap_rec *crec = NULL;
+       char *req_buf = NULL;
+       uint32_t valid_chap_entries;
+       uint32_t num_entries;
+       uint16_t chap_tbl_idx = 0;
+       int rc = 0;
+       int fd;
+
+       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 exit_chap_info;
+       }
+
+       num_entries = MAX_CHAP_BUF_SZ / sizeof(*crec);
+
+       req_buf = calloc(1, REQ_CHAP_BUF_SZ);
+       if (!req_buf) {
+               log_error("Could not allocate memory for CHAP request.");
+               rc = ISCSI_ERR_NOMEM;
+               goto exit_chap_info;
+       }
+
+       fd = ipc->ctldev_open();
+       if (fd < 0) {
+               rc = ISCSI_ERR_INTERNAL;
+               log_error("Netlink open failed.");
+               goto exit_chap_info;
+       }
+
+get_chap:
+       memset(req_buf, 0, REQ_CHAP_BUF_SZ);
+
+       rc = ipc->get_chap(t->handle, host_no, chap_tbl_idx, num_entries,
+                          req_buf, &valid_chap_entries);
+       if (rc < 0) {
+               log_error("get_chap_info failed. errno=%d", errno);
+               rc = ISCSI_ERR;
+               goto exit_chap_info;
+       }
+
+       crec = (struct iscsi_chap_rec *) (req_buf +
+                                         sizeof(struct iscsi_uevent));
+
+       if (valid_chap_entries)
+               chap_tbl_idx =
+               (crec + (valid_chap_entries - 1))->chap_tbl_idx + 1;
+
+       /* print chap info */
+       for (uint32_t i = 0; i < valid_chap_entries; i++) {
+               idbm_print_host_chap_info(crec);
+               crec++;
+       }
+
+       if (valid_chap_entries != num_entries)
+               goto exit_chap_info;
+       else
+               goto get_chap;
+
+       ipc->ctldev_close();
+
+exit_chap_info:
+       if (req_buf)
+               free(req_buf);
+
+       return rc;
+}
+
+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, &param_count);
+       if (rc) {
+               log_error("Invalid username/password pair passed. Unable to determine the type of chap entry");
+               rc = ISCSI_ERR_INVAL;
+               goto free_info_rec;
+       }
+
+       if (param_count > 2) {
+               log_error("Only one pair of username/password can be passed.");
+               rc = ISCSI_ERR;
+               goto free_info_rec;
+       }
+
+       memset(&crec, 0, sizeof(crec));
+       rc = fill_host_chap_rec(params, &crec, chap_info, chap_index, type,
+                               &param_count);
+       if (rc) {
+               log_error("Unable to fill CHAP record");
+               goto free_info_rec;
+       }
+
+       /* +2 for event and nlmsghdr */
+       param_count += 2;
+       iovs = calloc((param_count * sizeof(struct iovec)),
+                      sizeof(char));
+       if (!iovs) {
+               log_error("Out of Memory.");
+               rc = ISCSI_ERR_NOMEM;
+               goto free_info_rec;
+       }
+
+       /* param_used gives actual number of iovecs used for chap */
+       param_used = chap_build_config(&crec, iovs);
+       if (!param_used) {
+               log_error("Build chap config failed.");
+               rc = ISCSI_ERR;
+               goto free_iovec;
+       }
+
+       fd = ipc->ctldev_open();
+       if (fd < 0) {
+               rc = ISCSI_ERR_INTERNAL;
+               log_error("Netlink open failed.");
+               goto free_iovec;
+       }
+
+       rc = ipc->set_chap(t->handle, host_no, iovs, param_count);
+       if (rc < 0) {
+               log_error("CHAP setting failed");
+               if (rc == -EBUSY) {
+                       rc = ISCSI_ERR_BUSY;
+                       log_error("CHAP index %d is in use.",
+                                 crec.chap_tbl_idx);
+               } else {
+                       rc = ISCSI_ERR;
+               }
+
+               goto free_iovec;
+       }
+
+       ipc->ctldev_close();
+
+free_iovec:
+       /* start at 2, because 0 is for nlmsghdr and 1 for event */
+       iov = iovs + 2;
+       for (i = 0; i < param_used; i++, iov++) {
+               if (iov->iov_base)
+                       free(iov->iov_base);
+       }
+
+       free(iovs);
+
+free_info_rec:
+       if (chap_info)
+               free(chap_info);
+
+exit_set_chap:
+       return rc;
+}
+
+static int delete_host_chap_info(uint32_t host_no, uint16_t chap_tbl_idx)
+{
+       struct iscsi_transport *t = NULL;
+       int fd, rc = 0;
+
+       if (chap_tbl_idx > MAX_CHAP_ENTRIES) {
+               log_error("Invalid chap table index.");
+               goto exit_delete_chap;
+       }
+
+       t = iscsi_sysfs_get_transport_by_hba(host_no);
+       if (!t) {
+               log_error("Could not match hostno %d to "
+                         "transport.", host_no);
+               rc = ISCSI_ERR_TRANS_NOT_FOUND;
+               goto exit_delete_chap;
+       }
+
+       fd = ipc->ctldev_open();
+       if (fd < 0) {
+               log_error("Netlink open failed.");
+               rc = ISCSI_ERR_INTERNAL;
+               goto exit_delete_chap;
+       }
+
+       log_info("Deleting 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.");
+               if (rc == -EBUSY) {
+                       rc = ISCSI_ERR_BUSY;
+                       log_error("CHAP index %d is in use.", chap_tbl_idx);
+               } else
+                       rc = ISCSI_ERR;
+       }
+
+       ipc->ctldev_close();
+
+exit_delete_chap:
+       return rc;
+}
+
+static int exec_host_chap_op(int op,
+                            __attribute__((unused))int info_level,
+                            uint32_t host_no,
+                            uint64_t chap_index,
+                            struct list_head *params)
+{
+       int rc = ISCSI_ERR_INVAL;
+
+       switch (op) {
+       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, chap_index);
+               break;
+       default:
+               log_error("Invalid operation.");
+               break;
+       }
+
+       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(__attribute__((unused))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;
+}
+
+static int iscsi_check_session_use_count(uint32_t sid) {
+       char *config_file;
+       char *safe_logout;
+
+       config_file = get_config_file();
+       if (!config_file) {
+               log_error("Could not get config file from iscsid");
+               return 0;
+       }
+
+       safe_logout = cfg_get_string_param(config_file, "iscsid.safe_logout");
+       if (!safe_logout || strcmp(safe_logout, "Yes"))
+               return 0;
+
+       return session_in_use(sid);
+}
+
+int iscsi_logout_flashnode_sid(struct iscsi_transport *t, uint32_t host_no,
+                              uint32_t sid)
+{
+       int fd, rc = 0;
+
+       if (iscsi_check_session_use_count(sid)) {
+               log_error("Session is actively in use for mounted storage, "
+                         "and iscsid.safe_logout is configured.");
+               return ISCSI_ERR_BUSY;
+       }
+
+       fd = ipc->ctldev_open();
+       if (fd < 0) {
+               log_error("Netlink open failed.");
+               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(__attribute__((unused))int op,
+                             __attribute__((unused))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;
+
+       list_for_each_entry(param, params, list) {
+               if (!strcmp(param->name, IFACE_ISCSINAME)) {
+                       log_error("Can not update "
+                                 "iface.iscsi_ifacename. Delete it, "
+                                 "and then create a new one.");
+                       return ISCSI_ERR_INVAL;
+               }
+
+               if (iface_is_bound_by_hwaddr(&rec->iface) &&
+                   !strcmp(param->name, IFACE_NETNAME)) {
+                       log_error("Can not update interface binding "
+                                 "from hwaddress to net_ifacename. "
+                                 "You must delete the interface and "
+                                 "create a new one");
+                       return ISCSI_ERR_INVAL;
+               }
+
+               if (iface_is_bound_by_netdev(&rec->iface) &&
+                   !strcmp(param->name, IFACE_HWADDR)) {
+                       log_error("Can not update interface binding "
+                                 "from net_ifacename to hwaddress. "
+                                 "You must delete the interface and "
+                                 "create a new one");
+                       return ISCSI_ERR_INVAL;
+               }
+       }
+       return 0;
+}
+
+static void _print_iface_tree(struct iscsi_node **nodes, uint32_t node_count,
+                             const char *iface_name,
+                             struct iscsi_node **matched_nodes)
+{
+       struct iscsi_node *node = NULL;
+       uint32_t matched_node_count = 0;
+       uint32_t i = 0;
+
+       for (i = 0; i < node_count; ++i) {
+               node = nodes[i];
+               if (strcmp(iface_name, iscsi_node_iface_name_get(node))
+                   == 0)
+                       matched_nodes[matched_node_count++] = node;
+       }
+       printf("Iface: %s\n", iface_name);
+       print_nodes_tree(matched_nodes, matched_node_count, _PRINT_MODE_IFACE);
+}
+
+static int print_iface_tree(struct iscsi_context *ctx,
+                            const char *iface_name)
+{
+       int rc = 0;
+       struct iscsi_node **nodes = NULL;
+       struct iscsi_node **matched_nodes = NULL;
+       uint32_t node_count = 0;
+       struct iscsi_iface *iface = NULL;
+       struct iscsi_iface **ifaces = NULL;
+       uint32_t iface_count = 0;
+       uint32_t i = 0;
+
+       _good(iscsi_nodes_get(ctx, &nodes, &node_count),
+             rc, out);
+       if (node_count == 0)
+               goto out;
+       matched_nodes = calloc(node_count, sizeof(struct iscsi_node *));
+       if (matched_nodes == NULL) {
+               log_error("No memory");
+               goto out;
+       }
+
+       if (iface_name != NULL) {
+               // Just make sure specified iface exists
+               _good(iscsi_iface_get(ctx, iface_name, &iface), rc, out);
+               _print_iface_tree(nodes, node_count, iface_name,
+                                 matched_nodes);
+       } else {
+               _good(iscsi_ifaces_get(ctx, &ifaces, &iface_count),
+                     rc, out);
+               for (i = 0; i < iface_count; ++i)
+                       _print_iface_tree(nodes, node_count,
+                                         iscsi_iface_name_get(ifaces[i]),
+                                         matched_nodes);
+       }
+
+out:
+       free(matched_nodes);
+       iscsi_ifaces_free(ifaces, iface_count);
+       iscsi_iface_free(iface);
+       iscsi_nodes_free(nodes, node_count);
+       return rc;
+}
+
+static int iface_param_update(struct iface_rec *iface, struct list_head *params)
+{
+       struct node_rec *rec;
+       int rc = 0;
+
+       rec = idbm_create_rec(NULL, -1, NULL, -1, iface, 1);
+       if (!rec) {
+               rc = ISCSI_ERR_INVAL;
+               goto update_fail;
+       }
+
+       if (iscsi_check_for_running_session(rec))
+               log_warning("Updating iface while iscsi sessions "
+                           "are using it. You must logout the running "
+                           "sessions then log back in for the "
+                           "new settings to take affect.");
+
+       rc = verify_iface_params(params, rec);
+       if (rc)
+               goto update_fail;
+
+       rc = iface_conf_update(params, &rec->iface);
+       if (rc)
+               goto update_fail;
+
+       rc = __for_each_matched_rec(0, rec, params, idbm_node_set_param);
+       if (rc == ISCSI_ERR_NO_OBJS_FOUND)
+               rc = 0;
+       else if (rc)
+               goto update_fail;
+
+       printf("%s updated.\n", iface->name);
+       free(rec);
+       return rc;
+
+update_fail:
+       log_error("Could not update iface %s: %s",
+                 iface->name, iscsi_err_to_str(rc));
+       free(rec);
+       return rc;
+}
+
+struct iface_param_sync {
+       struct iface_rec *primary;
+       struct list_head *params;
+       int count;
+};
+
+static int update_sync_params(void *data, struct iface_rec *iface)
+{
+       struct iface_param_sync *iface_params = data;
+       struct iface_rec *primary = iface_params->primary;
+       struct list_head *params = iface_params->params;
+
+       if ((strcmp(primary->transport_name, iface->transport_name)) ||
+           (strcmp(primary->hwaddress, iface->hwaddress)) ||
+           (primary->iface_num != iface->iface_num))
+               return 0;
+
+       return iface_param_update(iface, params);
+}
+
+static int split_vlan_params(struct list_head *params, struct list_head *vlan_params)
+{
+       struct user_param *param, *tmp;
+
+       list_for_each_entry_safe(param, tmp, params, list) {
+               if (!strncmp(param->name, "iface.vlan", 10)) {
+                       list_move_tail(&param->list, vlan_params);
+               }
+       }
+       return 0;
+}
+
+static inline void list_splice_tail(struct list_head *list, struct list_head *head)
+{
+       list->prev->next = head;
+       list->next->prev = head->prev;
+       head->prev->next = list->next;
+       head->prev = list->prev;
+       INIT_LIST_HEAD(list);
+}
+
+/* TODO: merge iter helpers and clean them up, so we can use them here */
+static int exec_iface_op(struct iscsi_context *ctx,
+                        int op,
+                        __attribute__((unused))int do_show,
+                        int info_level,
+                        struct iface_rec *iface,
+                        uint64_t host_no,
+                        struct list_head *params)
+{
+       struct host_info hinfo;
+       struct node_rec *rec = NULL;
+       int rc = 0;
+       struct iscsi_iface **ifaces = NULL;
+       struct iscsi_iface *iface_info = NULL;
+       uint32_t iface_count = 0;
+       uint32_t i = 0;
+
+       LIST_HEAD(vlan_params);
+       struct iscsi_transport *t;
+       switch (op) {
+       case OP_NEW:
+               if (!iface) {
+                       log_error("Could not add interface. No interface "
+                                 "passed in.");
+                       return EINVAL;
+               }
+
+               rec = idbm_create_rec(NULL, -1, NULL, -1, iface, 0);
+               if (rec && iscsi_check_for_running_session(rec)) {
+                       rc = ISCSI_ERR_SESS_EXISTS;
+                       goto new_fail;
+               }
+
+               iface_setup_defaults(iface);
+               rc = iface_conf_write(iface);
+               if (rc)
+                       goto new_fail;
+               iface_param_update(iface, params);
+               printf("New interface %s added\n", iface->name);
+               break;
+new_fail:
+               log_error("Could not create new interface %s.", iface->name);
+               break;
+       case OP_DELETE:
+               if (!iface) {
+                       log_error("Could not delete interface. No interface "
+                                 "passed in.");
+                       return ISCSI_ERR_INVAL;
+               }
+
+               rec = idbm_create_rec(NULL, -1, NULL, -1, iface, 1);
+               if (!rec) {
+                       rc = ISCSI_ERR_INVAL;
+                       goto delete_fail;
+               }
+
+               /* logout and delete records using it first */
+               rc = __for_each_matched_rec(0, rec, NULL, delete_node);
+               if (rc && rc != ISCSI_ERR_NO_OBJS_FOUND)
+                       goto delete_fail;
+
+               rc = iface_conf_delete(iface);
+               if (rc)
+                       goto delete_fail;
+
+               printf("%s unbound and deleted.\n", iface->name);
+               break;
+delete_fail:
+               log_error("Could not delete iface %s: %s", iface->name,
+                         iscsi_err_to_str(rc));
+               break;
+       case OP_UPDATE:
+               if (!iface || list_empty(params)) {
+                       log_error("Update requires name, value, and iface.");
+                       rc = ISCSI_ERR_INVAL;
+                       break;
+               }
+
+               rec = idbm_create_rec(NULL, -1, NULL, -1, iface, 1);
+               if (!rec) {
+                       rc = ISCSI_ERR_INVAL;
+                       break;
+               }
+               t = iscsi_sysfs_get_transport_by_name(rec->iface.transport_name);
+               if (!t) {
+                       log_error("Cound not locate transport for iface %s", iface->name);
+                       rc = ISCSI_ERR_INVAL;
+                       break;
+               }
+               if (t->template->sync_vlan_settings) {
+                       /* sync shared vlan settings across ifaces */
+                       int nr_found = 0;
+                       struct iface_param_sync sync_params = {
+                               .primary = &rec->iface,
+                               .params = &vlan_params,
+                               .count = 0,
+                       };
+                       split_vlan_params(params, &vlan_params);
+                       iface_for_each_iface(&sync_params, 1, &nr_found, update_sync_params);
+               }
+               iface_param_update(&rec->iface, params);
+               list_splice_tail(&vlan_params, params);
+               break;
+       case OP_APPLY:
+               if (!iface) {
+                       log_error("Apply requires iface.");
+                       rc = ISCSI_ERR_INVAL;
+                       break;
+               }
+               rc = iface_conf_read(iface);
+               if (rc) {
+                       log_error("Could not read iface %s (%d).",
+                                 iface->name, rc);
+                       break;
+               }
+
+               rc = iface_apply_net_config(iface, op);
+               if (rc) {
+                       log_error("Could not apply net configuration: %s",
+                                 iscsi_err_to_str(rc));
+                       break;
+               }
+               printf("%s applied.\n", iface->name);
+               break;
+       case OP_APPLY_ALL:
+               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;
+               }
+
+               /*
+                * Need to get other iface info like transport.
+                */
+               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%" PRIu64 " to ifaces.",
+                                 host_no);
+                       rc = ISCSI_ERR_INVAL;
+                       break;
+               }
+               rc = iface_apply_net_config(&hinfo.iface, op);
+               if (rc) {
+                       log_error("Could not apply net configuration: %s",
+                                 iscsi_err_to_str(rc));
+                       break;
+               }
+
+               printf("Applied settings to ifaces attached to host%" PRIu64 ".\n",
+                      host_no);
+               break;
+       default:
+               if ((op != OP_NOOP) && (op != OP_SHOW)) {
+                       rc = ISCSI_ERR_INVAL;
+                       goto out;
+               }
+               switch (info_level) {
+               case 0:
+               case -1:
+                       if (iface == NULL) {
+                               _good(iscsi_ifaces_get(ctx, &ifaces,
+                                                      &iface_count),
+                                     rc, out);
+                               if (iface_count == 0) {
+                                       log_error("No interfaces found.");
+                                       rc = ISCSI_ERR_NO_OBJS_FOUND;
+                                       goto out;
+                               }
+
+                               for (i = 0; i < iface_count; ++i)
+                                       iface_print_flat(ifaces[i]);
+                       } else {
+                               _good(iscsi_iface_get(ctx, iface->name,
+                                                     &iface_info),
+                                     rc, out);
+                               iscsi_iface_print_config(iface_info);
+                       }
+                       break;
+               case 1:
+                       /*
+                        * TODO: we can display how the ifaces are related to
+                        * node records.
+                        * And we can add a scsi_host mode which would display
+                        * how sessions are related to hosts (scsi_host and
+                        * iscsi_sessions are the currently running instance of
+                        * an iface or node record).
+                        */
+                       /*
+                        * TODO(Gris Ge): Once we have node support from
+                        * libopeniscsiusr, change below codes.
+                        */
+                       rc = print_iface_tree(ctx, iface ? iface->name : NULL);
+                       break;
+               default:
+                       log_error("Invalid info level %d. Try 0 - 1.",
+                                 info_level);
+                       rc = LIBISCSI_ERR_INVAL;
+                       goto out;
+               }
+       }
+
+out:
+       iscsi_ifaces_free(ifaces, iface_count);
+       iscsi_iface_free(iface_info);
+
+       if (rec)
+               free(rec);
+       return rc;
+}
+
+static int verify_node_params(struct list_head *params, struct node_rec *rec)
+{
+       struct user_param *param;
+
+       if (list_empty(params)) {
+               log_error("update requires name and value");
+               return ISCSI_ERR_INVAL;
+       }
+
+       list_for_each_entry(param, params, list) {
+               /* compat - old tools used node and iface transport name */
+               if (!strncmp(param->name, "iface.", 6) &&
+                    strcmp(param->name, "iface.transport_name")) {
+                       log_error("Cannot modify %s. Use iface mode to update "
+                                 "this value.", param->name);
+                       return ISCSI_ERR_INVAL;
+               }
+
+               if (!strcmp(param->name, "node.transport_name")) {
+                       free(param->name);
+                       param->name = strdup("iface.transport_name");
+                       if (!param->name) {
+                               log_error("Could not allocate memory for "
+                                         "param.");
+                               return ISCSI_ERR_NOMEM;
+                       }
+               }
+               /*
+                * tmp hack - we added compat crap above for the transport,
+                * but want to fix Doran's issue in this release too. However
+                * his patch is too harsh on many settings and we do not have
+                * time to update apps so we have this tmp hack until we
+                * can settle on a good interface that distros can use
+                * and we can mark stable.
+                */
+               if (!strcmp(param->name, "iface.transport_name")) {
+                       if (iscsi_check_for_running_session(rec)) {
+                               log_warning("Cannot modify node/iface "
+                                           "transport name while a session "
+                                           "is using it. Log out the session "
+                                           "then update record.");
+                               return ISCSI_ERR_SESS_EXISTS;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+/* TODO cleanup arguments */
+static int exec_node_op(struct iscsi_context *ctx, int op, int do_login,
+                       int do_logout, int do_show, int do_rescan, int do_stats,
+                       bool wait, int info_level, struct node_rec *rec,
+                       struct list_head *params)
+{
+       int rc = 0;
+
+       if (rec)
+               log_debug(2, "%s: %s:%s node [%s,%s,%d] sid %u", __FUNCTION__,
+                         rec->iface.transport_name, rec->iface.name,
+                         rec->name, rec->conn[0].address, rec->conn[0].port,
+                         rec->session.sid);
+
+       if (op == OP_NEW) {
+               rc = add_static_recs(rec);
+               goto out;
+       }
+
+       if (do_rescan) {
+               rc = for_each_session(rec, rescan_portal, 1);
+               goto out;
+       }
+
+       if (do_stats) {
+               rc = for_each_session(rec, session_stats, 0);
+               goto out;
+       }
+
+       if (do_login && do_logout) {
+               log_error("Invalid parameters. Both login and logout passed in");
+               rc = ISCSI_ERR_INVAL;
+               goto out;
+       }
+
+       if ((do_login || do_logout) && op > OP_NOOP) {
+               log_error("Invalid parameters. Login/logout and op passed in");
+               rc = ISCSI_ERR_INVAL;
+               goto out;
+       }
+
+       if ((!do_login && !do_logout && op == OP_NOOP) &&
+           ((rec == NULL) ||
+            (!strlen(rec->name) && !strlen(rec->conn[0].address) &&
+             !strlen(rec->iface.name)))) {
+               rc = print_nodes(ctx, info_level);
+               goto out;
+       }
+
+       if (do_login) {
+               rc = login_portals(rec, wait);
+               goto out;
+       }
+
+       if (do_logout) {
+               int nr_found;
+
+               rc = iscsi_logout_portals(rec, &nr_found, 1,
+                                         iscsi_logout_matched_portal);
+               if (rc == ISCSI_ERR_NO_OBJS_FOUND)
+                       log_error("No matching sessions found");
+               goto out;
+       }
+
+       if (op == OP_NOOP || (!do_login && !do_logout && op == OP_SHOW)) {
+               rc = print_nodes_config(ctx, do_show ? true : false,
+                                       rec->name, rec->conn[0].address,
+                                       rec->conn[0].port, rec->iface.name);
+               goto out;
+       }
+
+       if (op == OP_UPDATE) {
+               rc = verify_node_params(params, rec);
+               if (rc)
+                       goto out;
+
+               rc = for_each_matched_rec(rec, params, idbm_node_set_param);
+               goto out;
+       } else if (op == OP_DELETE) {
+               rc = for_each_matched_rec(rec, NULL, delete_node);
+               goto out;
+       } else {
+               log_error("operation is not supported.");
+               rc = ISCSI_ERR_INVAL;
+               goto out;
+       }
+out:
+       return rc;
+}
+
+static int exec_fw_disc_op(discovery_rec_t *drec, struct list_head *ifaces,
+                          int info_level, int do_login, int op)
+{
+       LIST_HEAD(targets);
+       LIST_HEAD(rec_list);
+       LIST_HEAD(new_ifaces);
+       struct iface_rec *iface, *tmp_iface;
+       struct node_rec *rec, *tmp_rec;
+       int rc = 0;
+
+       /*
+        * 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;
+
+       /*
+        * if a user passed in ifaces then we use them and ignore the ibft
+        * net info
+        */
+       if (!list_empty(ifaces)) {
+               list_for_each_entry_safe(iface, tmp_iface, ifaces, list) {
+                       rc = iface_conf_read(iface);
+                       if (rc) {
+                               log_error("Could not read iface info for %s. "
+                                         "Make sure an iface config with the "
+                                         "file name and iface.iscsi_ifacename "
+                                         "%s is in %s.", iface->name,
+                                         iface->name, IFACE_CONFIG_DIR);
+                               list_del_init(&iface->list);
+                               free(iface);
+                               continue;
+                       }
+               }
+               goto discover_fw_tgts;
+       }
+
+       /*
+        * Next, check if we see any offload cards. If we do then
+        * we make an iface if needed.
+        *
+        * Note1: if there is not a offload card we do not setup
+        * software iscsi binding with the nic used for booting,
+        * because we do not know if that was intended.
+        *
+        * Note2: we assume that the user probably wanted to access
+        * all targets through all the ifaces instead of being limited
+        * to what you can export in ibft.
+        */
+       rc = fw_get_targets(&targets);
+       if (rc) {
+               log_error("Could not get list of targets from firmware. "
+                         "(err %d)", rc);
+               return rc;
+       }
+       rc = iface_create_ifaces_from_boot_contexts(&new_ifaces, &targets);
+       if (rc)
+               goto done;
+       if (!list_empty(&new_ifaces))
+               ifaces = &new_ifaces;
+
+discover_fw_tgts:
+       rc = idbm_bind_ifaces_to_nodes(discovery_fw, drec,
+                                      ifaces, &rec_list);
+       if (rc)
+               log_error("Could not perform fw discovery.");
+       else
+               rc = exec_disc_op_on_recs(drec, &rec_list, info_level,
+                                          do_login, op);
+
+done:
+       fw_free_targets(&targets);
+
+       list_for_each_entry_safe(iface, tmp_iface, &new_ifaces, list) {
+               list_del(&iface->list);
+               free(iface);
+       }
+
+       list_for_each_entry_safe(rec, tmp_rec, &rec_list, list) {
+               list_del(&rec->list);
+               free(rec);
+       }
+       return rc;
+}
+
+static int fill_in_default_fw_values(node_rec_t *rec, struct list_head *params)
+{
+       struct user_param *param;
+       int rc;
+
+       /* must init this so we can check if user overrode them */
+       rec->session.initial_login_retry_max = -1;
+       rec->conn[0].timeo.noop_out_interval = -1;
+       rec->conn[0].timeo.noop_out_timeout = -1;
+       rec->session.scan = -1;
+
+       list_for_each_entry(param, params, list) {
+               /*
+                * do not allow user to override iface parameters, since
+                * firmware/ibft values should be used and not overridden
+                */
+               if (!strcmp(param->name, IFACE_NETNAME) ||
+                   !strcmp(param->name, IFACE_HWADDR) ||
+                   !strcmp(param->name, IFACE_TRANSPORTNAME)) {
+                       log_error("Cannot override interface parameters for firmware logins");
+                       return ISCSI_ERR_INVAL;
+               }
+       }
+
+       if (!list_empty(params)) {
+               rc = idbm_node_set_rec_from_param(params, rec, 0);
+               if (rc)
+                       return rc;
+       }
+
+       /*
+        * For root boot we could not change this in older versions so
+        * if user did not override then use the defaults.
+        *
+        * Increase to account for boot using static setup.
+        */
+       if (rec->session.initial_login_retry_max == -1)
+               rec->session.initial_login_retry_max = 30;
+
+       /* firmware logins are usually used for booting, so no NOPs */
+       if (rec->conn[0].timeo.noop_out_interval == -1)
+               rec->conn[0].timeo.noop_out_interval = 0;
+       if (rec->conn[0].timeo.noop_out_timeout == -1)
+               rec->conn[0].timeo.noop_out_timeout = 0;
+
+       /* default scan mode is "auto" */
+       if (rec->session.scan == -1)
+               rec->session.scan = DEF_INITIAL_SCAN;
+
+       return 0;
+}
+
+static int exec_fw_op(discovery_rec_t *drec, struct list_head *ifaces,
+                     int info_level, int do_login, int op, bool wait,
+                     struct list_head *params)
+{
+       struct boot_context *context;
+       LIST_HEAD(targets);
+        LIST_HEAD(rec_list);
+       struct node_rec *rec;
+       int rc = 0;
+
+       if (drec)
+               return exec_fw_disc_op(drec, ifaces, info_level, do_login, op);
+
+       /* The following ops do not interact with the DB */
+       rc = fw_get_targets(&targets);
+       if (rc) {
+               log_error("Could not get list of targets from firmware. "
+                         "(err %d)", rc);
+               return rc;
+       }
+
+       if (do_login) {
+               list_for_each_entry(context, &targets, list) {
+                       rec = idbm_create_rec_from_boot_context(context);
+                       if (!rec) {
+                               log_error("Could not convert firmware info to "
+                                         "node record.");
+                               rc = ISCSI_ERR_NOMEM;
+                               break;
+                       }
+                       /* update rec based on params and default values */
+                       rc = fill_in_default_fw_values(rec, params);
+                       if (rc) {
+                               log_error("Could not merge user params");
+                               break;
+                       }
+
+                       if (wait)
+                               iscsi_login_portal(NULL, NULL, rec);
+                       else
+                               iscsi_login_portal_nowait(rec);
+                       free(rec);
+               }
+       } else {
+               list_for_each_entry(context, &targets, list)
+                       fw_print_entry(context);
+       }
+
+       fw_free_targets(&targets);
+       return rc;
+}
+
+static void setup_drec_defaults(int type, char *ip, int port,
+                               struct discovery_rec *drec)
+{
+       switch (type) {
+       case DISCOVERY_TYPE_ISNS:
+               idbm_isns_defaults(&drec->u.isns);
+               break;
+       case DISCOVERY_TYPE_SENDTARGETS:
+               idbm_sendtargets_defaults(&drec->u.sendtargets);
+               break;
+       default:
+               log_error("Invalid disc type.");
+       }
+       strlcpy(drec->address, ip, sizeof(drec->address));
+       drec->port = port;
+       drec->type = type;
+}
+
+/**
+ * exec_discover - prep, add, read and exec discovery on drec
+ * @type: discovery type
+ * @ip: IP address
+ * @port: port
+ * @ifaces: list of ifaces to bind to
+ * @info_level: print level
+ * @do_login: set to 1 if discovery function should also log into portals found
+ * @do_discover: set to 1 if discovery was requested
+ * @op: ops passed in by user
+ * @drec: discovery rec struct
+ *
+ * This function determines what type of op needs to be executed
+ * and will read and add a drec, and perform discovery if needed.
+ *
+ * returns:
+ *     Greater than 0 - error
+ *     0 - op/discovery completed
+ *     -1 - exec db op
+ */
+static int exec_discover(int disc_type, char *ip, int port,
+                        struct list_head *ifaces, int info_level,
+                        int do_login, int do_discover, int op,
+                        struct discovery_rec *drec)
+{
+       int rc;
+
+       if (ip == NULL) {
+               log_error("Please specify portal as <ipaddr>[:<ipport>]");
+               return ISCSI_ERR_INVAL;
+       }
+
+       if (op & OP_NEW && !do_discover) {
+               setup_drec_defaults(disc_type, ip, port, drec);
+
+               rc = idbm_add_discovery(drec);
+               if (rc) {
+                       log_error("Could not add new discovery record.");
+                       return rc;
+               } else {
+                       printf("New discovery record for [%s,%d] added.\n", ip,
+                              port);
+                       return 0;
+               }
+       }
+
+       rc = idbm_discovery_read(drec, disc_type, ip, port);
+       if (rc) {
+               if (!do_discover) {
+                       log_error("Discovery record [%s,%d] not found.",
+                                 ip, port);
+                       return rc;
+               }
+
+               /* Just add default rec for user */
+               log_debug(1, "Discovery record [%s,%d] not found!",
+                         ip, port);
+               setup_drec_defaults(disc_type, ip, port, drec);
+               if (!(op & OP_NONPERSISTENT)) {
+                       rc = idbm_add_discovery(drec);
+                       if (rc) {
+                               log_error("Could not add new discovery "
+                                         "record.");
+                               return rc;
+                       }
+               }
+       } else if (!do_discover)
+               return -1;
+
+       rc = 0;
+       switch (disc_type) {
+       case DISCOVERY_TYPE_SENDTARGETS:
+       case DISCOVERY_TYPE_ISNS:
+               rc = do_target_discovery(drec, ifaces, info_level, do_login, op,
+                                   0);
+               break;
+       default:
+               log_error("Unsupported discovery type.");
+               break;
+       }
+
+       return rc;
+}
+
+static int exec_disc2_op(int disc_type, char *ip, int port,
+                        struct list_head *ifaces, int info_level, int do_login,
+                        int do_discover, int op, struct list_head *params,
+                        int do_show)
+{
+       struct discovery_rec drec;
+       int rc = 0;
+
+       memset(&drec, 0, sizeof(struct discovery_rec));
+       drec.iscsid_req_tmo = -1;
+       if (disc_type != -1)
+               drec.type = disc_type;
+
+       switch (disc_type) {
+       case DISCOVERY_TYPE_SENDTARGETS:
+               if (port < 0)
+                       port = ISCSI_LISTEN_PORT;
+
+               rc = exec_discover(disc_type, ip, port, ifaces, info_level,
+                                  do_login, do_discover, op, &drec);
+               if (rc < 0)
+                       goto do_db_op;
+               goto done;
+       case DISCOVERY_TYPE_SLP:
+               log_error("SLP discovery is not fully implemented yet.");
+               rc = ISCSI_ERR_INVAL;
+               goto done;
+       case DISCOVERY_TYPE_ISNS:
+               if (port < 0)
+                       port = ISNS_DEFAULT_PORT;
+
+               rc = exec_discover(disc_type, ip, port, ifaces, info_level,
+                                  do_login, do_discover, op, &drec);
+               if (rc < 0)
+                       goto do_db_op;
+               goto done;
+       case DISCOVERY_TYPE_FW:
+               if (!do_discover) {
+                       log_error("Invalid command. Possibly missing "
+                                 "--discover argument.");
+                       rc = ISCSI_ERR_INVAL;
+                       goto done;
+               }
+
+               drec.type = DISCOVERY_TYPE_FW;
+               rc = exec_fw_op(&drec, ifaces, info_level, do_login, op, true, NULL);
+               goto done;
+       default:
+               rc = ISCSI_ERR_INVAL;
+
+               if (!ip) {
+                        if (op == OP_NOOP || op == OP_SHOW) {
+                               if (idbm_print_all_discovery(info_level))
+                                       /* successfully found some recs */
+                                       rc = 0;
+                               else
+                                       rc = ISCSI_ERR_NO_OBJS_FOUND;
+                       } else
+                               log_error("Invalid operation. Operation not "
+                                         "supported.");
+               } else if (op)
+                       log_error("Invalid command. Possibly missing discovery "
+                                 "--type.");
+               else
+                       log_error("Invalid command. Portal not needed or "
+                                 "Possibly missing discovery --type.");
+               goto done;
+       }
+
+do_db_op:
+       rc = 0;
+
+       if (op == OP_NOOP || op == OP_SHOW) {
+               if (!idbm_print_discovery_info(&drec, do_show)) {
+                       log_error("No records found");
+                       rc = ISCSI_ERR_NO_OBJS_FOUND;
+               }
+       } else if (op == OP_DELETE) {
+               rc = idbm_delete_discovery(&drec);
+               if (rc)
+                       log_error("Unable to delete record!");
+       } else if (op == OP_UPDATE) {
+               if (list_empty(params)) {
+                       log_error("Update requires name and value.");
+                       rc = ISCSI_ERR_INVAL;
+                       goto done;
+               }
+               rc = idbm_discovery_set_param(params, &drec);
+       } else {
+               log_error("Operation is not supported.");
+               rc = ISCSI_ERR_INVAL;
+               goto done;
+       }
+done:
+       return rc;
+}
+
+static int exec_disc_op(int disc_type,
+                       char *ip,
+                       int port,
+                       struct list_head *ifaces,
+                       int info_level,
+                       int do_login,
+                       int do_discover,
+                       int op,
+                       __attribute__((unused))struct list_head *params,
+                       int do_show,
+                       bool wait)
+{
+       struct discovery_rec drec;
+       int rc = 0;
+
+       memset(&drec, 0, sizeof(struct discovery_rec));
+       drec.iscsid_req_tmo = -1;
+
+       switch (disc_type) {
+       case DISCOVERY_TYPE_SENDTARGETS:
+               drec.type = DISCOVERY_TYPE_SENDTARGETS;
+
+               if (port < 0)
+                       port = ISCSI_LISTEN_PORT;
+
+               if (ip == NULL) {
+                       log_error("Please specify portal as "
+                                 "<ipaddr>[:<ipport>]");
+                       rc = ISCSI_ERR_INVAL;
+                       goto done;
+               }
+
+               idbm_sendtargets_defaults(&drec.u.sendtargets);
+               strlcpy(drec.address, ip, sizeof(drec.address));
+               drec.port = port;
+               rc = do_target_discovery(&drec, ifaces, info_level,
+                                   do_login, op, 1);
+               if (rc)
+                       goto done;
+               break;
+       case DISCOVERY_TYPE_SLP:
+               log_error("SLP discovery is not fully implemented yet.");
+               rc = ISCSI_ERR_INVAL;
+               break;
+       case DISCOVERY_TYPE_ISNS:
+               if (!ip) {
+                       log_error("Please specify portal as "
+                                 "<ipaddr>:[<ipport>]");
+                       rc = ISCSI_ERR_INVAL;
+                       goto done;
+               }
+
+               strlcpy(drec.address, ip, sizeof(drec.address));
+               if (port < 0)
+                       drec.port = ISNS_DEFAULT_PORT;
+               else
+                       drec.port = port;
+
+               drec.type = DISCOVERY_TYPE_ISNS;
+               rc = do_target_discovery(&drec, ifaces, info_level,
+                                       do_login, op, 0);
+               if (rc)
+                       goto done;
+               break;
+       case DISCOVERY_TYPE_FW:
+               drec.type = DISCOVERY_TYPE_FW;
+               rc = exec_fw_op(&drec, ifaces, info_level, do_login, op, wait, NULL);
+               break;
+       default:
+               if (ip) {
+                       /*
+                        * We only have sendtargets disc recs in discovery
+                        * mode, so we can hardcode the port check to the
+                        * iscsi default here.
+                        *
+                        * For isns or slp recs then discovery db mode
+                        * must be used.
+                        */
+                       if (port < 0)
+                               port = ISCSI_LISTEN_PORT;
+
+                       if (idbm_discovery_read(&drec,
+                                               DISCOVERY_TYPE_SENDTARGETS,
+                                               ip, port)) {
+                               log_error("Discovery record [%s,%d] "
+                                         "not found!", ip, port);
+                               rc = ISCSI_ERR_INVAL;
+                               goto done;
+                       }
+                       if ((do_discover || do_login) &&
+                           drec.type == DISCOVERY_TYPE_SENDTARGETS) {
+                               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)) {
+                                       log_error("No records found");
+                                       rc = ISCSI_ERR_NO_OBJS_FOUND;
+                               }
+                       } else if (op == OP_DELETE) {
+                               rc = idbm_delete_discovery(&drec);
+                               if (rc)
+                                       log_error("Unable to delete record!");
+                       } else if (op == OP_UPDATE || op == OP_NEW) {
+                               log_error("Operations new and update for "
+                                         "discovery mode is not supported. "
+                                         "Use discoverydb mode.");
+                               rc = ISCSI_ERR_INVAL;
+                               goto done;
+                       } else {
+                               log_error("Invalid operation.");
+                               rc = ISCSI_ERR_INVAL;
+                               goto done;
+                       }
+               } else if (op == OP_NOOP || op == OP_SHOW) {
+                       if (!idbm_print_all_discovery(info_level))
+                               rc = ISCSI_ERR_NO_OBJS_FOUND;
+                       goto done;
+               } else {
+                       log_error("Invalid operation.");
+                       rc = ISCSI_ERR_INVAL;
+                       goto done;
+               }
+               /* fall through */
+       }
+
+done:
+       return rc;
+}
+
+static uint64_t parse_host_info(char *optarg, int *rc)
+{
+       int err = 0;
+       uint64_t host_no;
+
+       *rc = 0;
+       if (strstr(optarg, ":")) {
+               transport_probe_for_offload();
+
+               host_no = iscsi_sysfs_get_host_no_from_hwaddress(optarg,
+                                                                &err);
+               if (err) {
+                       log_error("Could not match MAC to host.");
+                       *rc = ISCSI_ERR_INVAL;
+               }
+       } else {
+               errno = 0;      // ensure errors from strtoull are real
+               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;
+               }
+       }
+       return host_no;
+}
+
+static char *iscsi_ping_stat_strs[] = {
+       /* ISCSI_PING_SUCCESS */
+       "success",
+       /* ISCSI_PING_FW_DISABLED */
+       "firmware disabled",
+       /* ISCSI_PING_IPADDR_INVALID */
+       "invalid IP address",
+       /* ISCSI_PING_LINKLOCAL_IPV6_ADDR_INVALID */
+       "invalid link local IPv6 address",
+       /* ISCSI_PING_TIMEOUT */
+       "timed out",
+       /* ISCSI_PING_INVALID_DEST_ADDR */
+       "invalid destination address",
+       /* ISCSI_PING_OVERSIZE_PACKET */
+       "oversized packet",
+       /* ISCSI_PING_ICMP_ERROR */
+       "ICMP error",
+       /* ISCSI_PING_MAX_REQ_EXCEEDED */
+       "Max request exceeded",
+       /* ISCSI_PING_NO_ARP_RECEIVED */
+       "No ARP response received",
+};
+
+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", status);
+               return NULL;
+       }
+
+       return iscsi_ping_stat_strs[status];
+}
+
+static int exec_ping_op(struct iface_rec *iface, char *ip, int size, int count,
+                       int interval)
+{
+       int rc = ISCSI_ERR;
+       uint32_t iface_type = ISCSI_IFACE_TYPE_IPV4;
+       struct iscsi_transport *t = NULL;
+       uint32_t host_no, status = 0;
+       struct sockaddr_storage addr;
+       struct host_info hinfo;
+       int i;
+
+       if (!iface) {
+               log_error("Ping requires iface.");
+               rc = ISCSI_ERR_INVAL;
+               goto ping_exit;
+       }
+
+       if (!ip) {
+               log_error("Ping requires destination ipaddress.");
+               rc = ISCSI_ERR_INVAL;
+               goto ping_exit;
+       }
+
+       if (size <= 0) {
+               log_error("Invalid packet size: %d.", size);
+               rc = ISCSI_ERR_INVAL;
+               goto ping_exit;
+       }
+
+       if (count <= 0) {
+               log_error("Invalid number of packets to transmit: %d.", count);
+               rc = ISCSI_ERR_INVAL;
+               goto ping_exit;
+       }
+
+       if (interval < 0) {
+               log_error("Invalid timing interval: %d.", interval);
+               rc = ISCSI_ERR_INVAL;
+               goto ping_exit;
+       }
+
+       rc = iface_conf_read(iface);
+       if (rc) {
+               log_error("Could not read iface %s (%d).", iface->name, rc);
+               goto ping_exit;
+       }
+
+
+       iface_type = iface_get_iptype(iface);
+
+       t = iscsi_sysfs_get_transport_by_name(iface->transport_name);
+       if (!t) {
+               log_error("Can't find transport.");
+               rc = ISCSI_ERR_INVAL;
+               goto ping_exit;
+       }
+
+       host_no = iscsi_sysfs_get_host_no_from_hwinfo(iface, &rc);
+       if (host_no == 0) {
+               log_error("Can't find host_no.");
+               rc = ISCSI_ERR_INVAL;
+               goto ping_exit;
+       }
+
+       rc = resolve_address(ip, NULL, &addr);
+       if (rc) {
+               log_error("Invalid IP address.");
+               rc = ISCSI_ERR_INVAL;
+               goto ping_exit;
+       }
+
+       /* TODO: move this. It is needed by interface for pid */
+       srand(time(NULL));
+
+       for (i = 1; i <= count; i++) {
+               /*
+                * To support drivers like bnx2i that do not use
+                * the iscsi iface to send a ping, we invoke transport
+                * callout here.
+                */
+               status = 0;
+               if (t->template->exec_ping) {
+                       if (!strlen(iface->netdev)) {
+                               memset(&hinfo, 0, sizeof(hinfo));
+                               hinfo.host_no = host_no;
+                               iscsi_sysfs_get_hostinfo_by_host_no(&hinfo);
+                               strcpy(iface->netdev, hinfo.iface.netdev);
+                       }
+
+                       rc = iscsi_set_net_config(t, NULL, iface);
+                       if (rc && (rc != ISCSI_ERR_AGAIN))
+                               goto ping_err;
+
+                       rc = t->template->exec_ping(t, iface, size, &addr,
+                                                   &status);
+               } else {
+                       rc = ipc->exec_ping(t->handle, host_no,
+                                           (struct sockaddr *)&addr,
+                                           iface->iface_num, iface_type,
+                                           (uint32_t)size, &status);
+               }
+
+ping_err:
+               if (!rc && !status)
+                       printf("Ping %d completed\n", i);
+               else if (status)
+                       printf("Ping %d failed: %s\n", i,
+                               iscsi_ping_stat_to_str(status));
+               else
+                       printf("Ping %d failed: %s\n", i, iscsi_err_to_str(rc));
+
+               if (i < count)
+                       sleep(interval);
+       }
+
+ping_exit:
+       return rc;
+}
+
+int
+main(int argc, char **argv)
+{
+       char *ip = NULL, *name = NULL, *value = NULL;
+       char *targetname = NULL, *group_session_mgmt_mode = NULL;
+       int ch, longindex, mode=-1, port=-1, do_login=0, do_rescan=0;
+       int rc=0, sid=-1, op=OP_NOOP, type=-1, do_logout=0, do_stats=0;
+       int do_login_all=0, do_logout_all=0, info_level=-1, num_ifaces = 0;
+       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;
+       int timeout = ISCSID_REQ_TIMEOUT;
+       struct sigaction sa_old;
+       struct sigaction sa_new;
+       LIST_HEAD(ifaces);
+       struct iface_rec *iface = NULL, *tmp_iface;
+       struct node_rec *rec = NULL;
+       uint32_t host_no =  MAX_HOST_NO + 1;
+       uint64_t index = ULLONG_MAX;
+       struct user_param *param, *tmp_param;
+       LIST_HEAD(params);
+       struct iscsi_context *ctx = NULL;
+       int librc = LIBISCSI_OK;
+       struct iscsi_session **ses = NULL;
+       uint32_t se_count = 0;
+       struct iscsi_session *se = NULL;
+       bool wait = true;
+
+       /* enable stdout logging */
+       log_init(program_name, 1024, log_do_log_std, NULL);
+
+       ctx = iscsi_context_new();
+       if (ctx == NULL) {
+               log_error("No memory");
+               goto out;
+       }
+
+       /* do not allow ctrl-c for now... */
+       memset(&sa_old, 0, sizeof(struct sigaction));
+       memset(&sa_new, 0, sizeof(struct sigaction));
+
+       sa_new.sa_handler = catch_sigint;
+       sigemptyset(&sa_new.sa_mask);
+       sa_new.sa_flags = 0;
+       sigaction(SIGINT, &sa_new, &sa_old );
+
+       umask(0077);
+
+       sysfs_init();
+
+       optopt = 0;
+       while ((ch = getopt_long(argc, argv, short_options,
+                                long_options, &longindex)) >= 0) {
+               switch (ch) {
+               case 'k':
+                       killiscsid = atoi(optarg);
+                       if (killiscsid < 0) {
+                               log_error("Invalid killiscsid priority %d "
+                                         "Priority must be greater than or "
+                                         "equal to zero.", killiscsid);
+                               rc = ISCSI_ERR_INVAL;
+                               goto out;
+                       }
+                       break;
+               case 't':
+                       type = str_to_type(optarg);
+                       break;
+               case 'o':
+                       op |= str_to_op(optarg);
+                       if (op == OP_NOOP) {
+                               log_error("can not recognize operation: '%s'",
+                                       optarg);
+                               rc = ISCSI_ERR_INVAL;
+                               goto out;
+                       }
+                       break;
+               case 'n':
+                       name = optarg;
+                       break;
+               case 'v':
+                       value = optarg;
+                       break;
+               case 'H':
+                       host_no = parse_host_info(optarg, &rc);
+                       if (rc)
+                               goto out;
+                       break;
+               case 'r':
+                       sid = iscsi_sysfs_get_sid_from_path(optarg);
+                       if (sid < 0) {
+                               log_error("invalid sid '%s'",
+                                         optarg);
+                               rc = ISCSI_ERR_INVAL;
+                               goto out;
+                       }
+                       break;
+               case 'R':
+                       do_rescan = 1;
+                       break;
+               case 'P':
+                       info_level = atoi(optarg);
+                       break;
+               case 'D':
+                       do_discover = 1;
+                       break;
+               case 'l':
+                       do_login = 1;
+                       break;
+               case 'u':
+                       do_logout = 1;
+                       break;
+               case 'U':
+                       do_logout_all = 1;
+                       group_session_mgmt_mode= optarg;
+                       break;
+               case 'L':
+                       do_login_all= 1;
+                       group_session_mgmt_mode= optarg;
+                       break;
+               case 's':
+                       do_stats = 1;
+                       break;
+               case 'S':
+                       do_show = 1;
+                       break;
+               case 'd':
+                       log_level = atoi(optarg);
+                       if (log_level >= 8)
+                               iscsi_context_log_priority_set
+                                       (ctx, LIBISCSI_LOG_PRIORITY_DEBUG);
+                       else if (log_level >= 4)
+                               iscsi_context_log_priority_set
+                                       (ctx, LIBISCSI_LOG_PRIORITY_INFO);
+                       else if (log_level >= 2)
+                               iscsi_context_log_priority_set
+                                       (ctx, LIBISCSI_LOG_PRIORITY_WARNING);
+                       else
+                               iscsi_context_log_priority_set
+                                       (ctx, LIBISCSI_LOG_PRIORITY_ERROR);
+                       break;
+               case 'm':
+                       mode = str_to_mode(optarg);
+                       rc = verify_mode_params(argc, argv, mode);
+                       if (ISCSI_SUCCESS != rc)
+                               goto out;
+                       break;
+               case 'C':
+                       sub_mode = str_to_submode(optarg);
+                       break;
+               case 'T':
+                       targetname = optarg;
+                       break;
+               case 'p':
+                       ip = str_to_ipport(optarg, &port, &tpgt);
+                       break;
+               case 'a':
+                       ip = optarg;
+                       break;
+               case 'b':
+                       packet_size = atoi(optarg);
+                       break;
+               case 'c':
+                       ping_count = atoi(optarg);
+                       break;
+               case 'i':
+                       ping_interval = atoi(optarg);
+                       break;
+               case 'I':
+                       iface = iface_alloc(optarg, &rc);
+                       if (rc == ISCSI_ERR_INVAL) {
+                               printf("Invalid iface name %s. Must be from "
+                                       "1 to %d characters.\n",
+                                       optarg, ISCSI_MAX_IFACE_LEN - 1);
+                               goto out;
+                       } else if (!iface || rc) {
+                               printf("Could not add iface %s.", optarg);
+                               rc = ISCSI_ERR_INVAL;
+                               goto out;
+                       }
+
+                       list_add_tail(&iface->list, &ifaces);
+                       num_ifaces++;
+                       break;
+               case 'V':
+                       printf("%s version %s\n", program_name,
+                               ISCSI_VERSION_STR);
+                       return 0;
+               case 'x':
+                       errno = 0;      // ensure errors from strtoull are real
+                       index = strtoull(optarg, NULL, 10);
+                       if (errno) {
+                               log_error("Invalid index %s. %s.",
+                                         optarg, strerror(errno));
+                               rc = ISCSI_ERR_INVAL;
+                               goto out;
+                       }
+                       break;
+               case 'A':
+                       portal_type = str_to_portal_type(optarg);
+                       break;
+               case 'W':
+                       wait = false;
+                       break;
+               case 'h':
+                       usage(0);
+               }
+
+               if (name && value) {
+                       param = idbm_alloc_user_param(name, value);
+                       if (!param) {
+                               log_error("Cannot allocate memory for params.");
+                               rc = ISCSI_ERR_NOMEM;
+                               goto out;
+                       }
+                       list_add_tail(&param->list, &params);
+                       name = NULL;
+                       value = NULL;
+               }
+       }
+
+       if (optopt) {
+               log_error("unrecognized character '%c'", optopt);
+               rc = ISCSI_ERR_INVAL;
+               goto out;
+       }
+
+       if (killiscsid >= 0) {
+               kill_iscsid(killiscsid, timeout);
+               goto out;
+       }
+
+       if (mode < 0)
+               usage(ISCSI_ERR_INVAL);
+
+       increase_max_files();
+       if (idbm_init(get_config_file)) {
+               log_warning("exiting due to idbm configuration error");
+               rc = ISCSI_ERR_IDBM;
+               goto out;
+       }
+
+       switch (mode) {
+       case MODE_FW:
+               rc = exec_fw_op(NULL, NULL, info_level, do_login, op, wait, &params);
+               break;
+       case MODE_HOST:
+               if (sub_mode != -1) {
+                       switch (sub_mode) {
+                       case MODE_CHAP:
+                               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,
+                                                      index, &params);
+                               break;
+                       case MODE_FLASHNODE:
+                               if (host_no > MAX_HOST_NO) {
+                                       log_error("FLASHNODE mode requires host no");
+                                       rc = ISCSI_ERR_INVAL;
+                                       break;
+                               }
+
+                               if (index == ULLONG_MAX)
+                                       index = (uint64_t)MAX_FLASHNODE_IDX + 1;
+
+                               rc = exec_flashnode_op(op, info_level, host_no,
+                                                      index, portal_type,
+                                                      &params);
+                               break;
+                       case MODE_HOST_STATS:
+                               if (host_no > MAX_HOST_NO) {
+                                       log_error("STATS mode requires host no");
+                                       rc = ISCSI_ERR_INVAL;
+                                       break;
+                               }
+
+                               rc = exec_host_stats_op(op, info_level,
+                                                       host_no);
+                               break;
+
+                       default:
+                               log_error("Invalid Sub Mode");
+                               break;
+                       }
+               } else {
+                       librc = iscsi_sessions_get(ctx, &ses, &se_count);
+
+                       if (librc != LIBISCSI_OK) {
+                               log_error("Failed to query iSCSI sessions, "
+                                         "error %d: %s", librc,
+                                         iscsi_strerror(librc));
+                               /* libopeniscsiusr rc is one-to-one map to iscsiadm
+                                * rc
+                                */
+                               rc = librc;
+                               goto out;
+                       }
+                       rc = host_info_print(info_level, host_no, ses,
+                                            se_count);
+               }
+               break;
+       case MODE_IFACE:
+               iscsi_default_iface_setup(ctx);
+
+               if (!list_empty(&ifaces)) {
+                       iface = list_entry(ifaces.next, struct iface_rec,
+                                          list);
+                       if (num_ifaces > 1)
+                               log_error("iface mode only accepts one "
+                                         "interface. Using the first one "
+                                         "%s.", iface->name);
+               }
+
+               if (sub_mode == MODE_PING)
+                       rc = exec_ping_op(iface, ip, packet_size, ping_count,
+                                         ping_interval);
+               else
+                       rc = exec_iface_op(ctx, op, do_show, info_level, iface,
+                                          host_no, &params);
+
+               break;
+       case MODE_DISCOVERYDB:
+               rc = exec_disc2_op(type, ip, port, &ifaces, info_level,
+                                  do_login, do_discover, op, &params,
+                                  do_show);
+               break;
+       case MODE_DISCOVERY:
+               rc = exec_disc_op(type, ip, port, &ifaces, info_level,
+                                 do_login, do_discover, op, &params,
+                                 do_show, wait);
+               break;
+       case MODE_NODE:
+               if (do_login_all) {
+                       rc = login_by_startup(group_session_mgmt_mode, wait);
+                       goto out;
+               }
+
+               if (do_logout_all) {
+                       rc = logout_by_startup(group_session_mgmt_mode);
+                       goto out;
+               }
+
+               if (!list_empty(&ifaces)) {
+                       iface = list_entry(ifaces.next, struct iface_rec,
+                                          list);
+                       if (num_ifaces > 1)
+                               log_error("NODE mode only accepts one "
+                                         "interface. Using the first one "
+                                         "driver %s hwaddress %s ipaddress "
+                                         "%s.", iface->transport_name,
+                                         iface->hwaddress, iface->ipaddress);
+               }
+
+               if (ip && port == -1)
+                       port = ISCSI_LISTEN_PORT;
+
+               rec = idbm_create_rec(targetname, tpgt, ip, port, iface, 1);
+               if (!rec) {
+                       rc = ISCSI_ERR_NOMEM;
+                       goto out;
+               }
+
+               rc = exec_node_op(ctx, op, do_login, do_logout, do_show,
+                                 do_rescan, do_stats, wait, info_level, rec,
+                                 &params);
+               break;
+       case MODE_SESSION:
+               if (sid >= 0) {
+                       char session[64];
+                       struct session_info *info;
+
+                       snprintf(session, 63, "session%d", sid);
+                       session[63] = '\0';
+
+                       info = calloc(1, sizeof(*info));
+                       if (!info) {
+                               rc = ISCSI_ERR_NOMEM;
+                               goto out;
+                       }
+                       info->iscsid_req_tmo = -1;
+
+                       rc = iscsi_sysfs_get_sessioninfo_by_id(info, session);
+                       if (rc) {
+                               log_error("Could not get session info for sid "
+                                         "%d", sid);
+                               goto free_info;
+                       }
+
+                       /*
+                        * We should be able to go on, but for now
+                        * we only support session mode ops if the module
+                        * is loaded and we support that module.
+                        */
+                       if (!iscsi_sysfs_get_transport_by_sid(sid))
+                               goto free_info;
+
+                       if (!do_logout && !do_rescan && !do_stats &&
+                           op == OP_NOOP && info_level > 0) {
+                               librc = iscsi_session_get
+                                       (ctx, sid & UINT32_MAX, &se);
+                               if (librc != LIBISCSI_OK) {
+                                       log_error("Failed to query iSCSI "
+                                                 "session %d, error %d: %s",
+                                                 sid, librc,
+                                                 iscsi_strerror(librc));
+                                       rc = ISCSI_ERR_INVAL;
+                                       goto out;
+                               }
+                               ses = (struct iscsi_session **)
+                                       calloc(1,
+                                              sizeof(struct iscsi_session *));
+                               ses[0] = se;
+                               se_count = 1;
+                               rc = session_info_print(info_level, ses,
+                                                       se_count, do_show);
+                               goto free_info;
+                       }
+
+                       rec = idbm_create_rec(info->targetname,
+                                             info->tpgt,
+                                             info->persistent_address,
+                                             info->persistent_port,
+                                             &info->iface, 1);
+                       if (!rec) {
+                               rc = ISCSI_ERR_NOMEM;
+                               goto free_info;
+                       }
+                       rec->session.info = info;
+                       rec->session.sid = sid;
+
+                       /*
+                        * A "new" session means to login a multiple of the
+                        * currently-detected session.
+                        */
+                       if (op == OP_NEW) {
+                               op = OP_NOOP;
+                               do_login = 1;
+                               rec->session.multiple = 1;
+                       }
+
+                       /* drop down to node ops */
+                       rc = exec_node_op(ctx, op, do_login, do_logout, do_show,
+                                         do_rescan, do_stats, wait, info_level,
+                                         rec, &params);
+free_info:
+                       free(info);
+                       goto out;
+               } else {
+                       if (op == OP_NEW) {
+                               log_error("session mode: Operation 'new' only "
+                                         "allowed with specific session IDs");
+                               rc = ISCSI_ERR_INVAL;
+                               goto out;
+                       }
+                       if (do_logout || do_rescan || do_stats) {
+                               rc = exec_node_op(ctx, op, do_login, do_logout,
+                                                do_show, do_rescan, do_stats,
+                                                wait, info_level, NULL, &params);
+                               goto out;
+                       }
+
+                       librc = iscsi_sessions_get(ctx, &ses, &se_count);
+
+                       if (librc != LIBISCSI_OK) {
+                               log_error("Failed to query iSCSI sessions, "
+                                         "error %d: %s", librc,
+                                         iscsi_strerror(librc));
+                               /* libopeniscsiusr rc is one-to-one map to iscsiadm
+                                * rc
+                                */
+                               rc = librc;
+                               goto out;
+                       }
+                       if (se_count == 0) {
+                               log_error("No active sessions.");
+                               rc =ISCSI_ERR_NO_OBJS_FOUND;
+                               goto out;
+                       }
+
+                       rc = session_info_print(info_level, ses, se_count,
+                                               do_show);
+
+               }
+               break;
+       default:
+               log_error("This mode is not yet supported");
+               /* fall through */
+       }
+
+out:
+       iscsi_context_free(ctx);
+       if (rec)
+               free(rec);
+       iscsi_sessions_free(ses, se_count);
+       idbm_terminate();
+       list_for_each_entry_safe(iface, tmp_iface, &ifaces, list) {
+               list_del(&iface->list);
+               free(iface);
+       }
+       list_for_each_entry_safe(param, tmp_param, &params, list) {
+               list_del(&param->list);
+               idbm_free_user_param(param);
+       }
+       free_transports();
+       sysfs_cleanup();
+       return rc;
+}
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/iscsid.c b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/iscsid.c
new file mode 100644 (file)
index 0000000..8441037
--- /dev/null
@@ -0,0 +1,656 @@
+/*
+ * iSCSI Initiator Daemon
+ *
+ * Copyright (C) 2004 Dmitry Yusupov, Alex Aizman
+ * Copyright (C) 2006 Mike Christie
+ * Copyright (C) 2006 Red Hat, Inc. All rights reserved.
+
+ * 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 <fcntl.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <signal.h>
+#include <grp.h>
+#include <sys/mman.h>
+#include <sys/utsname.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/prctl.h>
+#ifndef        NO_SYSTEMD
+#include <systemd/sd-daemon.h>
+#endif
+
+#include "iscsid.h"
+#include "mgmt_ipc.h"
+#include "event_poll.h"
+#include "iscsi_ipc.h"
+#include "log.h"
+#include "iscsi_util.h"
+#include "initiator.h"
+#include "transport.h"
+#include "idbm.h"
+#include "version.h"
+#include "iscsi_sysfs.h"
+#include "iface.h"
+#include "session_info.h"
+#include "sysdeps.h"
+#include "discoveryd.h"
+#include "iscsid_req.h"
+#include "iscsi_err.h"
+
+#ifndef PR_SET_IO_FLUSHER
+#define PR_SET_IO_FLUSHER 57
+#endif
+
+/* global config info */
+struct iscsi_daemon_config daemon_config;
+struct iscsi_daemon_config *dconfig = &daemon_config;
+
+static char program_name[] = "iscsid";
+static pid_t log_pid;
+static gid_t gid;
+static bool daemonize = true;
+static int mgmt_ipc_fd;
+static int sessions_to_recover = 0;
+
+static struct option const long_options[] = {
+       {"config", required_argument, NULL, 'c'},
+       {"initiatorname", required_argument, NULL, 'i'},
+       {"foreground", no_argument, NULL, 'f'},
+       {"debug", required_argument, NULL, 'd'},
+       {"uid", required_argument, NULL, 'u'},
+       {"gid", required_argument, NULL, 'g'},
+       {"no-pid-file", no_argument, NULL, 'n'},
+       {"pid", required_argument, NULL, 'p'},
+       {"help", no_argument, NULL, 'h'},
+       {"version", no_argument, NULL, 'v'},
+       {NULL, 0, NULL, 0},
+};
+
+static void usage(int status)
+{
+       if (status != 0)
+               fprintf(stderr, "Try `%s --help' for more information.\n",
+                       program_name);
+       else {
+               printf("Usage: %s [OPTION]\n", program_name);
+               printf("\
+Open-iSCSI initiator daemon.\n\
+  -c, --config=[path]     Execute using the config file (" CONFIG_FILE ").\n\
+  -i, --initiatorname=[path]     read initiatorname from file (" INITIATOR_NAME_FILE ").\n\
+  -f, --foreground        Make the program run in the foreground\n\
+  -d, --debug debuglevel  Print debugging information\n\
+  -u, --uid=uid           Run as uid, default is current user\n\
+  -g, --gid=gid           Run as gid, default is current user group\n\
+  -n, --no-pid-file       Do not use a pid file\n\
+  -p, --pid=pidfile       Use pid file (default " PID_FILE ").\n\
+  -h, --help              Display this help and exit\n\
+  -v, --version           Display version and exit\n\
+");
+       }
+       exit(status);
+}
+
+static void
+setup_rec_from_negotiated_values(node_rec_t *rec, struct session_info *info)
+{
+       struct iscsi_session_operational_config session_conf;
+       struct iscsi_conn_operational_config conn_conf;
+       struct iscsi_auth_config auth_conf;
+
+       idbm_node_setup_from_conf(rec);
+       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);
+       rec->tpgt = info->tpgt;
+
+       iscsi_sysfs_get_negotiated_session_conf(info->sid, &session_conf);
+       iscsi_sysfs_get_negotiated_conn_conf(info->sid, &conn_conf);
+       iscsi_sysfs_get_auth_conf(info->sid, &auth_conf);
+
+       if (strlen(auth_conf.username))
+               strcpy(rec->session.auth.username, auth_conf.username);
+
+       if (strlen(auth_conf.username_in))
+               strcpy(rec->session.auth.username_in, auth_conf.username_in);
+
+       if (strlen((char *)auth_conf.password)) {
+               strcpy((char *)rec->session.auth.password,
+                       (char *)auth_conf.password);
+               rec->session.auth.password_length = auth_conf.password_length;
+       }
+
+       if (strlen((char *)auth_conf.password_in)) {
+               strcpy((char *)rec->session.auth.password_in,
+                       (char *)auth_conf.password_in);
+               rec->session.auth.password_in_length =
+                                               auth_conf.password_in_length;
+       }
+
+       if (is_valid_operational_value(conn_conf.HeaderDigest)) {
+               if (conn_conf.HeaderDigest)
+                       rec->conn[0].iscsi.HeaderDigest =
+                                               CONFIG_DIGEST_PREFER_ON;
+               else
+                       rec->conn[0].iscsi.HeaderDigest =
+                                               CONFIG_DIGEST_PREFER_OFF;
+       }
+
+       if (is_valid_operational_value(conn_conf.DataDigest)) {
+               if (conn_conf.DataDigest)
+                       rec->conn[0].iscsi.DataDigest = CONFIG_DIGEST_PREFER_ON;
+               else
+                       rec->conn[0].iscsi.DataDigest =
+                                               CONFIG_DIGEST_PREFER_OFF;
+       }
+
+       if (is_valid_operational_value(conn_conf.MaxRecvDataSegmentLength))
+               rec->conn[0].iscsi.MaxRecvDataSegmentLength =
+                                       conn_conf.MaxRecvDataSegmentLength;
+
+       if (is_valid_operational_value(conn_conf.MaxXmitDataSegmentLength))
+                rec->conn[0].iscsi.MaxXmitDataSegmentLength =
+                                       conn_conf.MaxXmitDataSegmentLength;
+
+       if (is_valid_operational_value(session_conf.FirstBurstLength))
+               rec->session.iscsi.FirstBurstLength =
+                                       session_conf.FirstBurstLength;
+
+       if (is_valid_operational_value(session_conf.MaxBurstLength))
+               rec->session.iscsi.MaxBurstLength =
+                                       session_conf.MaxBurstLength;
+
+       if (is_valid_operational_value(session_conf.ImmediateData)) {
+               if (session_conf.ImmediateData)
+                       rec->session.iscsi.ImmediateData = 1;
+               else
+                       rec->session.iscsi.ImmediateData = 0;
+       }
+
+       if (is_valid_operational_value(session_conf.InitialR2T)) {
+               if (session_conf.InitialR2T)
+                       rec->session.iscsi.InitialR2T = 0;
+               else
+                       rec->session.iscsi.InitialR2T = 1;
+       }
+}
+
+static int sync_session(__attribute__((unused))void *data,
+                       struct session_info *info)
+{
+       node_rec_t rec, sysfsrec;
+       iscsiadm_req_t req;
+       iscsiadm_rsp_t rsp;
+       struct iscsi_transport *t;
+       int rc, retries = 0;
+
+       log_debug(7, "sync session [%d][%s,%s.%d][%s]", info->sid,
+                 info->targetname, info->persistent_address,
+                 info->port, info->iface.hwaddress);
+
+       t = iscsi_sysfs_get_transport_by_sid(info->sid);
+       if (!t)
+               return 0;
+
+       /*
+        * Just rescan the device in case this is the first startup.
+        * (TODO: should do this async and check for state).
+        */
+       if (t->caps & CAP_FW_DB) {
+               uint32_t host_no;
+               int err;
+
+               host_no = iscsi_sysfs_get_host_no_from_sid(info->sid, &err);
+               if (err) {
+                       log_error("Could not get host no from sid %u. Can not "
+                                 "sync session: %s", info->sid,
+                                 iscsi_err_to_str(err));
+                       return 0;
+               }
+               iscsi_sysfs_scan_host(host_no, 0, idbm_session_autoscan(NULL));
+               return 0;
+       }
+
+       if (!iscsi_sysfs_session_user_created(info->sid))
+               return 0;
+
+       memset(&rec, 0, sizeof(node_rec_t));
+       /*
+        * We might get the local ip address for software. We do not
+        * want to try and bind a session by ip though.
+        */
+       if (!t->template->set_host_ip)
+               memset(info->iface.ipaddress, 0, sizeof(info->iface.ipaddress));
+
+       if (idbm_rec_read(&rec, info->targetname, info->tpgt,
+                         info->persistent_address, info->persistent_port,
+                         &info->iface, false)) {
+               log_warning("Could not read data from db. Using default and "
+                           "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
+                * the values from them and sysfs to try and get
+                * the most uptodate values.
+                *
+                * Currenlty that means we will use the CHAP, target, portal
+                * and iface values from sysfs and use timer, queue depth,
+                * and segment length values from the record.
+                */
+               memset(&sysfsrec, 0, sizeof(node_rec_t));
+               setup_rec_from_negotiated_values(&sysfsrec, info);
+               /*
+                * target, portal and iface values have to be the same
+                * or we would not have found the record, so just copy
+                * CHAP settings.
+                */
+               memcpy(&rec.session.auth, &sysfsrec.session.auth,
+                     sizeof(struct iscsi_auth_config));
+       }
+
+       /* multiple drivers could be connected to the same portal */
+       if (!iscsi_match_session(&rec, info))
+               return -1;
+       /*
+        * We use the initiator name from sysfs because
+        * the session could have come from our db or ibft or some other
+        * app.
+        */
+       strcpy(rec.iface.iname, info->iface.iname);
+       memset(&req, 0, sizeof(req));
+       req.command = MGMT_IPC_SESSION_SYNC;
+       req.u.session.sid = info->sid;
+       memcpy(&req.u.session.rec, &rec, sizeof(node_rec_t));
+
+retry:
+       rc = iscsid_exec_req(&req, &rsp, 0, info->iscsid_req_tmo);
+       if (rc == ISCSI_ERR_ISCSID_NOTCONN && retries < 30) {
+               retries++;
+               sleep(1);
+               goto retry;
+       } else if (rc == ISCSI_ERR_SESS_EXISTS) {
+               log_debug(1, "sync session %d returned ISCSI_ERR_SESS_EXISTS", info->sid);
+       }
+
+       return 0;
+}
+
+static char *iscsid_get_config_file(void)
+{
+       return daemon_config.config_file;
+}
+
+static void iscsid_shutdown(void)
+{
+       pid_t pid;
+
+       killpg(gid, SIGTERM);
+       while ((pid = waitpid(0, NULL, 0) > 0))
+               log_debug(7, "cleaned up pid %d", pid);
+
+       log_info("iscsid shutting down.");
+       if (daemonize && log_pid >= 0) {
+               log_debug(1, "daemon stopping");
+               log_close(log_pid);
+       }
+}
+
+static void catch_signal(int signo)
+{
+       /*
+        * Do not try to call log_debug() if there is a PIPE error
+        * because we can get caught in a PIPE error loop.
+        */
+       if (signo != SIGPIPE)
+               log_debug(1, "pid %d caught signal %d", getpid(), signo);
+
+       /* In foreground mode, treat SIGINT like SIGTERM */
+       if (!daemonize && signo == SIGINT)
+               signo = SIGTERM;
+
+       switch (signo) {
+       case SIGTERM:
+               event_loop_exit(NULL);
+               break;
+       default:
+               break;
+       }
+}
+
+static void missing_iname_warn(char *initiatorname_file)
+{
+       log_error("Warning: InitiatorName file %s does not exist or does not "
+                 "contain a properly formatted InitiatorName. If using "
+                 "software iscsi (iscsi_tcp or ib_iser) or partial offload "
+                 "(bnx2i or cxgbi iscsi), you may not be able to log "
+                 "into or discover targets. Please create a file %s that "
+                 "contains a sting with the format: InitiatorName="
+                 "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.", initiatorname_file, initiatorname_file);
+}
+
+/* called right before we enter the event loop */
+static void set_state_to_ready(void)
+{
+#ifndef        NO_SYSTEMD
+       if (sessions_to_recover)
+               sd_notify(0, "READY=1\n"
+                               "RELOADING=1\n"
+                               "STATUS=Syncing existing session(s)\n");
+       else
+               sd_notify(0, "READY=1\n"
+                               "STATUS=Ready to process requests\n");
+#endif
+}
+
+/* called when recovery process has been reaped */
+static void set_state_done_reloading(void)
+{
+#ifndef        NO_SYSTEMD
+       sessions_to_recover = 0;
+       sd_notifyf(0, "READY=1\n"
+                       "STATUS=Ready to process requests\n");
+#endif
+}
+
+int main(int argc, char *argv[])
+{
+       struct utsname host_info; /* will use to compound initiator alias */
+       char *config_file = CONFIG_FILE;
+       char *initiatorname_file = INITIATOR_NAME_FILE;
+       char *pid_file = PID_FILE;
+       char *safe_logout;
+       char *ipc_auth_uid;
+       int ch, longindex;
+       uid_t uid = 0;
+       struct sigaction sa_old;
+       struct sigaction sa_new;
+       int control_fd;
+       pid_t pid;
+       bool pid_file_specified = false;
+       bool no_pid_file_specified = false;
+
+       while ((ch = getopt_long(argc, argv, "c:i:fd:nu:g:p:vh", long_options,
+                                &longindex)) >= 0) {
+               switch (ch) {
+               case 'c':
+                       config_file = optarg;
+                       break;
+               case 'i':
+                       initiatorname_file = optarg;
+                       break;
+               case 'f':
+                       daemonize = false;
+                       break;
+               case 'd':
+                       log_level = atoi(optarg);
+                       break;
+               case 'u':
+                       uid = strtoul(optarg, NULL, 10);
+                       break;
+               case 'g':
+                       gid = strtoul(optarg, NULL, 10);
+                       break;
+               case 'n':
+                       pid_file = NULL;
+                       no_pid_file_specified = true;
+                       break;
+               case 'p':
+                       pid_file = optarg;
+                       pid_file_specified = true;
+                       break;
+               case 'v':
+                       printf("%s version %s\n", program_name,
+                               ISCSI_VERSION_STR);
+                       exit(0);
+               case 'h':
+                       usage(0);
+                       break;
+               default:
+                       usage(1);
+                       break;
+               }
+       }
+
+       if (pid_file_specified) {
+               if (no_pid_file_specified) {
+                       fprintf(stderr, "error: Conflicting PID-file options requested\n");
+                       usage(1);
+               }
+               if (!daemonize) {
+                       fprintf(stderr, "error: PID file specified but unused in foreground mode\n");
+                       usage(1);
+               }
+       }
+
+       /* initialize logger */
+       log_pid = log_init(program_name, DEFAULT_AREA_SIZE,
+                     daemonize ? log_do_log_daemon : log_do_log_std, NULL);
+       if (log_pid < 0)
+               exit(ISCSI_ERR);
+
+       /* do not allow ctrl-c for now... */
+       sa_new.sa_handler = catch_signal;
+       sigemptyset(&sa_new.sa_mask);
+       sa_new.sa_flags = 0;
+       sigaction(SIGINT, &sa_new, &sa_old );
+       sigaction(SIGPIPE, &sa_new, &sa_old );
+       sigaction(SIGTERM, &sa_new, &sa_old );
+
+       sysfs_init();
+       if (idbm_init(iscsid_get_config_file)) {
+               log_close(log_pid);
+               exit(ISCSI_ERR);
+       }
+
+       umask(0077);
+
+       mgmt_ipc_fd = -1;
+       control_fd = -1;
+       daemon_config.initiator_name = NULL;
+       daemon_config.initiator_alias = NULL;
+
+       if ((mgmt_ipc_fd = mgmt_ipc_listen()) < 0) {
+               log_close(log_pid);
+               exit(ISCSI_ERR);
+       }
+
+       if (daemonize) {
+               char buf[64];
+               int fd = -1;
+
+               if (pid_file) {
+                       fd = open(pid_file, O_WRONLY|O_CREAT, 0644);
+                       if (fd < 0) {
+                               log_error("Unable to create pid file");
+                               log_close(log_pid);
+                               exit(ISCSI_ERR);
+                       }
+               }
+               pid = fork();
+               if (pid < 0) {
+                       log_error("Starting daemon failed");
+                       log_close(log_pid);
+                       exit(ISCSI_ERR);
+               } else if (pid) {
+                       log_info("iSCSI daemon with pid=%d started!", pid);
+                       exit(0);
+               }
+
+               if (chdir("/") < 0)
+                       log_debug(1, "Unable to chdir to /");
+               if (fd > 0) {
+                       if (lockf(fd, F_TLOCK, 0) < 0) {
+                               log_error("Unable to lock pid file");
+                               log_close(log_pid);
+                               exit(ISCSI_ERR);
+                       }
+                       if (ftruncate(fd, 0) < 0) {
+                               log_error("Unable to truncate pid file");
+                               log_close(log_pid);
+                               exit(ISCSI_ERR);
+                       }
+                       sprintf(buf, "%d\n", getpid());
+                       if (write(fd, buf, strlen(buf)) < 0) {
+                               log_error("Unable to write pid file");
+                               log_close(log_pid);
+                               exit(ISCSI_ERR);
+                       }
+               }
+               close(fd);
+
+               if ((control_fd = ipc->ctldev_open()) < 0) {
+                       log_close(log_pid);
+                       exit(ISCSI_ERR);
+               }
+
+               daemon_init();
+       } else {
+               if ((control_fd = ipc->ctldev_open()) < 0) {
+                       log_close(log_pid);
+                       exit(1);
+               }
+       }
+
+       if (gid && setgid(gid) < 0) {
+               log_error("Unable to setgid to %d", gid);
+               log_close(log_pid);
+               exit(ISCSI_ERR);
+       }
+
+       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;
+       daemon_config.config_file = config_file;
+       daemon_config.initiator_name = cfg_get_string_param(initiatorname_file,
+                                                           "InitiatorName");
+       if (daemon_config.initiator_name == NULL)
+               missing_iname_warn(initiatorname_file);
+
+       /* optional InitiatorAlias */
+       daemon_config.initiator_alias =
+                               cfg_get_string_param(initiatorname_file,
+                                                    "InitiatorAlias");
+       if (!daemon_config.initiator_alias) {
+               memset(&host_info, 0, sizeof (host_info));
+               if (uname(&host_info) >= 0) {
+                       daemon_config.initiator_alias =
+                               strdup(host_info.nodename);
+               }
+       }
+
+       log_debug(1, "InitiatorName=%s", daemon_config.initiator_name ?
+                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);
+
+       ipc_auth_uid = cfg_get_string_param(config_file, "iscsid.ipc_auth_uid");
+       if (ipc_auth_uid && !strcmp(ipc_auth_uid, "Yes"))
+               ipc->auth_type = ISCSI_IPC_AUTH_UID;
+       free(ipc_auth_uid);
+
+       /* see if we have any stale sessions to recover */
+       sessions_to_recover = iscsi_sysfs_count_sessions();
+       if (sessions_to_recover) {
+
+               /*
+                * recover stale sessions in the background
+                */
+
+               pid = fork();
+               if (pid == 0) {
+                       int nr_found; /* not used */
+                       /* child */
+                       /* 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"
+                                 " will not be synced", errno);
+               } else {
+                       /* parent */
+                       log_debug(8, "forked child (pid=%d) to recover %d session(s)",
+                                       (int)pid, sessions_to_recover);
+                       reap_track_reload_process(pid, set_state_done_reloading);
+               }
+       }
+
+       iscsi_initiator_init();
+       increase_max_files();
+       discoveryd_start(daemon_config.initiator_name);
+
+       /* oom-killer will not kill us at the night... */
+       if (oom_adjust())
+               log_debug(1, "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_error("failed to mlockall, exiting...");
+               log_close(log_pid);
+               exit(ISCSI_ERR);
+       }
+
+       if (prctl(PR_SET_IO_FLUSHER, 1, 0, 0, 0) == -1) {
+               if (errno == EINVAL) {
+                       log_info("prctl could not mark iscsid with the PR_SET_IO_FLUSHER flag, because the feature is not supported in this kernel. Will proceed, but iscsid may hang during session level recovery if memory is low.\n");
+               } else {
+                       log_error("prctl could not mark iscsid with the PR_SET_IO_FLUSHER flag due to error %s\n",
+                                 strerror(errno));
+               }
+       }
+
+       set_state_to_ready();
+       event_loop(ipc, control_fd, mgmt_ipc_fd);
+
+       idbm_terminate();
+       sysfs_cleanup();
+       ipc->ctldev_close();
+       mgmt_ipc_close(mgmt_ipc_fd);
+       if (daemon_config.initiator_name)
+               free(daemon_config.initiator_name);
+       if (daemon_config.initiator_alias)
+               free(daemon_config.initiator_alias);
+       free_initiator();
+       iscsid_shutdown();
+       return 0;
+}
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/iscsid.h b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/iscsid.h
new file mode 100644 (file)
index 0000000..b9f3d54
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * iSCSI Initiator Daemon
+ *
+ * Copyright (C) 2004 Dmitry Yusupov, Alex Aizman
+ * 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 ISCSID_H
+#define ISCSID_H
+
+/* IPC API */
+extern struct iscsi_ipc *ipc;
+
+/* iscsid.c: daemon config */
+struct iscsi_daemon_config {
+       char *config_file;
+       char *pid_file;
+       char *initiator_name;
+       char *initiator_alias;
+       int safe_logout;
+};
+extern struct iscsi_daemon_config *dconfig;
+
+#endif /* ISCSID_H */
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/iscsid_req.c b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/iscsid_req.c
new file mode 100644 (file)
index 0000000..fbcba41
--- /dev/null
@@ -0,0 +1,344 @@
+/*
+ * iscsid communication helpers
+ *
+ * Copyright (C) 2004 Dmitry Yusupov, Alex Aizman
+ * Copyright (C) 2006 - 2010 Mike Christie
+ * Copyright (C) 2006 - 2010 Red Hat, Inc. All rights reserved.
+ * maintained by open-iscsi@googlegroups.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * See the file COPYING included with this distribution for more details.
+ */
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/un.h>
+#include <poll.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include "initiator.h"
+#include "log.h"
+#include "mgmt_ipc.h"
+#include "iscsi_util.h"
+#include "config.h"
+#include "iscsi_err.h"
+#include "iscsid_req.h"
+#include "uip_mgmt_ipc.h"
+
+static void iscsid_startup(void)
+{
+       char *startup_cmd;
+
+       startup_cmd = cfg_get_string_param(CONFIG_FILE, "iscsid.startup");
+       if (!startup_cmd) {
+               log_error("iscsid is not running. Could not start it up "
+                         "automatically using the startup command in the "
+                         "iscsid.conf iscsid.startup setting. "
+                         "Please check that the file exists or that your "
+                         "init scripts have started iscsid.");
+               return;
+       }
+
+       if (system(startup_cmd) < 0)
+               log_error("Could not execute '%s' (err %d)",
+                         startup_cmd, errno);
+
+       free(startup_cmd);
+}
+
+#define MAXSLEEP 128
+
+static int ipc_connect(int *fd, char *unix_sock_name, int start_iscsid)
+{
+       int nsec, addr_len;
+       struct sockaddr_un addr;
+
+       *fd = socket(AF_LOCAL, SOCK_STREAM, 0);
+       if (*fd < 0) {
+               log_error("can not create IPC socket (%d)!", errno);
+               return ISCSI_ERR_ISCSID_NOTCONN;
+       }
+
+       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, addr_len) == 0)
+                       /* Connection established */
+                       return ISCSI_SUCCESS;
+
+               /* If iscsid isn't there, there's no sense
+                * in retrying. */
+               if (errno == ECONNREFUSED) {
+                       if (start_iscsid && nsec == 1)
+                               iscsid_startup();
+                       else
+                               break;
+               }
+
+               /*
+                * Delay before trying again
+                */
+               if (nsec <= MAXSLEEP/2)
+                       sleep(nsec);
+       }
+       close(*fd);
+       *fd = -1;
+       log_error("can not connect to iSCSI daemon (%d)!", errno);
+       return ISCSI_ERR_ISCSID_NOTCONN;
+}
+
+char iscsid_namespace[64] = ISCSIADM_NAMESPACE;
+
+void iscsid_set_namespace(pid_t pid) {
+       if (pid) {
+               snprintf(iscsid_namespace, 64, ISCSIADM_NAMESPACE "-%d", pid);
+       } else {
+               snprintf(iscsid_namespace, 64, ISCSIADM_NAMESPACE);
+       }
+}
+
+static int iscsid_connect(int *fd, int start_iscsid)
+{
+       return ipc_connect(fd, iscsid_namespace, start_iscsid);
+}
+
+int iscsid_request(int *fd, iscsiadm_req_t *req, int start_iscsid)
+{
+       int err;
+
+       err = iscsid_connect(fd, start_iscsid);
+       if (err)
+               return err;
+
+       if ((err = write(*fd, req, sizeof(*req))) != sizeof(*req)) {
+               log_error("got write error (%d/%d) on cmd %d, daemon died?",
+                       err, errno, req->command);
+               close(*fd);
+               return ISCSI_ERR_ISCSID_COMM_ERR;
+       }
+       return ISCSI_SUCCESS;
+}
+
+int iscsid_response(int fd, iscsiadm_cmd_e cmd, iscsiadm_rsp_t *rsp,
+                   int timeout)
+{
+       size_t len = sizeof(*rsp);
+       int iscsi_err = ISCSI_ERR_ISCSID_COMM_ERR;
+       int err;
+
+       while (len) {
+               struct pollfd pfd;
+
+               pfd.fd = fd;
+               pfd.events = POLLIN;
+               err = poll(&pfd, 1, timeout);
+               if (!err) {
+                       return ISCSI_ERR_REQ_TIMEDOUT;
+               } else if (err < 0) {
+                       if (errno == EINTR)
+                               continue;
+                       log_error("got poll error (%d/%d), daemon died?",
+                                 err, errno);
+                       return ISCSI_ERR_ISCSID_COMM_ERR;
+               } else if (pfd.revents & POLLIN) {
+                       err = recv(fd, rsp, sizeof(*rsp), MSG_WAITALL);
+                       if (err <= 0) {
+                               log_error("read error (%d/%d), daemon died?",
+                                         err, errno);
+                               break;
+                       }
+                       len -= err;
+                       iscsi_err = rsp->err;
+               }
+       }
+       close(fd);
+
+       if (!iscsi_err && cmd != rsp->command)
+               iscsi_err = ISCSI_ERR_ISCSID_COMM_ERR;
+       return iscsi_err;
+}
+
+int iscsid_exec_req(iscsiadm_req_t *req, iscsiadm_rsp_t *rsp,
+                   int start_iscsid, int tmo)
+{
+       int fd;
+       int err;
+
+       err = iscsid_request(&fd, req, start_iscsid);
+       if (err)
+               return err;
+
+       return iscsid_response(fd, req->command, rsp, tmo);
+}
+
+int iscsid_req_wait(iscsiadm_cmd_e cmd, int fd)
+{
+       iscsiadm_rsp_t rsp;
+
+       memset(&rsp, 0, sizeof(iscsiadm_rsp_t));
+       return iscsid_response(fd, cmd, &rsp, -1);
+}
+
+int iscsid_req_by_rec_async(iscsiadm_cmd_e cmd, node_rec_t *rec, int *fd)
+{
+       iscsiadm_req_t req;
+
+       memset(&req, 0, sizeof(iscsiadm_req_t));
+       req.command = cmd;
+       memcpy(&req.u.session.rec, rec, sizeof(node_rec_t));
+
+       return iscsid_request(fd, &req, 1);
+}
+
+int iscsid_req_by_rec(iscsiadm_cmd_e cmd, node_rec_t *rec)
+{
+       int err, fd;
+
+       err = iscsid_req_by_rec_async(cmd, rec, &fd);
+       if (err)
+               return err;
+       return iscsid_req_wait(cmd, fd);
+}
+
+int iscsid_req_by_sid_async(iscsiadm_cmd_e cmd, int sid, int *fd)
+{
+       iscsiadm_req_t req;
+
+       memset(&req, 0, sizeof(iscsiadm_req_t));
+       req.command = cmd;
+       req.u.session.sid = sid;
+
+       return iscsid_request(fd, &req, 1);
+}
+
+int iscsid_req_by_sid(iscsiadm_cmd_e cmd, int sid)
+{
+       int err, fd;
+
+       err = iscsid_req_by_sid_async(cmd, sid, &fd);
+       if (err)
+               return err;
+       return iscsid_req_wait(cmd, fd);
+}
+
+static int uip_connect(int *fd)
+{
+       return ipc_connect(fd, ISCSID_UIP_NAMESPACE, 0);
+}
+
+int uip_broadcast(void *buf, size_t buf_len, int fd_flags, uint32_t *status)
+{
+       int err;
+       int fd;
+       iscsid_uip_rsp_t rsp;
+       int flags;
+       int count;
+       size_t write_res;
+       
+       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 */
+       write_res = write(fd, buf, buf_len);
+       if (write_res != buf_len) {
+               log_error("got write error (%d/%d), daemon died?",
+                         (int)write_res, errno);
+               close(fd);
+               return ISCSI_ERR_ISCSID_COMM_ERR;
+       }
+
+       log_debug(3, "send iface config to uIP daemon");
+
+       /*  Set the socket to a non-blocking read, this way if there are
+        *  problems waiting for uIP, iscsid can bailout early */
+       flags = fcntl(fd, F_GETFL, 0);
+       if (flags == -1)
+               flags = 0;
+
+       if (fd_flags)
+               flags |= fd_flags;
+
+       err = fcntl(fd, F_SETFL, flags);
+       if (err) {
+               log_error("could not set uip broadcast to non-blocking: %d",
+                         errno);
+               close(fd);
+               return ISCSI_ERR;
+       }
+
+#define MAX_UIP_BROADCAST_READ_TRIES 5
+       for (count = 0; count < MAX_UIP_BROADCAST_READ_TRIES; count++) {
+               /*  Wait for the response */
+               err = read(fd, &rsp, sizeof(rsp));
+               if (err == sizeof(rsp)) {
+                       log_debug(3, "Broadcasted to uIP with length: %zu cmd: 0x%x rsp: 0x%x",
+                                 buf_len, rsp.command, rsp.err);
+                       err = 0;
+                       break;
+               } else if ((err == -1) && (errno == EAGAIN)) {
+                       usleep(1000000);
+                       continue;
+               } else {
+                       log_error("Could not read response (%d/%d), daemon "
+                                 "died?", err, errno);
+                       err = ISCSI_ERR;
+                       break;
+               }
+       }
+
+       if (count == MAX_UIP_BROADCAST_READ_TRIES) {
+               log_error("Could not broadcast to uIP after %d tries",
+                         count);
+               err = ISCSI_ERR_AGAIN;
+       }
+
+       if (err)
+               goto done;
+
+       switch (rsp.command) {
+       case ISCSID_UIP_IPC_GET_IFACE:
+               if (rsp.err != ISCSID_UIP_MGMT_IPC_DEVICE_UP) {
+                       log_debug(3, "Device is not ready\n");
+                       err = ISCSI_ERR_AGAIN;
+               }
+
+               break;
+       case ISCSID_UIP_IPC_PING:
+               *status = rsp.ping_sc;
+               if (rsp.err == ISCSID_UIP_MGMT_IPC_DEVICE_INITIALIZING) {
+                       log_debug(3, "Device is not ready\n");
+                       err = ISCSI_ERR_AGAIN;
+               } else if (*status) {
+                       err = ISCSI_ERR;
+               }
+
+               break;
+       default:
+               err = ISCSI_ERR;
+       }
+
+done:
+       close(fd);
+       return err;
+}
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/iscsid_req.h b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/iscsid_req.h
new file mode 100644 (file)
index 0000000..d580ed2
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * iscsid communication helpers
+ *
+ * Copyright (C) 2010 Mike Christie
+ * Copyright (C) 2010 Red Hat, Inc. All rights reserved.
+ * 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 ISCSID_REQ_H_
+#define ISCSID_REQ_H
+
+#define ISCSID_REQ_TIMEOUT 1000
+
+struct iscsiadm_req;
+struct iscsiadm_rsp;
+struct node_rec;
+
+extern char iscsid_namespace[64];
+extern void iscsid_set_namespace(pid_t);
+
+extern int iscsid_exec_req(struct iscsiadm_req *req, struct iscsiadm_rsp *rsp,
+                          int iscsid_start, int tmo);
+extern int iscsid_req_wait(iscsiadm_cmd_e cmd, int fd);
+extern int iscsid_req_by_rec_async(iscsiadm_cmd_e cmd, struct node_rec *rec,
+                                  int *fd);
+extern int iscsid_req_by_rec(iscsiadm_cmd_e cmd, struct node_rec *rec);
+extern int iscsid_req_by_sid_async(iscsiadm_cmd_e cmd, int sid, int *fd);
+extern int iscsid_req_by_sid(iscsiadm_cmd_e cmd, int sid);
+
+extern int uip_broadcast(void *buf, size_t buf_len, int fd_flags,
+                        uint32_t *status);
+
+#endif
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/iscsistart.c b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/iscsistart.c
new file mode 100644 (file)
index 0000000..546840f
--- /dev/null
@@ -0,0 +1,581 @@
+/*
+ * iSCSI Root Boot Program based on daemon code
+ *
+ * Copyright (C) 2004 Dmitry Yusupov, Alex Aizman
+ * Copyright (C) 2006 Mike Christie
+ * Copyright (C) 2006 Red Hat, Inc.  All rights reserved.
+ * 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 <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <signal.h>
+#include <time.h>
+#include <sys/mman.h>
+#include <sys/utsname.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include "initiator.h"
+#include "iscsi_ipc.h"
+#include "event_poll.h"
+#include "transport.h"
+#include "log.h"
+#include "iscsi_util.h"
+#include "idbm.h"
+#include "idbm_fields.h"
+#include "version.h"
+#include "iscsi_sysfs.h"
+#include "iscsi_settings.h"
+#include "fw_context.h"
+#include "iface.h"
+#include "sysdeps.h"
+#include "iscsid_req.h"
+#include "iscsi_err.h"
+#include "iface.h"
+
+/* global config info */
+/* initiator needs initiator name/alias */
+struct iscsi_daemon_config daemon_config;
+struct iscsi_daemon_config *dconfig = &daemon_config;
+
+static node_rec_t config_rec;
+static LIST_HEAD(targets);
+static LIST_HEAD(user_params);
+
+static char program_name[] = "iscsistart";
+static char config_file[TARGET_NAME_MAXLEN];
+
+/* used by initiator */
+extern struct iscsi_ipc *ipc;
+
+static struct option const long_options[] = {
+       {"config", required_argument, NULL, 'c'},
+       {"initiatorname", required_argument, NULL, 'i'},
+       {"targetname", required_argument, NULL, 't'},
+       {"tgpt", required_argument, NULL, 'g'},
+       {"address", required_argument, NULL, 'a'},
+       {"port", required_argument, NULL, 'p'},
+       {"username", required_argument, NULL, 'u'},
+       {"password", required_argument, NULL, 'w'},
+       {"username_in", required_argument, NULL, 'U'},
+       {"password_in", required_argument, NULL, 'W'},
+       {"debug", required_argument, NULL, 'd'},
+       {"fwparam_connect", no_argument, NULL, 'b'},
+       {"fwparam_network", no_argument, NULL, 'N'},
+       {"fwparam_print", no_argument, NULL, 'f'},
+       {"param", required_argument, NULL, 'P'},
+       {"help", no_argument, NULL, 'h'},
+       {"version", no_argument, NULL, 'v'},
+       {NULL, 0, NULL, 0},
+};
+
+static void usage(int status)
+{
+       if (status != 0)
+               fprintf(stderr, "Try `%s --help' for more information.\n",
+                       program_name);
+       else {
+               printf("Usage: %s [OPTION]\n", program_name);
+               printf("\
+Open-iSCSI initiator.\n\
+  -c, --config=[path]      set config file (default " CONFIG_FILE ").\n\
+  -i, --initiatorname=name set InitiatorName to name (Required)\n\
+  -t, --targetname=name    set TargetName to name (Required)\n\
+  -g, --tgpt=N             set target portal group tag to N (Required)\n\
+  -a, --address=A.B.C.D    set IP address to A.B.C.D (Required)\n\
+  -p, --port=N             set port to N (Default 3260)\n\
+  -u, --username=N         set username to N (optional)\n\
+  -w, --password=N         set password to N (optional\n\
+  -U, --username_in=N      set incoming username to N (optional)\n\
+  -W, --password_in=N      set incoming password to N (optional)\n\
+  -d, --debug=debuglevel   print debugging information \n\
+  -b, --fwparam_connect    create a session to the target using iBFT or OF\n\
+  -N, --fwparam_network    bring up the network as specified by iBFT or OF\n\
+  -f, --fwparam_print      print the iBFT or OF info to STDOUT \n\
+  -P, --param=NAME=VALUE   set parameter with the name NAME to VALUE\n\
+  -h, --help               display this help and exit\n\
+  -v, --version            display version and exit\n\
+");
+       }
+       exit(status);
+}
+
+static int stop_event_loop(void)
+{
+       iscsiadm_req_t req;
+       iscsiadm_rsp_t rsp;
+       int rc;
+
+       memset(&req, 0, sizeof(req));
+       req.command = MGMT_IPC_IMMEDIATE_STOP;
+       rc = iscsid_exec_req(&req, &rsp, 0, -1);
+       if (rc) {
+               iscsi_err_print_msg(rc);
+               log_error("Could not stop event_loop");
+       }
+       return rc;
+}
+
+static int apply_params(struct node_rec *rec)
+{
+       struct user_param *param;
+       int rc;
+
+       /* Must init this so we can check if user overrode them */
+       rec->session.initial_login_retry_max = -1;
+       rec->conn[0].timeo.noop_out_interval = -1;
+       rec->conn[0].timeo.noop_out_timeout = -1;
+       rec->session.scan = -1;
+
+       list_for_each_entry(param, &user_params, list) {
+               /*
+                * user may not have passed in all params that were set by
+                * ibft/iscsi_boot, so clear out values that might conflict
+                * with user overrides
+                */
+               if (!strcmp(param->name, IFACE_NETNAME)) {
+                       /* overriding netname so MAC will be for old netdev */
+                       memset(rec->iface.hwaddress, 0,
+                               sizeof(rec->iface.hwaddress));
+               } else if (!strcmp(param->name, IFACE_HWADDR)) {
+                       /* overriding MAC so netdev will be for old MAC */
+                       memset(rec->iface.netdev, 0, sizeof(rec->iface.netdev));
+               } else if (!strcmp(param->name, IFACE_TRANSPORTNAME)) {
+                       /*
+                        * switching drivers so all old binding info is no
+                        * longer valid. Old values were either for offload
+                        * and we are switching to software or the reverse,
+                        * or switching types of cards (bnx2i to cxgb3i).
+                        */
+                       memset(&rec->iface, 0, sizeof(rec->iface));
+                       iface_setup_defaults(&rec->iface);
+               }
+       }
+
+       rc = idbm_node_set_rec_from_param(&user_params, rec, 0);
+       if (rc)
+               return rc;
+
+       /*
+        * For root boot we could not change this in older versions so
+        * if user did not override then use the defaults.
+        *
+        * Increase to account for boot using static setup.
+        */
+       if (rec->session.initial_login_retry_max == -1)
+               rec->session.initial_login_retry_max = 30;
+       /* we used to not be able to answer so turn off */
+       if (rec->conn[0].timeo.noop_out_interval == -1)
+               rec->conn[0].timeo.noop_out_interval = 0;
+       if (rec->conn[0].timeo.noop_out_timeout == -1)
+               rec->conn[0].timeo.noop_out_timeout = 0;
+       if (rec->session.scan == -1)
+               rec->session.scan = DEF_INITIAL_SCAN;
+
+       return 0;
+}
+
+static int parse_param(char *param_str)
+{
+       struct user_param *param;
+       char *name, *value;
+
+       name = param_str;
+
+       value = strchr(param_str, '=');
+       if (!value) {
+               log_error("Invalid --param %s. Missing value.", param_str);
+               return ISCSI_ERR_INVAL;
+       }
+       *value = '\0';
+
+       value++;
+       if (!strlen(value)) {
+               log_error("Invalid --param %s. Missing value.", param_str);
+               return ISCSI_ERR_INVAL;
+       }
+
+       param = idbm_alloc_user_param(name, value);
+       if (!param) {
+               log_error("Could not allocate memory for param.");
+               return ISCSI_ERR_NOMEM;
+       }
+
+       list_add(&param->list, &user_params);
+       return 0;
+}
+
+static int login_session(struct node_rec *rec)
+{
+       iscsiadm_req_t req;
+       iscsiadm_rsp_t rsp;
+       int rc, msec, err;
+       struct timespec ts;
+
+       rc = apply_params(rec);
+       if (rc)
+               return rc;
+
+       printf("%s: Logging into %s %s:%d,%d\n", program_name, rec->name,
+               rec->conn[0].address, rec->conn[0].port,
+               rec->tpgt);
+       memset(&req, 0, sizeof(req));
+       req.command = MGMT_IPC_SESSION_LOGIN;
+       memcpy(&req.u.session.rec, rec, sizeof(*rec));
+
+       /*
+        * Need to handle race where iscsid proc is starting up while we are
+        * trying to connect. Retry with exponential backoff, start from 50 ms.
+        */
+       for (msec = 50; msec <= 15000; msec <<= 1) {
+               /*
+                * Once our event loop is up then we want to wait for the login
+                * response. Either it logs in, we hit the login retries count,
+                * or this program crashes, so there no need for the response
+                * timeout.
+                */
+               rc = iscsid_exec_req(&req, &rsp, 0, -1);
+               if (rc == 0) {
+                       return rc;
+               } else if (rc == ISCSI_ERR_ISCSID_NOTCONN) {
+                       ts.tv_sec = msec / 1000;
+                       ts.tv_nsec = (msec % 1000) * 1000000L;
+
+                       /* On EINTR, retry nanosleep with remaining time. */
+                       while ((err = nanosleep(&ts, &ts)) < 0 &&
+                              errno == EINTR);
+                       if (err < 0)
+                               break;
+               } else {
+                       break;
+               }
+       }
+
+       iscsi_err_print_msg(rc);
+       return rc;
+}
+
+static char *get_config_file(void)
+{
+       return config_file;
+}
+
+static int setup_session(void)
+{
+       struct boot_context *context;
+       int rc = 0, rc2 = 0;
+
+       if (list_empty(&targets))
+               return login_session(&config_rec);
+
+       increase_max_files();
+       if (idbm_init(get_config_file)) {
+               log_warning("exiting due to idbm configuration error");
+               rc = ISCSI_ERR_IDBM;
+               goto out;
+       }
+
+       list_for_each_entry(context, &targets, list) {
+               struct node_rec *rec;
+
+               rec = idbm_create_rec_from_boot_context(context);
+               if (!rec) {
+                       log_error("Could not allocate memory. Could "
+                                 "not start boot session to "
+                                 "%s,%s,%d", context->targetname,
+                                 context->target_ipaddr,
+                                 context->target_port);
+                       continue;
+               }
+
+               rc2 = login_session(rec);
+               if (rc2)
+                       rc = rc2;
+               free(rec);
+       }
+       fw_free_targets(&targets);
+out:
+       return rc;
+}
+
+int session_in_use(__attribute__((unused))int sid)
+{
+       return 0;
+}
+
+static void catch_signal(int signo)
+{
+       log_warning("pid %d caught signal -%d", getpid(), signo);
+}
+
+static int check_params(char *initiatorname)
+{
+       if (!initiatorname) {
+               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", program_name);
+               return EINVAL;
+       }
+
+       if (!strlen(config_rec.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", program_name);
+               return EINVAL;
+       }
+
+       return 0;
+}
+
+#define check_str_param_len(str, max_len, param)                       \
+do {                                                                   \
+       if (strlen(str) > max_len) {                                    \
+               printf("%s: invalid %s %s. Max %s length is %d.\n",     \
+                       program_name, param, str, param, max_len);      \
+               exit(ISCSI_ERR_INVAL);                                  \
+       }                                                               \
+} while (0);
+
+int main(int argc, char *argv[])
+{
+       struct utsname host_info; /* will use to compound initiator alias */
+       struct iscsi_auth_config *auth;
+       char *initiatorname = NULL;
+       int ch, longindex, ret;
+       struct boot_context *context, boot_context;
+       struct sigaction sa_old;
+       struct sigaction sa_new;
+       struct user_param *param, *tmp_param;
+       int control_fd, mgmt_ipc_fd, err;
+       pid_t pid;
+
+       strcpy(config_file, CONFIG_FILE);
+       idbm_node_setup_defaults(&config_rec);
+       config_rec.name[0] = '\0';
+       config_rec.conn[0].address[0] = '\0';
+       auth = &config_rec.session.auth;
+
+       /* do not allow ctrl-c for now... */
+       sa_new.sa_handler = catch_signal;
+       sigemptyset(&sa_new.sa_mask);
+       sa_new.sa_flags = 0;
+       sigaction(SIGINT, &sa_new, &sa_old );
+
+       /* initialize logger */
+       log_init(program_name, DEFAULT_AREA_SIZE, log_do_log_std, NULL);
+
+       sysfs_init();
+
+       while ((ch = getopt_long(argc, argv, "c:P:i:t:g:a:p:d:u:w:U:W:bNfvh",
+                                long_options, &longindex)) >= 0) {
+               switch (ch) {
+               case 'c':
+                       strncpy(config_file, optarg, TARGET_NAME_MAXLEN);
+                       config_file[TARGET_NAME_MAXLEN-1] = 0;
+                       break;
+               case 'i':
+                       initiatorname = optarg;
+                       break;
+               case 't':
+                       check_str_param_len(optarg, TARGET_NAME_MAXLEN,
+                                           "targetname");
+                       strlcpy(config_rec.name, optarg, TARGET_NAME_MAXLEN);
+                       break;
+               case 'g':
+                       config_rec.tpgt = atoi(optarg);
+                       break;
+               case 'a':
+                       check_str_param_len(optarg, NI_MAXHOST, "address");
+                       strlcpy(config_rec.conn[0].address, optarg, NI_MAXHOST);
+                       break;
+               case 'p':
+                       config_rec.conn[0].port = atoi(optarg);
+                       break;
+               case 'w':
+                       check_str_param_len(optarg, AUTH_STR_MAX_LEN,
+                                          "password");
+                       strlcpy((char *)auth->password, optarg,
+                               AUTH_STR_MAX_LEN);
+                       auth->password_length = strlen((char *)auth->password);
+                       break;
+               case 'W':
+                       check_str_param_len(optarg, AUTH_STR_MAX_LEN,
+                                          "password_in");
+                       strlcpy((char *)auth->password_in, optarg,
+                               AUTH_STR_MAX_LEN);
+                       auth->password_in_length =
+                               strlen((char *)auth->password_in);
+                       break;
+               case 'u':
+                       check_str_param_len(optarg, AUTH_STR_MAX_LEN,
+                                           "username");
+                       strlcpy(auth->username, optarg, AUTH_STR_MAX_LEN);
+                       break;
+               case 'U':
+                       check_str_param_len(optarg, AUTH_STR_MAX_LEN,
+                                           "username_in");
+                       strlcpy(auth->username_in, optarg, AUTH_STR_MAX_LEN);
+                       break;
+               case 'd':
+                       log_level = atoi(optarg);
+                       break;
+               case 'b':
+                       memset(&boot_context, 0, sizeof(boot_context));
+                       ret = fw_get_entry(&boot_context);
+                       if (ret) {
+                               printf("Could not get boot entry.\n");
+                               exit(ret);
+                       }
+
+                       initiatorname = boot_context.initiatorname;
+                       ret = fw_get_targets(&targets);
+                       if (ret || list_empty(&targets)) {
+                               printf("Could not setup fw entries.\n");
+                               exit(ret);
+                       }
+                       break;
+               case 'N':
+                       exit(fw_setup_nics());
+               case 'f':
+                       ret = fw_get_targets(&targets);
+                       if (ret || list_empty(&targets)) {
+                               printf("Could not get list of targets from "
+                                      "firmware.\n");
+                               exit(ret);
+                       }
+
+                       list_for_each_entry(context, &targets, list)
+                               fw_print_entry(context);
+
+                       fw_free_targets(&targets);
+                       exit(0);
+               case 'P':
+                       err = parse_param(optarg);
+                       if (err)
+                               exit(err);
+                       break;
+               case 'v':
+                       printf("%s version %s\n", program_name,
+                               ISCSI_VERSION_STR);
+                       exit(0);
+               case 'h':
+                       usage(0);
+                       break;
+               default:
+                       usage(ISCSI_ERR_INVAL);
+                       break;
+               }
+       }
+
+       if (list_empty(&targets) && check_params(initiatorname))
+               exit(ISCSI_ERR_INVAL);
+
+       pid = fork();
+       if (pid < 0) {
+               log_error("iscsiboot fork failed");
+               exit(ISCSI_ERR_NOMEM);
+       } else if (pid) {
+               int status, rc, rc2;
+
+               /* make a special socket path for only this iscsistart instance */
+               iscsid_set_namespace(pid);
+               sleep(1);
+
+               rc = setup_session();
+               rc2 = stop_event_loop();
+               /*
+                * something horrible happened. kill child and get
+                * out of here
+                */
+               if (rc2)
+                       kill(pid, SIGTERM);
+
+               waitpid(pid, &status, WUNTRACED);
+               if (rc || rc2)
+                       exit(ISCSI_ERR);
+
+               log_debug(1, "iscsi parent done");
+               exit(0);
+       }
+
+       pid = getpid();
+       iscsid_set_namespace(pid);
+
+       mgmt_ipc_fd = mgmt_ipc_listen();
+       if (mgmt_ipc_fd  < 0) {
+               log_error("Could not setup mgmt ipc");
+               exit(ISCSI_ERR_NOMEM);
+       }
+
+       control_fd = ipc->ctldev_open();
+       if (control_fd < 0)
+               exit(ISCSI_ERR_NOMEM);
+
+       memset(&daemon_config, 0, sizeof (daemon_config));
+       daemon_config.initiator_name = initiatorname;
+       /* optional InitiatorAlias */
+       memset(&host_info, 0, sizeof (host_info));
+       if (uname(&host_info) >= 0)
+               daemon_config.initiator_alias = host_info.nodename;
+
+       log_debug(1, "InitiatorName=%s", daemon_config.initiator_name);
+       log_debug(1, "InitiatorAlias=%s", daemon_config.initiator_alias);
+       log_debug(1, "TargetName=%s", config_rec.name);
+       log_debug(1, "TPGT=%d", config_rec.tpgt);
+       log_debug(1, "IP Address=%s", config_rec.conn[0].address);
+
+       ipc->auth_type = ISCSI_IPC_AUTH_UID;
+
+       /* log the version, so that we can tell if the daemon and kernel module
+        * match based on what shows up in the syslog.  Tarballs releases
+        * always install both, but Linux distributors may put the kernel module
+        * in a different RPM from the daemon and utils, and users may try to
+        * mix and match in ways that don't work.
+        */
+       log_error("version %s", ISCSI_VERSION_STR);
+
+       /* oom-killer will not kill us at the night... */
+       if (oom_adjust())
+               log_debug(1, "can not adjust oom-killer's pardon");
+
+       /*
+        * Start Main Event Loop
+        */
+       iscsi_initiator_init();
+       event_loop(ipc, control_fd, mgmt_ipc_fd);
+       ipc->ctldev_close();
+       mgmt_ipc_close(mgmt_ipc_fd);
+       free_initiator();
+       sysfs_cleanup();
+       list_for_each_entry_safe(param, tmp_param, &user_params, list) {
+               list_del(&param->list);
+               idbm_free_user_param(param);
+       }
+
+       log_debug(1, "iscsi child done");
+       return 0;
+}
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/iser.c b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/iser.c
new file mode 100644 (file)
index 0000000..30459bb
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * iser helpers
+ *
+ * Copyright (C) 2012 Red Hat, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+#include "initiator.h"
+
+void iser_create_conn(struct iscsi_conn *conn)
+{
+       /* header digests not supported in iser */
+       conn->hdrdgst_en = ISCSI_DIGEST_NONE;
+}
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/iser.h b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/iser.h
new file mode 100644 (file)
index 0000000..e805cae
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef ISER_TRANSPORT
+#define ISER_TRANSPORT
+
+struct iscsi_conn;
+
+extern void iser_create_conn(struct iscsi_conn *conn);
+
+#endif
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/kern_err_table.c b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/kern_err_table.c
new file mode 100644 (file)
index 0000000..8af6f05
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2011 Aastha Mehta
+ * Copyright (C) 2011 Mike Christie
+ *
+ * maintained by open-iscsi@googlegroups.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * See the file COPYING included with this distribution for more details.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "iscsi_if.h"
+
+#include "kern_err_table.h"
+
+const char *kern_err_code_to_string(int err)
+{
+       switch (err){
+       case ISCSI_OK:
+               return "ISCSI_OK: operation successful";
+       case ISCSI_ERR_DATASN:
+               return "ISCSI_ERR_DATASN: Received invalid data sequence "
+                       "number from target";
+       case ISCSI_ERR_DATA_OFFSET:
+               return "ISCSI_ERR_DATA_OFFSET: Seeking offset beyond the size "
+                       "of the iSCSI segment";
+       case ISCSI_ERR_MAX_CMDSN:
+               return "ISCSI_ERR_MAX_CMDSN: Received invalid command sequence "
+                       "number from target";
+       case ISCSI_ERR_EXP_CMDSN:
+               return "ISCSI_ERR_EXP_CMDSN: Received invalid expected command "                        "sequence number from target";
+       case ISCSI_ERR_BAD_OPCODE:
+               return "ISCSI_ERR_BAD_OPCODE: Received an invalid iSCSI opcode";
+       case ISCSI_ERR_DATALEN:
+               return "ISCSI_ERR_DATALEN: Invalid data length value";
+       case ISCSI_ERR_AHSLEN:
+               return "ISCSI_ERR_AHSLEN: Received an invalid AHS length";
+       case ISCSI_ERR_PROTO:
+               return "ISCSI_ERR_PROTO: iSCSI protocol violation";
+       case ISCSI_ERR_LUN:
+               return "ISCSI_ERR_LUN: LUN mismatch";
+       case ISCSI_ERR_BAD_ITT:
+               return "ISCSI_ERR_BAD_ITT: Received invalid initiator task tag "                        "from target";
+       case ISCSI_ERR_CONN_FAILED:
+               return "ISCSI_ERR_CONN_FAILED: iSCSI connection failed";
+       case ISCSI_ERR_R2TSN:
+               return "ISCSI_ERR_R2TSN: Received invalid R2T (Ready to "
+                       "Transfer) data sequence number from target";
+       case ISCSI_ERR_SESSION_FAILED:
+               return "ISCSI_ERR_SESSION_FAILED: iSCSI session failed";
+       case ISCSI_ERR_HDR_DGST:
+               return "ISCSI_ERR_HDR_DGST: Header digest mismatch";
+       case ISCSI_ERR_DATA_DGST:
+               return "ISCSI_ERR_DATA_DGST: Data digest mismatch";
+       case ISCSI_ERR_PARAM_NOT_FOUND:
+               return "ISCSI_ERR_PARAM_NOT_FOUND: Parameter not found";
+       case ISCSI_ERR_NO_SCSI_CMD:
+               return "ISCSI_ERR_NO_SCSI_CMD: Could not look up SCSI command";
+       case ISCSI_ERR_INVALID_HOST:
+               return "ISCSI_ERR_INVALID_HOST: iSCSI host is in an invalid "
+                       "state";
+       case ISCSI_ERR_XMIT_FAILED:
+               return "ISCSI_ERR_XMIT_FAILED: Transmission of iSCSI packet "
+                       "failed";
+       case ISCSI_ERR_TCP_CONN_CLOSE:
+               return "ISCSI_ERR_TCP_CONN_CLOSE: TCP connection closed";
+       case ISCSI_ERR_SCSI_EH_SESSION_RST:
+               return "ISCSI_ERR_SCSI_EH_SESSION_RST: Session was dropped as "
+                       "a result of SCSI error recovery";
+       case ISCSI_ERR_NOP_TIMEDOUT:
+               return "ISCSI_ERR_NOP_TIMEDOUT: A NOP has timed out";
+       default:
+               return "Invalid or unknown error code";
+       }
+}
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/kern_err_table.h b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/kern_err_table.h
new file mode 100644 (file)
index 0000000..592e40d
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2011 Aastha Mehta
+ * Copyright (C) 2011 Mike Christie
+ *
+ * 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 __KERN_ERR_TABLE_H__
+#define __KERN_ERR_TABLE_H__
+
+extern const char *kern_err_code_to_string(int);
+#endif
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/local_strings.c b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/local_strings.c
new file mode 100644 (file)
index 0000000..2a40c2a
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2002 Cisco Systems, Inc.
+ * maintained by linux-iscsi-devel@lists.sourceforge.net
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * See the file COPYING included with this distribution for more details.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/param.h>
+
+#include "local_strings.h"
+#include "log.h"
+
+int str_init_buffer(struct str_buffer *s, size_t initial_allocation)
+{
+       if (s) {
+               memset(s, 0, sizeof (*s));
+               s->buffer = NULL;
+               if (initial_allocation) {
+                       s->buffer = malloc(initial_allocation);
+                       if (s->buffer) {
+                               s->allocated_length = initial_allocation;
+                               memset(s->buffer, 0, initial_allocation);
+                       }
+               }
+               s->data_length = 0;
+               return 1;
+       }
+
+       return 0;
+}
+
+struct str_buffer *str_alloc_buffer(size_t initial_allocation)
+{
+       struct str_buffer *s = calloc(1, sizeof (*s));
+
+       if (s)
+               str_init_buffer(s, initial_allocation);
+
+       return s;
+}
+
+void str_free_buffer(struct str_buffer *s)
+{
+       if (s) {
+               if (s->buffer) {
+                       free(s->buffer);
+                       s->buffer = NULL;
+               }
+               s->allocated_length = 0;
+               s->data_length = 0;
+       }
+}
+
+int str_enlarge_data(struct str_buffer *s, int length)
+{
+       void *new_buf;
+
+       if (s) {
+               s->data_length += length;
+               if (s->data_length > s->allocated_length) {
+                       log_debug(7, "enlarge buffer from %zu to %zu",
+                                 s->allocated_length, s->data_length);
+                       new_buf = realloc(s->buffer, s->data_length);
+                       if (!new_buf) {
+                               /* too big */
+                               log_error("enlarged buffer %p to %d data "
+                                         "bytes, with only %d bytes of buffer "
+                                         "space", s, (int)s->data_length,
+                                          (int)s->allocated_length);
+                               return ENOMEM;
+                       }
+                       s->buffer = new_buf;
+                       memset(s->buffer + s->allocated_length, 0,
+                              s->data_length - s->allocated_length);
+                       s->allocated_length = s->data_length;
+               }
+       }
+
+       return 0;
+}
+
+void str_remove_initial(struct str_buffer *s, int length)
+{
+       char *remaining;
+       int amount;
+
+       if (s && length) {
+               remaining = s->buffer + length;
+               amount = s->data_length - length;
+
+               if (amount < 0)
+                       amount = 0;
+               if (amount)
+                       memmove(s->buffer, remaining, amount);
+               s->data_length = amount;
+               s->buffer[amount] = '\0';
+       }
+}
+
+/* truncate the data length down */
+void str_truncate_buffer(struct str_buffer *s, size_t length)
+{
+       if (s) {
+               if (!s->data_length)
+                       return;
+               if (length <= s->data_length) {
+                       s->data_length = length;
+                       s->buffer[s->data_length] = '\0';
+               } else if (length <= s->allocated_length) {
+                       /* clear the data, and declare the
+                        * data length to be larger
+                        */
+                       memset(s->buffer + s->data_length, 0,
+                              length - s->data_length);
+                       s->data_length = length;
+               } else {
+                       log_error(
+                              "couldn't truncate data buffer to length %d, "
+                              "only allocated %d",
+                              (int)length, (int)s->allocated_length);
+               }
+       }
+}
+
+char *str_buffer_data(struct str_buffer *s)
+{
+       if (s)
+               return s->buffer;
+       else
+               return NULL;
+}
+
+size_t str_data_length(struct str_buffer * s)
+{
+       if (s)
+               return s->data_length;
+       else
+               return 0;
+}
+
+size_t str_unused_length(struct str_buffer * s)
+{
+       if (s)
+               return s->allocated_length - s->data_length;
+       else
+               return 0;
+}
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/local_strings.h b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/local_strings.h
new file mode 100644 (file)
index 0000000..22d21e4
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * iSCSI variable-sized string buffers
+ *
+ * Copyright (C) 2002 Cisco Systems, Inc.
+ * maintained by linux-iscsi-devel@lists.sourceforge.net
+ *
+ * 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 STRINGS_H
+#define STRINGS_H
+
+struct str_buffer {
+       size_t allocated_length;
+       size_t data_length;     /* not including the trailing NUL */
+       char *buffer;
+};
+
+extern int str_init_buffer(struct str_buffer *s, size_t initial_allocation);
+extern struct str_buffer *str_alloc_buffer(size_t initial_allocation);
+extern void str_free_buffer(struct str_buffer *s);
+
+extern int str_enlarge_data(struct str_buffer *s, int length);
+extern void str_remove_initial(struct str_buffer *s, int length);
+extern void str_truncate_buffer(struct str_buffer *s, size_t length);
+extern char *str_buffer_data(struct str_buffer *s);
+extern size_t str_data_length(struct str_buffer *s);
+extern size_t str_unused_length(struct str_buffer *s);
+
+#endif /* STRINGS_H */
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/log.c b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/log.c
new file mode 100644 (file)
index 0000000..29cf39f
--- /dev/null
@@ -0,0 +1,493 @@
+/*
+ * Copyright (C) 2002-2003 Ardis Technolgies <roman@ardistech.com>
+ *
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <ctype.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/shm.h>
+#include <sys/ipc.h>
+#include <sys/types.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include "iscsi_util.h"
+#include "log.h"
+
+#define SEMKEY 0xA7L
+#define LOGDBG 0
+
+#if LOGDBG
+#define logdbg(file, fmt, args...) fprintf(file, fmt, ##args)
+#else
+#define logdbg(file, fmt, args...) do {} while (0)
+#endif
+
+char *log_name;
+int log_level = 0;
+struct logarea *la = NULL;
+
+static int log_stop_daemon = 0;
+static void (*log_func)(int prio, void *priv, const char *fmt, va_list ap);
+static void *log_func_priv;
+
+static void free_logarea (void)
+{
+       int shmid;
+
+       if (!la)
+               return;
+
+       if (la->semid != -1)
+               semctl(la->semid, 0, IPC_RMID, la->semarg);
+       if (la->buff) {
+               shmdt(la->buff);
+               shmctl(la->shmid_buff, IPC_RMID, NULL);
+               la->buff = NULL;
+               la->shmid_buff = -1;
+       }
+       if (la->start) {
+               shmdt(la->start);
+               shmctl(la->shmid_msg, IPC_RMID, NULL);
+               la->start = NULL;
+               la->shmid_msg = -1;
+       }
+       shmid = la->shmid;
+       shmdt(la);
+       shmctl(shmid, IPC_RMID, NULL);
+       la = NULL;
+}
+
+static int logarea_init (int size)
+{
+       int shmid;
+
+       logdbg(stderr,"enter logarea_init\n");
+
+       if ((shmid = shmget(IPC_PRIVATE, sizeof(struct logarea),
+                           0600 | IPC_CREAT | IPC_EXCL)) == -1) {
+               syslog(LOG_ERR, "shmget logarea failed %d", errno);
+               return 1;
+       }
+
+       la = shmat(shmid, NULL, 0);
+       if (!la) {
+               syslog(LOG_ERR, "shmat logarea failed %d", errno);
+               shmctl(shmid, IPC_RMID, NULL);
+               return 1;
+       }
+       la->shmid = shmid;
+       la->start = NULL;
+       la->buff = NULL;
+       la->semid = -1;
+
+       if (size < MAX_MSG_SIZE)
+               size = DEFAULT_AREA_SIZE;
+
+       if ((shmid = shmget(IPC_PRIVATE, size,
+                           0600 | IPC_CREAT | IPC_EXCL)) == -1) {
+               syslog(LOG_ERR, "shmget msg failed %d", errno);
+               free_logarea();
+               return 1;
+       }
+       la->shmid_msg = shmid;
+
+       la->start = shmat(la->shmid_msg, NULL, 0);
+       if (!la->start) {
+               syslog(LOG_ERR, "shmat msg failed %d", errno);
+               free_logarea();
+               return 1;
+       }
+       memset(la->start, 0, size);
+
+       la->empty = 1;
+       la->end = la->start + size;
+       la->head = la->start;
+       la->tail = la->start;
+
+       if ((shmid = shmget(IPC_PRIVATE, MAX_MSG_SIZE + sizeof(struct logmsg),
+                           0600 | IPC_CREAT | IPC_EXCL)) == -1) {
+               syslog(LOG_ERR, "shmget logmsg failed %d", errno);
+               free_logarea();
+               return 1;
+       }
+       la->buff = shmat(shmid, NULL, 0);
+       if (!la->buff) {
+               syslog(LOG_ERR, "shmat logmsgfailed %d", errno);
+               free_logarea();
+               return 1;
+       }
+
+       if ((la->semid = semget(SEMKEY, 1, 0600 | IPC_CREAT)) < 0) {
+               syslog(LOG_ERR, "semget failed %d", errno);
+               free_logarea();
+               return 1;
+       }
+
+       la->semarg.val=1;
+       if (semctl(la->semid, 0, SETVAL, la->semarg) < 0) {
+               syslog(LOG_ERR, "semctl failed %d", errno);
+               free_logarea();
+               return 1;
+       }
+
+       la->shmid_buff = shmid;
+       la->ops[0].sem_num = 0;
+       la->ops[0].sem_flg = 0;
+
+       return 0;
+
+}
+
+#if LOGDBG
+static void dump_logarea (void)
+{
+       struct logmsg * msg;
+
+       logdbg(stderr, "\n==== area: start addr = %p, end addr = %p ====\n",
+               la->start, la->end);
+       logdbg(stderr, "|addr     |next     |prio|msg\n");
+
+       for (msg = (struct logmsg *)la->head; (void *)msg != la->tail;
+            msg = msg->next)
+               logdbg(stderr, "|%p |%p |%i   |%s\n", (void *)msg, msg->next,
+                               msg->prio, (char *)&msg->str);
+
+       logdbg(stderr, "|%p |%p |%i   |%s\n", (void *)msg, msg->next,
+                       msg->prio, (char *)&msg->str);
+
+       logdbg(stderr, "\n\n");
+}
+#endif
+
+int log_enqueue (int prio, const char * fmt, va_list ap)
+{
+       int len, fwd;
+       char buff[MAX_MSG_SIZE];
+       struct logmsg * msg;
+       struct logmsg * lastmsg;
+
+       lastmsg = (struct logmsg *)la->tail;
+
+       if (!la->empty) {
+               fwd = sizeof(struct logmsg) +
+                     strlen((char *)&lastmsg->str) * sizeof(char) + 1;
+               la->tail += fwd;
+       }
+       vsnprintf(buff, MAX_MSG_SIZE, fmt, ap);
+       len = strlen(buff) * sizeof(char) + 1;
+
+       /* not enough space on tail : rewind */
+       if (la->head <= la->tail &&
+           (long)(len + sizeof(struct logmsg)) > (la->end - la->tail)) {
+               logdbg(stderr, "enqueue: rewind tail to %p\n", la->tail);
+                       la->tail = la->start;
+
+                       if (la->empty)
+                               la->head = lastmsg = la->tail;
+       }
+
+       /* not enough space on head : drop msg */
+       if (la->head > la->tail &&
+           (long)(len + sizeof(struct logmsg)) > (la->head - la->tail)) {
+               logdbg(stderr, "enqueue: log area overrun, drop msg\n");
+
+               if (!la->empty)
+                       la->tail = lastmsg;
+
+               return 1;
+       }
+
+       /* ok, we can stage the msg in the area */
+       la->empty = 0;
+       msg = (struct logmsg *)la->tail;
+       msg->prio = prio;
+       memcpy((void *)&msg->str, buff, len);
+       lastmsg->next = la->tail;
+       msg->next = la->head;
+
+       logdbg(stderr, "enqueue: %p, %p, %i, %s\n", (void *)msg, msg->next,
+               msg->prio, (char *)&msg->str);
+
+#if LOGDBG
+       dump_logarea();
+#endif
+       return 0;
+}
+
+int log_dequeue (void * buff)
+{
+       struct logmsg * src = (struct logmsg *)la->head;
+       struct logmsg * dst = (struct logmsg *)buff;
+       struct logmsg * lst = (struct logmsg *)la->tail;
+       int len;
+
+       if (la->empty)
+               return 0;
+
+       len = strlen((char *)&src->str) * sizeof(char) +
+             sizeof(struct logmsg) + 1;
+
+       dst->prio = src->prio;
+       memcpy(dst, src,  len);
+
+       if (la->tail == la->head)
+               la->empty = 1; /* purge the last log msg */
+       else {
+               la->head = src->next;
+               lst->next = la->head;
+       }
+       logdbg(stderr, "dequeue: %p, %p, %i, %s\n",
+              (void *)src, src->next, src->prio, (char *)&src->str);
+
+       memset((void *)src, 0, len);
+
+       return len;
+}
+
+/*
+ * this one can block under memory pressure
+ */
+static void log_syslog (void * buff)
+{
+       struct logmsg * msg = (struct logmsg *)buff;
+
+       syslog(msg->prio, "%s", (char *)&msg->str);
+}
+
+void log_do_log_daemon(int prio,
+                      __attribute__((unused))void *priv,
+                      const char *fmt,
+                      va_list ap)
+{
+       struct sembuf ops[1];
+
+       ops[0].sem_num = la->ops[0].sem_num;
+       ops[0].sem_flg = la->ops[0].sem_flg;
+
+       ops[0].sem_op = -1;
+       if (semop(la->semid, ops, 1) < 0) {
+               syslog(LOG_ERR, "semop down failed %d", errno);
+               return;
+       }
+
+       log_enqueue(prio, fmt, ap);
+
+       ops[0].sem_op = 1;
+       if (semop(la->semid, ops, 1) < 0)
+               syslog(LOG_ERR, "semop up failed");
+}
+
+void log_do_log_std(int prio,
+                   __attribute__((unused))void *priv,
+                   const char *fmt,
+                   va_list ap)
+{
+       if (prio == LOG_INFO) {
+               vfprintf(stdout, fmt, ap);
+               fprintf(stdout, "\n");
+       } else {
+               fprintf(stderr, "%s: ", log_name);
+               vfprintf(stderr, fmt, ap);
+               fprintf(stderr, "\n");
+               fflush(stderr);
+       }
+}
+
+void log_warning(const char *fmt, ...)
+{
+       va_list ap;
+       va_start(ap, fmt);
+       log_func(LOG_WARNING, log_func_priv, fmt, ap);
+       va_end(ap);
+}
+
+void log_error(const char *fmt, ...)
+{
+       va_list ap;
+       va_start(ap, fmt);
+       log_func(LOG_ERR, log_func_priv, fmt, ap);
+       va_end(ap);
+}
+
+void log_debug(int level, const char *fmt, ...)
+{
+       if (log_level > level) {
+               va_list ap;
+               va_start(ap, fmt);
+               log_func(LOG_DEBUG, log_func_priv, fmt, ap);
+               va_end(ap);
+       }
+}
+
+void log_info(const char *fmt, ...)
+{
+       va_list ap;
+       va_start(ap, fmt);
+       log_func(LOG_INFO, log_func_priv, fmt, ap);
+       va_end(ap);
+}
+
+#if 0 /* Unused */
+static void __dump_line(int level, unsigned char *buf, int *cp)
+{
+       char line[16*3+5], *lp = line;
+       int i, cnt;
+
+       cnt = *cp;
+       if (!cnt)
+               return;
+       for (i = 0; i < 16; i++) {
+               if (i < cnt)
+                       lp += sprintf(lp, " %02x", buf[i]);
+               else
+                       lp += sprintf(lp, "   ");
+               if ((i % 4) == 3)
+                       lp += sprintf(lp, " |");
+               if (i >= cnt || !isprint(buf[i]))
+                       buf[i] =  ' ';
+       }
+       log_debug(level, "%s %.16s |", line, buf);
+       *cp = 0;
+}
+
+static void __dump_char(int level, unsigned char *buf, int *cp, int ch)
+{
+       int cnt = (*cp)++;
+
+       buf[cnt] = ch;
+       if (cnt == 15)
+               __dump_line(level, buf, cp);
+}
+
+#define dump_line() __dump_line(level, char_buf, &char_cnt)
+#define dump_char(ch) __dump_char(level, char_buf, &char_cnt, ch)
+#endif /* Unused */
+
+static void log_flush(void)
+{
+       int msglen;
+       struct sembuf ops[1];
+
+       ops[0].sem_num = la->ops[0].sem_num;
+       ops[0].sem_flg = la->ops[0].sem_flg;
+
+
+       while (!la->empty) {
+               ops[0].sem_op = -1;
+               if (semop(la->semid, ops, 1) < 0) {
+                       syslog(LOG_ERR, "semop down failed %d", errno);
+                       exit(1);
+               }
+               msglen = log_dequeue(la->buff);
+               ops[0].sem_op = 1;
+               if (semop(la->semid, ops, 1) < 0) {
+                       syslog(LOG_ERR, "semop up failed");
+                       exit(1);
+               }
+               if (msglen)
+                       log_syslog(la->buff);
+       }
+}
+
+static void catch_signal(int signo)
+{
+       switch (signo) {
+       case SIGSEGV:
+               log_flush();
+               break;
+       case SIGTERM:
+               log_stop_daemon = 1;
+               break;
+       }
+
+       log_debug(1, "pid %d caught signal -%d", getpid(), signo);
+}
+
+static void __log_close(void)
+{
+       if (log_func == log_do_log_daemon) {
+               log_flush();
+               closelog();
+               free_logarea();
+       }
+}
+
+int log_init(char *program_name, int size,
+       void (*func)(int prio, void *priv, const char *fmt, va_list ap),
+       void *priv)
+{
+       logdbg(stderr,"enter log_init\n");
+       log_name = program_name;
+       log_func = func;
+       log_func_priv = priv;
+
+       if (log_func == log_do_log_daemon) {
+               struct sigaction sa_old;
+               struct sigaction sa_new;
+               pid_t pid;
+
+               openlog(log_name, 0, LOG_DAEMON);
+               setlogmask (LOG_UPTO (LOG_DEBUG));
+
+               if (logarea_init(size)) {
+                       syslog(LOG_ERR, "logarea init failed");
+                       return -1;
+               }
+
+               pid = fork();
+               if (pid < 0) {
+                       syslog(LOG_ERR, "starting logger failed");
+                       exit(1);
+               } else if (pid) {
+                       syslog(LOG_INFO,
+                              "iSCSI logger with pid=%d started!", pid);
+                       return pid;
+               }
+
+               daemon_init();
+
+               /* flush on daemon's crash */
+               sa_new.sa_handler = (void*)catch_signal;
+               sigemptyset(&sa_new.sa_mask);
+               sa_new.sa_flags = 0;
+               sigaction(SIGSEGV, &sa_new, &sa_old );
+               sigaction(SIGTERM, &sa_new, &sa_old );
+
+               while(1) {
+                       log_flush();
+                       sleep(1);
+
+                       if (log_stop_daemon)
+                               break;
+               }
+
+               __log_close();
+               exit(0);
+       }
+
+       return 0;
+}
+
+void log_close(pid_t pid)
+{
+       int status;
+
+       if (log_func != log_do_log_daemon || pid < 0) {
+               __log_close();
+               return;
+       }
+
+       if (pid > 0) {
+               kill(pid, SIGTERM);
+               waitpid(pid, &status, 0);
+       }
+}
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/log.h b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/log.h
new file mode 100644 (file)
index 0000000..c548791
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * iSCSI Safe Logging and Tracing Library
+ *
+ * Copyright (C) 2004 Dmitry Yusupov, Alex Aizman
+ * maintained by open-iscsi@googlegroups.com
+ *
+ * circular buffer code based on log.c from dm-multipath project
+ *
+ * heavily based on code from log.c:
+ *   Copyright (C) 2002-2003 Ardis Technolgies <roman@ardistech.com>,
+ *   licensed under the terms of the GNU GPL v2.0,
+ *
+ * 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 LOG_H
+#define LOG_H
+
+#include <stdarg.h>
+#include <sys/types.h>
+#include "iscsid.h"
+
+union semun {
+       int val;
+       struct semid_ds *buf;
+       unsigned short int *array;
+       struct seminfo *__buf;
+};
+#include <sys/sem.h>
+
+#define DEFAULT_AREA_SIZE 16384
+#define MAX_MSG_SIZE 256
+
+extern int log_level;
+
+struct logmsg {
+       short int prio;
+       void *next;
+       char *str;
+};
+
+struct logarea {
+       int shmid;
+       int shmid_msg;
+       int shmid_buff;
+       int empty;
+       void *head;
+       void *tail;
+       void *start;
+       void *end;
+       char *buff;
+       struct sembuf ops[1];
+       int semid;
+       union semun semarg;
+};
+
+extern struct logarea *la;
+
+extern int log_init(char *program_name, int size,
+       void (*func)(int prio, void *priv, const char *fmt, va_list ap),
+       void *priv);
+extern void log_close (pid_t pid);
+extern void dump_logmsg (void *);
+extern void log_info(const char *fmt, ...)
+       __attribute__ ((format (printf, 1, 2)));
+extern void log_warning(const char *fmt, ...)
+       __attribute__ ((format (printf, 1, 2)));
+extern void log_error(const char *fmt, ...)
+       __attribute__ ((format (printf, 1, 2)));
+extern void log_debug(int level, const char *fmt, ...)
+       __attribute__ ((format (printf, 2, 3)));
+
+extern void log_do_log_daemon(int prio, void *priv, const char *fmt, va_list ap);
+extern void log_do_log_std(int prio, void *priv, const char *fmt, va_list ap);
+
+#endif /* LOG_H */
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/login.c b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/login.c
new file mode 100644 (file)
index 0000000..096deda
--- /dev/null
@@ -0,0 +1,1618 @@
+/*
+ * iSCSI Login Library
+ *
+ * Copyright (C) 2004 Dmitry Yusupov, Alex Aizman
+ * maintained by open-iscsi@googlegroups.com
+ *
+ * heavily based on code from iscsi-login.c:
+ * Copyright (C) 2001 Cisco Systems, Inc.
+ *
+ * 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.
+ *
+ * Formation of iSCSI login pdu, processing the login response and other
+ * functions are defined here
+ */
+
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <poll.h>
+#include <errno.h>
+#include <sys/param.h>
+
+#include "initiator.h"
+#include "transport.h"
+#include "log.h"
+#include "iscsi_timer.h"
+
+/* caller is assumed to be well-behaved and passing NUL terminated strings */
+int
+iscsi_add_text(struct iscsi_hdr *pdu, char *data, int max_data_length,
+               char *param, char *value)
+{
+       int param_len = strlen(param);
+       int value_len = strlen(value);
+       int length = param_len + 1 + value_len + 1;     /* param, separator,
+                                                        * value, and trailing
+                                                        * NULL
+                                                        */
+       int pdu_length = ntoh24(pdu->dlength);
+       char *text = data;
+       char *end = data + max_data_length;
+
+       /* find the end of the current text */
+       text += pdu_length;
+       pdu_length += length;
+
+       if (text + length >= end) {
+               log_warning("Failed to add login text "
+                           "'%s=%s'", param, value);
+               return 0;
+       }
+
+       /* param */
+       memcpy(text, param, param_len);
+       text += param_len;
+
+       /* separator */
+       *text++ = ISCSI_TEXT_SEPARATOR;
+
+       /* value */
+       memcpy(text, value, value_len);
+       text += value_len;
+
+       /* NUL */
+       *text++ = '\0';
+
+       /* update the length in the PDU header */
+       hton24(pdu->dlength, pdu_length);
+
+       return 1;
+}
+
+static int
+iscsi_find_key_value(char *param, char *pdu, char *pdu_end, char **value_start,
+                    char **value_end)
+{
+       char *str = param;
+       char *text = pdu;
+       char *value;
+
+       if (value_start)
+               *value_start = NULL;
+       if (value_end)
+               *value_end = NULL;
+
+       /* make sure they contain the same bytes */
+       while (*str) {
+               if (text >= pdu_end)
+                       return 0;
+               if (*text == '\0')
+                       return 0;
+               if (*str != *text)
+                       return 0;
+               str++;
+               text++;
+       }
+
+       if ((text >= pdu_end) || (*text == '\0')
+           || (*text != ISCSI_TEXT_SEPARATOR)) {
+               return 0;
+       }
+
+       /* find the value */
+       value = text + 1;
+
+       /* find the end of the value */
+       while ((text < pdu_end) && (*text))
+               text++;
+
+       if (value_start)
+               *value_start = value;
+       if (value_end)
+               *value_end = text;
+
+       return 1;
+}
+
+static enum iscsi_login_status
+get_auth_key_type(struct iscsi_acl *auth_client, char **data, char *end)
+{
+       char *key;
+       char *value = NULL;
+        char *value_end = NULL;
+       char *text = *data;
+
+       int keytype = AUTH_KEY_TYPE_NONE;
+
+       while (acl_get_next_key_type(&keytype) == AUTH_STATUS_NO_ERROR) {
+               key = (char *)acl_get_key_name(keytype);
+               if (key && iscsi_find_key_value(key, text, end, &value,
+                                               &value_end)) {
+                       if (acl_recv_key_value(auth_client, keytype, value) !=
+                                              AUTH_STATUS_NO_ERROR) {
+                               log_error("login negotiation failed, can't "
+                                         "accept %s in security stage", text);
+                               return LOGIN_NEGOTIATION_FAILED;
+                       }
+                       text = value_end;
+                       *data = text;
+                       return LOGIN_OK;
+               }
+       }
+       log_error("Login negotiation failed, can't accept %s in security "
+                 "stage", text);
+       return LOGIN_NEGOTIATION_FAILED;
+}
+
+int
+resolve_address(char *host, char *port, struct sockaddr_storage *ss)
+{
+       struct addrinfo hints, *res;
+       int rc;
+
+       memset(&hints, 0, sizeof(struct addrinfo));
+       hints.ai_family = AF_UNSPEC;
+       hints.ai_socktype = SOCK_STREAM;
+
+       if ((rc = getaddrinfo(host, port, &hints, &res))) {
+               log_error("Cannot resolve host %s. getaddrinfo error: "
+                         "[%s]", host, gai_strerror(rc));
+               return rc;
+       }
+
+       memcpy(ss, res->ai_addr, res->ai_addrlen);
+
+       freeaddrinfo(res);
+
+       return rc;
+}
+
+/*
+ * try to reset the session's IP address and port, based on the TargetAddress
+ * provided
+ */
+int
+iscsi_update_address(iscsi_conn_t *conn, char *address)
+{
+       char *port, *tag;
+       char default_port[NI_MAXSERV];
+       iscsi_session_t *session = conn->session;
+       struct sockaddr_storage addr;
+
+       if ((tag = strrchr(address, ','))) {
+               *tag = '\0';
+               tag++;
+       }
+       if ((port = strrchr(address, ':'))) {
+               *port = '\0';
+               port++;
+       }
+
+       if (!port) {
+               sprintf(default_port, "%d", ISCSI_LISTEN_PORT);
+               port = default_port;
+       }
+
+       if (*address == '[') {
+               char *end_bracket;
+
+               if (!(end_bracket = strchr(address, ']'))) {
+                       log_error("Invalid IPv6 address with opening bracket, "
+                                 "but no closing bracket.");
+                       return 0;
+               }
+               *end_bracket = '\0';
+               address++;
+        }
+
+       if (resolve_address(address, port, &addr)) {
+               log_error("cannot resolve host name %s", address);
+               return 0;
+       }
+
+       conn->saddr = addr;
+       if (tag)
+               session->portal_group_tag = atoi(tag);
+       return 1;
+}
+
+static enum iscsi_login_status
+get_security_text_keys(iscsi_session_t *session, int cid, char **data,
+                      struct iscsi_acl *auth_client, char *end)
+{
+       char *text = *data;
+       char *value = NULL;
+       char *value_end = NULL;
+       size_t size;
+       int tag;
+       enum iscsi_login_status ret;
+
+       /*
+        * a few keys are possible in Security stage
+        * which the auth code doesn't care about, but
+        * which we might want to see, or at least not
+        * choke on.
+        */
+       if (iscsi_find_key_value("TargetAlias", text, end, &value,
+               &value_end)) {
+               size = value_end - value;
+               session->target_alias = malloc(size + 1);
+               if (!session->target_alias) {
+                       /* Alias not critical. So just print an error */
+                       log_error("Login failed to allocate alias");
+                       *data = value_end;
+                       return LOGIN_OK;
+               }
+               memcpy(session->target_alias, value, size);
+               session->target_alias[size] = '\0';
+               text = value_end;
+       } else if (iscsi_find_key_value("TargetAddress", text, end, &value,
+                                        &value_end)) {
+               /*
+                * if possible, change the session's
+                * ip_address and port to the new TargetAddress for
+                * leading connection
+                */
+               if (iscsi_update_address(&session->conn[cid], value)) {
+                       text = value_end;
+               } else {
+                       log_error("Login redirection failed, "
+                                 "can't handle redirection to %s", value);
+                       return LOGIN_REDIRECTION_FAILED;
+               }
+       } else if (iscsi_find_key_value("TargetPortalGroupTag", text, end,
+                                        &value, &value_end)) {
+               /*
+                * We should have already obtained this
+                * via discovery, but the value could be stale.
+                * If the target was reconfigured it will send us
+                * the updated tpgt.
+                */
+               tag = strtoul(value, NULL, 0);
+               if (session->portal_group_tag >= 0) {
+                       if (tag != session->portal_group_tag)
+                               log_debug(2, "Portal group tag "
+                                         "mismatch, expected %u, "
+                                         "received %u. Updating",
+                                         session->portal_group_tag, tag);
+               }
+               /* we now know the tag */
+               session->portal_group_tag = tag;
+               text = value_end;
+       } else {
+               /*
+                * any key we don't recognize either
+                * goes to the auth code, or we choke
+                * on it
+                */
+               ret = get_auth_key_type(auth_client, &text, end);
+               if (ret != LOGIN_OK)
+                       return ret;
+       }
+       *data = text;
+       return LOGIN_OK;
+}
+
+static enum iscsi_login_status
+get_op_params_text_keys(iscsi_session_t *session, int cid,
+                       char **data, char *end)
+{
+       char *text = *data;
+       char *value = NULL;
+       char *value_end = NULL;
+       size_t size;
+       iscsi_conn_t *conn = &session->conn[cid];
+
+       if (iscsi_find_key_value("TargetAlias", text, end, &value,
+                                &value_end)) {
+               size = value_end - value;
+               if (session->target_alias &&
+                   strlen(session->target_alias) == size &&
+                   memcmp(session->target_alias, value, size) == 0) {
+                       *data = value_end;
+                       return LOGIN_OK;
+               }
+               free(session->target_alias);
+               session->target_alias = malloc(size + 1);
+               if (!session->target_alias) {
+                       /* Alias not critical. So just print an error */
+                       log_error("Login failed to allocate alias");
+                       *data = value_end;
+                       return LOGIN_OK;
+               }
+               memcpy(session->target_alias, value, size);
+               session->target_alias[size] = '\0';
+               text = value_end;
+       } else if (iscsi_find_key_value("TargetAddress", text, end, &value,
+                                        &value_end)) {
+               if (iscsi_update_address(conn, value))
+                       text = value_end;
+               else {
+                       log_error("Login redirection failed, "
+                                 "can't handle redirection to %s",
+                                 value);
+                       return LOGIN_REDIRECTION_FAILED;
+               }
+       } else if (iscsi_find_key_value("TargetPortalGroupTag", text, end,
+                                        &value, &value_end)) {
+               int tag = strtoul(value, NULL, 0);
+               /*
+                * We should have already obtained this
+                * via discovery, but the value could be stale.
+                * If the target was reconfigured it will send us
+                * the updated tpgt.
+                */
+               if (session->portal_group_tag >= 0) {
+                       if (tag != session->portal_group_tag)
+                               log_debug(2, "Portal group tag "
+                                         "mismatch, expected %u, "
+                                         "received %u. Updating",
+                                         session->portal_group_tag, tag);
+               }
+               /* we now know the tag */
+               session->portal_group_tag = tag;
+               text = value_end;
+       } else if (iscsi_find_key_value("InitialR2T", text, end, &value,
+                                        &value_end)) {
+               if (session->type == ISCSI_SESSION_TYPE_NORMAL) {
+                       if (value && (strcmp(value, "Yes") == 0))
+                               session->initial_r2t_en = 1;
+                       else
+                               session->initial_r2t_en = 0;
+               } else
+                       session->irrelevant_keys_bitmap |=
+                                               IRRELEVANT_INITIALR2T;
+               text = value_end;
+       } else if (iscsi_find_key_value("ImmediateData", text, end, &value,
+                                        &value_end)) {
+               if (session->type == ISCSI_SESSION_TYPE_NORMAL) {
+                       if (value && (strcmp(value, "Yes") == 0))
+                               session->imm_data_en = 1;
+                       else
+                               session->imm_data_en = 0;
+               } else
+                       session->irrelevant_keys_bitmap |=
+                                               IRRELEVANT_IMMEDIATEDATA;
+               text = value_end;
+       } else if (iscsi_find_key_value("MaxRecvDataSegmentLength", text, end,
+                                    &value, &value_end)) {
+               if (session->type == ISCSI_SESSION_TYPE_DISCOVERY ||
+                   !session->t->template->rdma) {
+                       int tgt_max_xmit;
+                       conn_rec_t *conn_rec = &session->nrec.conn[cid];
+
+                       tgt_max_xmit = strtoul(value, NULL, 0);
+                       /*
+                        * if the rec value is zero it means to use
+                        * what the target gave us.
+                        */
+                       if (!conn_rec->iscsi.MaxXmitDataSegmentLength ||
+                           tgt_max_xmit < (int)conn->max_xmit_dlength)
+                               conn->max_xmit_dlength = tgt_max_xmit;
+               }
+               text = value_end;
+       } else if (iscsi_find_key_value("FirstBurstLength", text, end, &value,
+                                        &value_end)) {
+               if (session->type == ISCSI_SESSION_TYPE_NORMAL)
+                       session->first_burst = strtoul(value, NULL, 0);
+               else
+                       session->irrelevant_keys_bitmap |=
+                                               IRRELEVANT_FIRSTBURSTLENGTH;
+               text = value_end;
+       } else if (iscsi_find_key_value("MaxBurstLength", text, end, &value,
+                                        &value_end)) {
+               /*
+                * we don't really care, since it's a  limit on the target's
+                * R2Ts, but record it anwyay
+                */
+               if (session->type == ISCSI_SESSION_TYPE_NORMAL)
+                       session->max_burst = strtoul(value, NULL, 0);
+               else
+                       session->irrelevant_keys_bitmap |=
+                                               IRRELEVANT_MAXBURSTLENGTH;
+               text = value_end;
+       } else if (iscsi_find_key_value("HeaderDigest", text, end, &value,
+                                        &value_end)) {
+               if (strcmp(value, "None") == 0) {
+                       if (conn->hdrdgst_en != ISCSI_DIGEST_CRC32C)
+                               conn->hdrdgst_en = ISCSI_DIGEST_NONE;
+                       else {
+                               log_error("Login negotiation "
+                                              "failed, HeaderDigest=CRC32C "
+                                              "is required, can't accept "
+                                              "%s", text);
+                               return LOGIN_NEGOTIATION_FAILED;
+                       }
+               } else if (strcmp(value, "CRC32C") == 0) {
+                       if (conn->hdrdgst_en != ISCSI_DIGEST_NONE)
+                               conn->hdrdgst_en = ISCSI_DIGEST_CRC32C;
+                       else {
+                               log_error("Login negotiation "
+                                      "failed, HeaderDigest=None is "
+                                      "required, can't accept %s", text);
+                               return LOGIN_NEGOTIATION_FAILED;
+                       }
+               } else {
+                       log_error("Login negotiation failed, "
+                                      "can't accept %s", text);
+                       return LOGIN_NEGOTIATION_FAILED;
+               }
+               text = value_end;
+       } else if (iscsi_find_key_value("DataDigest", text, end, &value,
+                                        &value_end)) {
+               if (strcmp(value, "None") == 0) {
+                       if (conn->datadgst_en != ISCSI_DIGEST_CRC32C)
+                               conn->datadgst_en = ISCSI_DIGEST_NONE;
+                       else {
+                               log_error("Login negotiation "
+                                      "failed, DataDigest=CRC32C "
+                                      "is required, can't accept %s", text);
+                               return LOGIN_NEGOTIATION_FAILED;
+                       }
+               } else if (strcmp(value, "CRC32C") == 0) {
+                       if (conn->datadgst_en != ISCSI_DIGEST_NONE)
+                               conn->datadgst_en = ISCSI_DIGEST_CRC32C;
+                       else {
+                               log_error("Login negotiation "
+                                      "failed, DataDigest=None is "
+                                      "required, can't accept %s", text);
+                               return LOGIN_NEGOTIATION_FAILED;
+                       }
+               } else {
+                       log_error("Login negotiation failed, "
+                                      "can't accept %s", text);
+                       return LOGIN_NEGOTIATION_FAILED;
+               }
+               text = value_end;
+       } else if (iscsi_find_key_value("DefaultTime2Wait", text, end, &value,
+                                        &value_end)) {
+               session->def_time2wait = strtoul(value, NULL, 0);
+               text = value_end;
+       } else if (iscsi_find_key_value("DefaultTime2Retain", text, end,
+                                        &value, &value_end)) {
+               session->def_time2retain = strtoul(value, NULL, 0);
+               text = value_end;
+       } else if (iscsi_find_key_value("OFMarker", text, end, &value,
+                                        &value_end))
+               /* result function is AND, target must honor our No */
+               text = value_end;
+       else if (iscsi_find_key_value("OFMarkInt", text, end, &value,
+                                        &value_end))
+               /* we don't do markers, so we don't care */
+               text = value_end;
+       else if (iscsi_find_key_value("IFMarker", text, end, &value,
+                                        &value_end))
+               /* result function is AND, target must honor our No */
+               text = value_end;
+       else if (iscsi_find_key_value("IFMarkInt", text, end, &value,
+                                        &value_end))
+               /* we don't do markers, so we don't care */
+               text = value_end;
+       else if (iscsi_find_key_value("DataPDUInOrder", text, end, &value,
+                                        &value_end)) {
+               if (session->type == ISCSI_SESSION_TYPE_NORMAL) {
+                       if (value && strcmp(value, "Yes") == 0)
+                               session->pdu_inorder_en = 1;
+                       else
+                               session->pdu_inorder_en = 0;
+               } else
+                       session->irrelevant_keys_bitmap |=
+                                               IRRELEVANT_DATAPDUINORDER;
+               text = value_end;
+       } else if (iscsi_find_key_value ("DataSequenceInOrder", text, end,
+                                        &value, &value_end)) {
+               if (session->type == ISCSI_SESSION_TYPE_NORMAL)
+                       if (value && strcmp(value, "Yes") == 0)
+                               session->dataseq_inorder_en = 1;
+                       else
+                               session->dataseq_inorder_en = 0;
+               else
+                       session->irrelevant_keys_bitmap |=
+                                               IRRELEVANT_DATASEQUENCEINORDER;
+               text = value_end;
+       } else if (iscsi_find_key_value("MaxOutstandingR2T", text, end, &value,
+                                        &value_end)) {
+               if (session->type == ISCSI_SESSION_TYPE_NORMAL)
+                       session->max_r2t = strtoul(value, NULL, 0);
+               else
+                       session->irrelevant_keys_bitmap |=
+                                               IRRELEVANT_MAXOUTSTANDINGR2T;
+               text = value_end;
+       } else if (iscsi_find_key_value("MaxConnections", text, end, &value,
+                                        &value_end)) {
+               if (session->type == ISCSI_SESSION_TYPE_NORMAL) {
+                       if (strcmp(value, "1")) {
+                               log_error("Login negotiation "
+                                              "failed, can't accept Max"
+                                              "Connections %s", value);
+                               return LOGIN_NEGOTIATION_FAILED;
+                       }
+               } else
+                       session->irrelevant_keys_bitmap |=
+                                               IRRELEVANT_MAXCONNECTIONS;
+               text = value_end;
+       } else if (iscsi_find_key_value("ErrorRecoveryLevel", text, end,
+                                        &value, &value_end)) {
+               if (strcmp(value, "0")) {
+                       log_error("Login negotiation failed, "
+                              "can't accept ErrorRecovery %s", value);
+                       return LOGIN_NEGOTIATION_FAILED;
+               }
+               text = value_end;
+       } else if (iscsi_find_key_value("RDMAExtensions", text, end,
+                                       &value, &value_end)) {
+               if (session->t->template->rdma &&
+                   strcmp(value, "Yes") != 0) {
+                       log_error("Login negotiation failed, "
+                                 "Target must support RDMAExtensions");
+                       return LOGIN_NEGOTIATION_FAILED;
+               }
+               text = value_end;
+       } else if (iscsi_find_key_value("InitiatorRecvDataSegmentLength", text,
+                                       end, &value, &value_end)) {
+               if (session->t->template->rdma) {
+                       conn->max_recv_dlength = MIN(conn->max_recv_dlength,
+                                                    strtoul(value, NULL, 0));
+               }
+               text = value_end;
+       } else if (iscsi_find_key_value("TargetRecvDataSegmentLength", text,
+                                       end, &value, &value_end)) {
+               if (session->t->template->rdma) {
+                       conn->max_xmit_dlength = MIN(conn->max_xmit_dlength,
+                                                    strtoul(value, NULL, 0));
+               }
+               text = value_end;
+       } else if (iscsi_find_key_value ("X-com.cisco.protocol", text, end,
+                                        &value, &value_end)) {
+               if (strcmp(value, "NotUnderstood") &&
+                   strcmp(value, "Reject") &&
+                   strcmp(value, "Irrelevant") &&
+                   strcmp(value, "draft20")) {
+                       /* if we didn't get a compatible protocol, fail */
+                       log_error("Login version mismatch, "
+                                      "can't accept protocol %s", value);
+                       return LOGIN_VERSION_MISMATCH;
+               }
+               text = value_end;
+       } else if (iscsi_find_key_value("X-com.cisco.PingTimeout", text, end,
+                                        &value, &value_end))
+               /* we don't really care what the target ends up using */
+               text = value_end;
+       else if (iscsi_find_key_value("X-com.cisco.sendAsyncText", text, end,
+                                        &value, &value_end))
+               /* we don't bother for the target response */
+               text = value_end;
+       else {
+               log_error("Login negotiation failed, couldn't "
+                              "recognize text %s", text);
+               return LOGIN_NEGOTIATION_FAILED;
+       }
+       *data = text;
+       return LOGIN_OK;
+}
+
+static enum iscsi_login_status
+check_security_stage_status(iscsi_session_t *session,
+                           struct iscsi_acl *auth_client)
+{
+       int debug_status = 0;
+
+       switch (acl_recv_end(auth_client, session)) {
+       case AUTH_STATUS_CONTINUE:
+               /* continue sending PDUs */
+               break;
+
+       case AUTH_STATUS_PASS:
+               break;
+
+       case AUTH_STATUS_NO_ERROR:      /* treat this as an error,
+                                        * since we should get a
+                                        * different code
+                                        */
+       case AUTH_STATUS_ERROR:
+       case AUTH_STATUS_FAIL:
+       default:
+               if (acl_get_dbg_status(auth_client, &debug_status) ==
+                   AUTH_STATUS_NO_ERROR)
+                       log_error("Login authentication failed "
+                                      "with target %s, %s",
+                                      session->target_name,
+                                      acl_dbg_status_to_text(debug_status));
+               else
+                       log_error("Login authentication failed "
+                                      "with target %s",
+                                      session->target_name);
+               return LOGIN_AUTHENTICATION_FAILED;
+       }
+       return LOGIN_OK;
+}
+
+/*
+ * this assumes the text data is always NULL terminated.  The caller can
+ * always arrange for that by using a slightly larger buffer than the max PDU
+ * size, and then appending a NULL to the PDU.
+ */
+static enum iscsi_login_status
+iscsi_process_login_response(iscsi_session_t *session, int cid,
+                            struct iscsi_login_rsp *login_rsp,
+                            char *data, int max_data_length)
+{
+       int transit = login_rsp->flags & ISCSI_FLAG_LOGIN_TRANSIT;
+       char *text = data;
+       char *end;
+       int pdu_current_stage, pdu_next_stage;
+       enum iscsi_login_status ret;
+       struct iscsi_acl *auth_client;
+       iscsi_conn_t *conn = &session->conn[cid];
+
+       auth_client = (session->num_auth_buffers > 0) ?
+               (struct iscsi_acl *)session->auth_buffers[0].address : NULL;
+
+       end = text + ntoh24(login_rsp->dlength) + 1;
+       if (end >= (data + max_data_length)) {
+               log_error("Login failed, process_login_response "
+                              "buffer too small to guarantee NULL "
+                              "termination");
+               return LOGIN_FAILED;
+       }
+
+       /* guarantee a trailing NUL */
+       *end = '\0';
+
+       /* if the response status was success, sanity check the response */
+       if (login_rsp->status_class == ISCSI_STATUS_CLS_SUCCESS) {
+               /* check the active version */
+               if (login_rsp->active_version != ISCSI_DRAFT20_VERSION) {
+                       log_error("Login version mismatch, "
+                                      "received incompatible active iSCSI "
+                                      "version 0x%02x, expected version "
+                                      "0x%02x",
+                                      login_rsp->active_version,
+                                      ISCSI_DRAFT20_VERSION);
+                       return LOGIN_VERSION_MISMATCH;
+               }
+
+               /* make sure the current stage matches */
+               pdu_current_stage = (login_rsp->flags &
+                                   ISCSI_FLAG_LOGIN_CURRENT_STAGE_MASK) >> 2;
+               if (pdu_current_stage != conn->current_stage) {
+                       log_error("Received invalid login PDU, "
+                                      "current stage mismatch, session %d, "
+                                      "response %d", conn->current_stage,
+                                      pdu_current_stage);
+                       return LOGIN_INVALID_PDU;
+               }
+
+               /*
+                * make sure that we're actually advancing if the T-bit is set
+                */
+               pdu_next_stage = login_rsp->flags &
+                                ISCSI_FLAG_LOGIN_NEXT_STAGE_MASK;
+               if (transit && (pdu_next_stage <= conn->current_stage))
+                       return LOGIN_INVALID_PDU;
+       }
+
+       if (conn->current_stage == ISCSI_SECURITY_NEGOTIATION_STAGE) {
+               if (acl_recv_begin(auth_client) != AUTH_STATUS_NO_ERROR) {
+                       log_error("Login failed because "
+                                      "acl_recv_begin failed");
+                       return LOGIN_FAILED;
+               }
+
+               if (acl_recv_transit_bit(auth_client, transit) !=
+                   AUTH_STATUS_NO_ERROR) {
+                       log_error("Login failed because "
+                                 "acl_recv_transit_bit failed");
+                       return LOGIN_FAILED;
+               }
+       }
+
+       /* scan the text data */
+       while (text && (text < end)) {
+               /* skip any NULs separating each text key=value pair */
+               while ((text < end) && (*text == '\0'))
+                       text++;
+               if (text >= end)
+                       break;
+
+               /* handle keys appropriate for each stage */
+               switch (conn->current_stage) {
+               case ISCSI_SECURITY_NEGOTIATION_STAGE:{
+                               ret = get_security_text_keys(session, cid,
+                                               &text, auth_client, end);
+                               if (ret != LOGIN_OK)
+                                       return ret;
+                               break;
+                       }
+               case ISCSI_OP_PARMS_NEGOTIATION_STAGE:{
+                               ret = get_op_params_text_keys(session, cid,
+                                               &text, end);
+                               if (ret != LOGIN_OK)
+                                       return ret;
+                               break;
+                       }
+               default:
+                       return LOGIN_FAILED;
+               }
+       }
+
+       if (conn->current_stage == ISCSI_SECURITY_NEGOTIATION_STAGE) {
+               ret = check_security_stage_status(session, auth_client);
+               if (ret != LOGIN_OK)
+                       return ret;
+       }
+       /* record some of the PDU fields for later use */
+       session->tsih = ntohs(login_rsp->tsih);
+       session->exp_cmdsn = ntohl(login_rsp->exp_cmdsn);
+       session->max_cmdsn = ntohl(login_rsp->max_cmdsn);
+       if (login_rsp->status_class == ISCSI_STATUS_CLS_SUCCESS)
+               conn->exp_statsn = ntohl(login_rsp->statsn) + 1;
+
+       if (transit) {
+               /* advance to the next stage */
+               conn->partial_response = 0;
+               conn->current_stage = login_rsp->flags &
+                                        ISCSI_FLAG_LOGIN_NEXT_STAGE_MASK;
+               session->irrelevant_keys_bitmap = 0;
+       } else
+               /*
+                * we got a partial response, don't advance,
+                * more negotiation to do
+                */
+               conn->partial_response = 1;
+
+       return LOGIN_OK;        /* this PDU is ok, though the login process
+                                * may not be done yet
+                                */
+}
+
+static int
+add_params_normal_session(iscsi_session_t *session, struct iscsi_hdr *pdu,
+                    char *data, int max_data_length)
+{
+       char value[AUTH_STR_MAX_LEN];
+
+       /* these are only relevant for normal sessions */
+       if (!iscsi_add_text(pdu, data, max_data_length, "InitialR2T",
+                           session->initial_r2t_en ? "Yes" : "No"))
+               return 0;
+
+       if (!iscsi_add_text(pdu, data, max_data_length,
+                           "ImmediateData",
+                           session->imm_data_en ? "Yes" : "No"))
+               return 0;
+
+       sprintf(value, "%d", session->max_burst);
+       if (!iscsi_add_text(pdu, data, max_data_length,
+                           "MaxBurstLength", value))
+               return 0;
+
+       sprintf(value, "%d",session->first_burst);
+       if (!iscsi_add_text(pdu, data, max_data_length,
+                           "FirstBurstLength", value))
+               return 0;
+
+       /* these we must have */
+       sprintf(value, "%d", session->max_r2t);
+       if (!iscsi_add_text(pdu, data, max_data_length,
+                           "MaxOutstandingR2T", value))
+               return 0;
+       if (!iscsi_add_text(pdu, data, max_data_length,
+                           "MaxConnections", "1"))
+               return 0;
+       if (!iscsi_add_text(pdu, data, max_data_length,
+                           "DataPDUInOrder", "Yes"))
+               return 0;
+       if (!iscsi_add_text(pdu, data, max_data_length,
+                           "DataSequenceInOrder", "Yes"))
+               return 0;
+       return 1;
+}
+
+static int
+add_params_transport_specific(iscsi_session_t *session, int cid,
+                            struct iscsi_hdr *pdu, char *data,
+                            int max_data_length)
+{
+       char value[AUTH_STR_MAX_LEN];
+       iscsi_conn_t *conn = &session->conn[cid];
+
+       if (session->type == ISCSI_SESSION_TYPE_DISCOVERY ||
+           !session->t->template->rdma) {
+               sprintf(value, "%d", conn->max_recv_dlength);
+               if (!iscsi_add_text(pdu, data, max_data_length,
+                                   "MaxRecvDataSegmentLength", value))
+                       return 0;
+       } else {
+               sprintf(value, "%d", conn->max_recv_dlength);
+               if (!iscsi_add_text(pdu, data, max_data_length,
+                                  "InitiatorRecvDataSegmentLength",
+                                   value))
+                       return 0;
+
+               sprintf(value, "%d", conn->max_xmit_dlength);
+               if (!iscsi_add_text(pdu, data, max_data_length,
+                                  "TargetRecvDataSegmentLength",
+                                   value))
+                       return 0;
+
+               if (!iscsi_add_text(pdu, data, max_data_length,
+                                  "RDMAExtensions", "Yes"))
+                       return 0;
+       }
+       return 1;
+}
+
+static int
+check_irrelevant_keys(iscsi_session_t *session, struct iscsi_hdr *pdu,
+                    char *data, int max_data_length)
+{
+       /* If you receive irrelevant keys, just check them from the irrelevant
+        * keys bitmap and respond with the key=Irrelevant text
+        */
+
+       if (session->irrelevant_keys_bitmap & IRRELEVANT_MAXCONNECTIONS)
+               if (!iscsi_add_text(pdu, data, max_data_length,
+                                   "MaxConnections", "Irrelevant"))
+                       return 0;
+
+       if (session->irrelevant_keys_bitmap & IRRELEVANT_INITIALR2T)
+               if (!iscsi_add_text(pdu, data, max_data_length,
+                                   "InitialR2T", "Irrelevant"))
+                       return 0;
+
+       if (session->irrelevant_keys_bitmap & IRRELEVANT_IMMEDIATEDATA)
+               if (!iscsi_add_text(pdu, data, max_data_length,
+                                   "ImmediateData", "Irrelevant"))
+                       return 0;
+
+       if (session->irrelevant_keys_bitmap & IRRELEVANT_MAXBURSTLENGTH)
+               if (!iscsi_add_text(pdu, data, max_data_length,
+                                   "MaxBurstLength", "Irrelevant"))
+                       return 0;
+
+       if (session->irrelevant_keys_bitmap & IRRELEVANT_FIRSTBURSTLENGTH)
+               if (!iscsi_add_text(pdu, data, max_data_length,
+                                   "FirstBurstLength", "Irrelevant"))
+                       return 0;
+
+       if (session->irrelevant_keys_bitmap & IRRELEVANT_MAXOUTSTANDINGR2T)
+               if (!iscsi_add_text(pdu, data, max_data_length,
+                                   "MaxOutstandingR2T", "Irrelevant"))
+                       return 0;
+
+       if (session->irrelevant_keys_bitmap & IRRELEVANT_DATAPDUINORDER)
+               if (!iscsi_add_text(pdu, data, max_data_length,
+                                   "DataPDUInOrder", "Irrelevant"))
+                       return 0;
+
+       if (session->irrelevant_keys_bitmap & IRRELEVANT_DATASEQUENCEINORDER )
+               if (!iscsi_add_text(pdu, data, max_data_length,
+                                   "DataSequenceInOrder", "Irrelevant"))
+                       return 0;
+
+       return 1;
+}
+
+static int
+fill_crc_digest_text(iscsi_conn_t *conn, struct iscsi_hdr *pdu,
+                    char *data, int max_data_length)
+{
+       switch (conn->hdrdgst_en) {
+       case ISCSI_DIGEST_NONE:
+               if (!iscsi_add_text(pdu, data, max_data_length,
+                   "HeaderDigest", "None"))
+                       return 0;
+               break;
+       case ISCSI_DIGEST_CRC32C:
+               if (!iscsi_add_text(pdu, data, max_data_length,
+                   "HeaderDigest", "CRC32C"))
+                       return 0;
+               break;
+       case ISCSI_DIGEST_CRC32C_NONE:
+               if (!iscsi_add_text(pdu, data, max_data_length,
+                   "HeaderDigest", "CRC32C,None"))
+                       return 0;
+               break;
+       default:
+       case ISCSI_DIGEST_NONE_CRC32C:
+               if (!iscsi_add_text(pdu, data, max_data_length,
+                   "HeaderDigest", "None,CRC32C"))
+                       return 0;
+               break;
+       }
+
+       switch (conn->datadgst_en) {
+       case ISCSI_DIGEST_NONE:
+               if (!iscsi_add_text(pdu, data, max_data_length,
+                   "DataDigest", "None"))
+                       return 0;
+               break;
+       case ISCSI_DIGEST_CRC32C:
+               if (!iscsi_add_text(pdu, data, max_data_length,
+                   "DataDigest", "CRC32C"))
+                       return 0;
+               break;
+       case ISCSI_DIGEST_CRC32C_NONE:
+               if (!iscsi_add_text(pdu, data, max_data_length,
+                   "DataDigest", "CRC32C,None"))
+                       return 0;
+               break;
+       default:
+       case ISCSI_DIGEST_NONE_CRC32C:
+               if (!iscsi_add_text(pdu, data, max_data_length,
+                   "DataDigest", "None,CRC32C"))
+                       return 0;
+               break;
+       }
+       return 1;
+}
+
+static int
+fill_op_params_text(iscsi_session_t *session, int cid, struct iscsi_hdr *pdu,
+                   char *data, int max_data_length, int *transit)
+{
+       char value[AUTH_STR_MAX_LEN];
+       iscsi_conn_t *conn = &session->conn[cid];
+       int rdma;
+
+       /* we always try to go from op params to full feature stage */
+       conn->current_stage = ISCSI_OP_PARMS_NEGOTIATION_STAGE;
+       conn->next_stage = ISCSI_FULL_FEATURE_PHASE;
+       *transit = 1;
+
+       rdma = (session->type == ISCSI_SESSION_TYPE_NORMAL) &&
+                       session->t->template->rdma;
+
+       /*
+        * If we haven't gotten a partial response, then either we shouldn't be
+        * here, or we just switched to this stage, and need to start offering
+        * keys.
+        */
+       if (!conn->partial_response) {
+               /*
+                * request the desired settings the first time
+                * we are in this stage
+                */
+               if (!rdma &&
+                   !fill_crc_digest_text(conn, pdu, data, max_data_length))
+                       return 0;
+
+               sprintf(value, "%d", session->def_time2wait);
+               if (!iscsi_add_text(pdu, data, max_data_length,
+                                   "DefaultTime2Wait", value))
+                       return 0;
+
+               sprintf(value, "%d", session->def_time2retain);
+               if (!iscsi_add_text(pdu, data, max_data_length,
+                                   "DefaultTime2Retain", value))
+                       return 0;
+
+               if (!iscsi_add_text(pdu, data, max_data_length,
+                                   "IFMarker", "No"))
+                       return 0;
+
+               if (!iscsi_add_text(pdu, data, max_data_length,
+                                   "OFMarker", "No"))
+                       return 0;
+
+               if (!iscsi_add_text(pdu, data, max_data_length,
+                                   "ErrorRecoveryLevel", "0"))
+                       return 0;
+
+               if (session->type == ISCSI_SESSION_TYPE_NORMAL) {
+                       if (!add_params_normal_session(session, pdu, data,
+                                                 max_data_length))
+                               return 0;
+
+                       if (!add_params_transport_specific(session, cid,
+                                                         pdu, data,
+ max_data_length))
+                               return 0;
+               } else {
+                       sprintf(value, "%d", conn->max_recv_dlength);
+                       if (!iscsi_add_text(pdu, data, max_data_length,
+                                           "MaxRecvDataSegmentLength", value))
+                               return 0;
+               }
+       } else {
+               if (!check_irrelevant_keys(session, pdu, data, max_data_length))
+                       return 0;
+
+               if (rdma &&
+                   !fill_crc_digest_text(conn, pdu, data, max_data_length))
+                       return 0;
+       }
+
+       return 1;
+}
+
+static void
+enum_auth_keys(struct iscsi_acl *auth_client, struct iscsi_hdr *pdu,
+              char *data, int max_data_length, int keytype)
+{
+       int present = 0, rc;
+       char *key = (char *)acl_get_key_name(keytype);
+       int key_length = key ? strlen(key) : 0;
+       int pdu_length = ntoh24(pdu->dlength);
+       char *auth_value = data + pdu_length + key_length + 1;
+       unsigned int max_length = max_data_length - (pdu_length
+                                         + key_length + 1);
+
+       /*
+        * add the key/value pairs the auth code wants to send
+        * directly to the PDU, since they could in theory be large.
+        */
+       rc = acl_send_key_val(auth_client, keytype, &present, auth_value,
+                             max_length);
+       if ((rc == AUTH_STATUS_NO_ERROR) && present) {
+               /* actually fill in the key */
+               strncpy(&data[pdu_length], key, key_length);
+               pdu_length += key_length;
+               data[pdu_length] = '=';
+               pdu_length++;
+               /*
+                * adjust the PDU's data segment length
+                * to include the value and trailing NUL
+                */
+               pdu_length += strlen(auth_value) + 1;
+               hton24(pdu->dlength, pdu_length);
+       }
+}
+
+static int
+fill_security_params_text(iscsi_session_t *session, int cid, struct iscsi_hdr *pdu,
+                         struct iscsi_acl *auth_client, char *data,
+                         int max_data_length, int *transit)
+{
+       int keytype = AUTH_KEY_TYPE_NONE;
+       int rc = acl_send_transit_bit(auth_client, transit);
+       iscsi_conn_t *conn = &session->conn[cid];
+
+       /* see if we're ready for a stage change */
+       if (rc != AUTH_STATUS_NO_ERROR)
+               return 0;
+
+       if (*transit) {
+               /*
+                * discovery sessions can go right to full-feature phase,
+                * unless they want to non-standard values for the few relevant
+                * keys, or want to offer vendor-specific keys
+                */
+               if (session->type == ISCSI_SESSION_TYPE_DISCOVERY)
+                       if ((conn->hdrdgst_en != ISCSI_DIGEST_NONE) ||
+                           (conn->datadgst_en != ISCSI_DIGEST_NONE) ||
+                           (conn->max_recv_dlength !=
+                           ISCSI_DEF_MAX_RECV_SEG_LEN))
+                               conn->next_stage =
+                                           ISCSI_OP_PARMS_NEGOTIATION_STAGE;
+                       else
+                               conn->next_stage = ISCSI_FULL_FEATURE_PHASE;
+               else
+                       conn->next_stage = ISCSI_OP_PARMS_NEGOTIATION_STAGE;
+       } else
+               conn->next_stage = ISCSI_SECURITY_NEGOTIATION_STAGE;
+
+       /* enumerate all the keys the auth code might want to send */
+       while (acl_get_next_key_type(&keytype) == AUTH_STATUS_NO_ERROR)
+               enum_auth_keys(auth_client, pdu, data, max_data_length,
+                              keytype);
+
+       return 1;
+}
+
+/**
+ * iscsi_make_login_pdu - Prepare the login pdu to be sent to iSCSI target.
+ * @session: session for which login is initiated.
+ * @pdu: login header
+ * @data: contains text keys to be negotiated during login
+ * @max_data_length: data size
+ *
+ * Description:
+ *     Based on whether authentication is enabled or not, corresponding text
+ *     keys are filled up in login pdu.
+ *
+ **/
+static int
+iscsi_make_login_pdu(iscsi_session_t *session, int cid, struct iscsi_hdr *hdr,
+                    char *data, int max_data_length)
+{
+       int transit = 0;
+       int ret;
+       struct iscsi_login *login_hdr = (struct iscsi_login *)hdr;
+       struct iscsi_acl *auth_client;
+       iscsi_conn_t *conn = &session->conn[cid];
+
+       auth_client = (session->num_auth_buffers > 0) ?
+               (struct iscsi_acl *)session->auth_buffers[0].address : NULL;
+
+       /* initialize the PDU header */
+       memset(login_hdr, 0, sizeof(*login_hdr));
+       login_hdr->opcode = ISCSI_OP_LOGIN | ISCSI_OP_IMMEDIATE;
+       login_hdr->cid = 0;
+       memcpy(login_hdr->isid, session->isid, sizeof(session->isid));
+       login_hdr->tsih = 0;
+       login_hdr->cmdsn = htonl(session->cmdsn);
+       /* don't increment on immediate */
+       login_hdr->min_version = ISCSI_DRAFT20_VERSION;
+       login_hdr->max_version = ISCSI_DRAFT20_VERSION;
+       login_hdr->exp_statsn = htonl(conn->exp_statsn);
+
+       /*
+        * the very first Login PDU has some additional requirements,
+        * and we need to decide what stage to start in.
+        */
+       if (conn->current_stage == ISCSI_INITIAL_LOGIN_STAGE) {
+               if (session->initiator_name && session->initiator_name[0]) {
+                       if (!iscsi_add_text(hdr, data, max_data_length,
+                            "InitiatorName", session->initiator_name))
+                               return 0;
+               } else {
+                       log_error("InitiatorName is required "
+                                      "on the first Login PDU");
+                       return 0;
+               }
+               if (session->initiator_alias && session->initiator_alias[0]) {
+                       if (!iscsi_add_text(hdr, data, max_data_length,
+                            "InitiatorAlias", session->initiator_alias))
+                               return 0;
+               }
+
+               if ((session->target_name[0] != '\0') &&
+                   (session->type == ISCSI_SESSION_TYPE_NORMAL)) {
+                       if (!iscsi_add_text(hdr, data, max_data_length,
+                           "TargetName", session->target_name))
+                               return 0;
+               }
+
+               if (!iscsi_add_text(hdr, data, max_data_length,
+                   "SessionType", (session->type ==
+                     ISCSI_SESSION_TYPE_DISCOVERY) ? "Discovery" : "Normal"))
+                       return 0;
+
+               if (auth_client)
+                       /* we're prepared to do authentication */
+                       conn->current_stage = conn->next_stage =
+                           ISCSI_SECURITY_NEGOTIATION_STAGE;
+               else
+                       /* can't do any authentication, skip that stage */
+                       conn->current_stage = conn->next_stage =
+                           ISCSI_OP_PARMS_NEGOTIATION_STAGE;
+       }
+
+       /* fill in text based on the stage */
+       switch (conn->current_stage) {
+       case ISCSI_OP_PARMS_NEGOTIATION_STAGE:{
+                       ret = fill_op_params_text(session, cid, hdr, data,
+                                                 max_data_length, &transit);
+                       if (!ret)
+                               return ret;
+                       break;
+               }
+       case ISCSI_SECURITY_NEGOTIATION_STAGE:{
+                       ret = fill_security_params_text(session, cid, hdr,
+                                       auth_client, data, max_data_length,
+                                       &transit);
+                       if (!ret)
+                               return ret;
+                       break;
+               }
+       case ISCSI_FULL_FEATURE_PHASE:
+               log_error("Can't send login PDUs in full "
+                              "feature phase");
+               return 0;
+       default:
+               log_error("Can't send login PDUs in unknown "
+                              "stage %d", conn->current_stage);
+               return 0;
+       }
+
+       /* fill in the flags */
+       login_hdr->flags = 0;
+       login_hdr->flags |= conn->current_stage << 2;
+       if (transit) {
+               /* transit to the next stage */
+               login_hdr->flags |= conn->next_stage;
+               login_hdr->flags |= ISCSI_FLAG_LOGIN_TRANSIT;
+       } else
+               /* next == current */
+               login_hdr->flags |= conn->current_stage;
+
+       return 1;
+}
+
+static enum iscsi_login_status
+check_for_authentication(iscsi_session_t *session,
+                        struct iscsi_acl *auth_client)
+{
+       enum iscsi_login_status ret = LOGIN_FAILED;
+
+       auth_client = (struct iscsi_acl *)session->auth_buffers[0].address;
+
+       /* prepare for authentication */
+       if (acl_init(TYPE_INITIATOR, session->num_auth_buffers,
+                    session->auth_buffers) != AUTH_STATUS_NO_ERROR) {
+               log_error("Couldn't initialize authentication");
+               return LOGIN_FAILED;
+       }
+
+       if ((session->username[0] != '\0') &&
+           (acl_set_user_name(auth_client, session->username) !=
+            AUTH_STATUS_NO_ERROR)) {
+               log_error("Couldn't set username");
+               goto end;
+       }
+
+       if ((session->password[0] != '\0') &&
+                   (acl_set_passwd(auth_client, session->password, session->password_length) !=
+            AUTH_STATUS_NO_ERROR)) {
+               log_error("Couldn't set password");
+               goto end;
+       }
+
+       int value_list[AUTH_CHAP_ALG_MAX_COUNT];
+
+       if (acl_set_chap_alg_list(auth_client,
+                               acl_init_chap_digests(value_list,
+                                       session->chap_algs,
+                                       AUTH_CHAP_ALG_MAX_COUNT),
+                               value_list) != AUTH_STATUS_NO_ERROR) {
+               log_error("Couldn't set CHAP algorithm list");
+               goto end;
+       }
+
+       if (acl_set_ip_sec(auth_client, 1) != AUTH_STATUS_NO_ERROR) {
+               log_error("Couldn't set IPSec");
+               goto end;
+       }
+
+       if (acl_set_auth_rmt(auth_client, session->bidirectional_auth) !=
+                            AUTH_STATUS_NO_ERROR) {
+               log_error("Couldn't set remote authentication");
+               goto end;
+       }
+       return LOGIN_OK;
+
+ end:
+       if (auth_client && acl_finish(auth_client) != AUTH_STATUS_NO_ERROR) {
+               log_error("Login failed, error finishing auth_client");
+               if (ret == LOGIN_OK)
+                       ret = LOGIN_FAILED;
+       }
+       return ret;
+}
+
+static enum iscsi_login_status
+check_status_login_response(iscsi_session_t *session, int cid,
+                           struct iscsi_login_rsp *login_rsp,
+                           char *data, int max_data_length, int *final)
+{
+       enum iscsi_login_status ret;
+
+       switch (login_rsp->status_class) {
+       case ISCSI_STATUS_CLS_SUCCESS:
+               /* process this response and possibly continue sending PDUs */
+               ret = iscsi_process_login_response(session, cid, login_rsp,
+                                                  data, max_data_length);
+               if (ret != LOGIN_OK)    /* pass back whatever
+                                        * error we discovered
+                                        */
+                       *final = 1;
+               break;
+       case ISCSI_STATUS_CLS_REDIRECT:
+               /*
+                * we need to process this response to get the
+                * TargetAddress of the redirect, but we don't care
+                * about the return code.
+                */
+               iscsi_process_login_response(session, cid, login_rsp,
+                                            data, max_data_length);
+               ret = LOGIN_REDIRECT;
+               *final = 1;
+               break;
+       case ISCSI_STATUS_CLS_INITIATOR_ERR:
+               if (login_rsp->status_detail ==
+                   ISCSI_LOGIN_STATUS_AUTH_FAILED) {
+                       log_error("Login failed to authenticate "
+                                      "with target %s", session->target_name);
+               }
+               ret = LOGIN_OK;
+               *final = 1;
+               break;
+       default:
+               /*
+                * some sort of error, login terminated unsuccessfully,
+                * though this function did it's job.
+                * the caller must check the status_class and
+                * status_detail and decide what to do next.
+                */
+               ret = LOGIN_OK;
+               *final = 1;
+       }
+       return ret;
+}
+
+int
+iscsi_login_begin(iscsi_session_t *session, iscsi_login_context_t *c)
+{
+       iscsi_conn_t *conn = &session->conn[c->cid];
+
+       c->auth_client = NULL;
+       c->login_rsp = (struct iscsi_login_rsp *)&c->pdu;
+       c->received_pdu = 0;
+       c->timeout = 0;
+       c->final = 0;
+       c->ret = LOGIN_FAILED;
+
+       /* prepare the session of the connection is leading */
+       if (c->cid ==0) {
+               session->cmdsn = 1;
+               session->exp_cmdsn = 1;
+               session->max_cmdsn = 1;
+       }
+
+       conn->current_stage = ISCSI_INITIAL_LOGIN_STAGE;
+       conn->partial_response = 0;
+
+       if (session->num_auth_buffers > 0) {
+               c->ret = check_for_authentication(session, c->auth_client);
+               if (c->ret != LOGIN_OK)
+                       return 1;
+       }
+
+       return 0;
+}
+
+int
+iscsi_login_req(iscsi_session_t *session, iscsi_login_context_t *c)
+{
+       iscsi_conn_t *conn = &session->conn[c->cid];
+
+       c->final = 0;
+       c->timeout = 0;
+       c->login_rsp = (struct iscsi_login_rsp *)&c->pdu;
+       c->ret = LOGIN_FAILED;
+
+       memset(c->buffer, 0, c->bufsize);
+       c->data = c->buffer;
+       c->max_data_length = c->bufsize;
+
+       /*
+        * pick the appropriate timeout. If we know the target has
+        * responded before, and we're in the security stage, we use a
+        * longer timeout, since the authentication alogorithms can
+        * take a while, especially if the target has to go talk to a
+        * tacacs or RADIUS server (which may or may not be
+        * responding).
+        */
+       if (c->received_pdu && (conn->current_stage ==
+               ISCSI_SECURITY_NEGOTIATION_STAGE))
+               c->timeout = conn->auth_timeout;
+       else
+               c->timeout = conn->login_timeout;
+
+       /*
+        * fill in the PDU header and text data based on the login
+        * stage that we're in
+        */
+       if (!iscsi_make_login_pdu(session, c->cid, &c->pdu, c->data,
+                                 c->max_data_length)) {
+               log_error("login failed, couldn't make a login PDU");
+               c->ret = LOGIN_FAILED;
+               goto done;
+       }
+
+       /* send a PDU to the target */
+       if (!iscsi_io_send_pdu(conn, &c->pdu, ISCSI_DIGEST_NONE,
+                           c->data, ISCSI_DIGEST_NONE, c->timeout)) {
+               /*
+                * FIXME: caller might want us to distinguish I/O
+                * error and timeout. Might want to switch portals on
+                * timeouts, but not I/O errors.
+                */
+               log_error("Login I/O error, failed to send a PDU");
+               c->ret = LOGIN_IO_ERROR;
+               goto done;
+       }
+       return 0;
+
+ done:
+       if (c->auth_client && acl_finish(c->auth_client) !=
+           AUTH_STATUS_NO_ERROR) {
+               log_error("Login failed, error finishing c->auth_client");
+               if (c->ret == LOGIN_OK)
+                       c->ret = LOGIN_FAILED;
+       }
+       return 1;
+}
+
+int
+iscsi_login_rsp(iscsi_session_t *session, iscsi_login_context_t *c)
+{
+       iscsi_conn_t *conn = &session->conn[c->cid];
+       int err;
+
+       /* read the target's response into the same buffer */
+       err = iscsi_io_recv_pdu(conn, &c->pdu, ISCSI_DIGEST_NONE, c->data,
+                               c->max_data_length, ISCSI_DIGEST_NONE,
+                               c->timeout);
+       if (err == -EAGAIN) {
+               goto done;
+       } else if (err < 0) {
+               /*
+                * FIXME: caller might want us to distinguish I/O
+                * error and timeout. Might want to switch portals on
+                * timeouts, but not I/O errors.
+                */
+               log_error("Login I/O error, failed to receive a PDU");
+               c->ret = LOGIN_IO_ERROR;
+               goto done;
+       }
+
+       err = -EIO;
+       c->received_pdu = 1;
+
+       /* check the PDU response type */
+       if (c->pdu.opcode == (ISCSI_OP_LOGIN_RSP | 0xC0)) {
+               /*
+                * it's probably a draft 8 login response,
+                * which we can't deal with
+                */
+               log_error("Received iSCSI draft 8 login "
+                         "response opcode 0x%x, expected draft "
+                         "20 login response 0x%2x",
+                         c->pdu.opcode, ISCSI_OP_LOGIN_RSP);
+               c->ret = LOGIN_VERSION_MISMATCH;
+               goto done;
+       } else if (c->pdu.opcode != ISCSI_OP_LOGIN_RSP) {
+               c->ret = LOGIN_INVALID_PDU;
+               goto done;
+       }
+
+       /*
+        * give the caller the status class and detail from the last
+        * login response PDU received
+        */
+       c->status_class = c->login_rsp->status_class;
+       c->status_detail = c->login_rsp->status_detail;
+       log_debug(1, "login response status %02d%02d",
+                       c->status_class, c->status_detail);
+       c->ret = check_status_login_response(session, c->cid,
+                    c->login_rsp, c->data, c->max_data_length,
+                    &c->final);
+       if (c->final)
+               goto done;
+       return 0;
+
+ done:
+       if (c->auth_client && acl_finish(c->auth_client) !=
+           AUTH_STATUS_NO_ERROR) {
+               log_error("Login failed, error finishing c->auth_client");
+               if (c->ret == LOGIN_OK)
+                       c->ret = LOGIN_FAILED;
+       }
+       return err;
+}
+
+/**
+ * iscsi_login - attempt to login to the target.
+ * @session: login is initiated over this session
+ * @buffer: holds login pdu
+ * @bufsize: size of login pdu
+ * @status_class: holds either success or failure as status of login
+ * @status_detail: contains details based on the login status
+ *
+ * Description:
+ *     The caller must check the status class to determine if the login
+ *     succeeded. A return of 1 does not mean the login succeeded, it just
+ *     means this function worked, and the status class is valid info.
+ *     This allows the caller to decide whether or not to retry logins, so
+ *     that we don't have any policy logic here.
+ **/
+enum iscsi_login_status
+iscsi_login(iscsi_session_t *session, int cid, char *buffer, size_t bufsize,
+           uint8_t *status_class, uint8_t *status_detail)
+{
+       iscsi_conn_t *conn = &session->conn[cid];
+       iscsi_login_context_t *c = &conn->login_context;
+       struct timeval connection_timer;
+       struct pollfd pfd;
+       int ret, timeout;
+
+       /*
+        * assume iscsi_login is only called from discovery, so it is
+        * safe to always set to zero
+        */
+       conn->exp_statsn = 0;
+
+       c->cid = cid;
+       c->buffer = buffer;
+       c->bufsize = bufsize;
+
+       if (iscsi_login_begin(session, c))
+               return c->ret;
+
+       do {
+               if (iscsi_login_req(session, c))
+                       return c->ret;
+
+               /*
+                * TODO: merge the poll and req/rsp code with the discovery
+                * poll and text req/rsp.
+                */
+               iscsi_timer_set(&connection_timer,
+                               session->conn[0].active_timeout);
+               timeout = iscsi_timer_msecs_until(&connection_timer);
+
+               memset(&pfd, 0, sizeof (pfd));
+               pfd.fd = conn->socket_fd;
+               pfd.events = POLLIN | POLLPRI;
+
+repoll:
+               pfd.revents = 0;
+               ret = poll(&pfd, 1, timeout);
+               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 response PDU.",
+                                   session->conn[0].active_timeout);
+                       c->ret = LOGIN_FAILED;
+                       return c->ret;
+               }
+
+               if (ret > 0) {
+                       if (pfd.revents & (POLLIN | POLLPRI)) {
+                               ret = iscsi_login_rsp(session, c);
+                               if (ret ==  -EAGAIN)
+                                       goto repoll;
+
+                               if (status_class)
+                                       *status_class = c->status_class;
+                               if (status_detail)
+                                       *status_detail = c->status_detail;
+
+                               if (ret)
+                                       return c->ret;
+                       } else if (pfd.revents & POLLHUP) {
+                               log_warning("Login POLLHUP");
+                               c->ret = LOGIN_FAILED;
+                               return c->ret;
+                       } else if (pfd.revents & POLLNVAL) {
+                               log_warning("Login POLLNVAL");
+                               c->ret = LOGIN_IO_ERROR;
+                               return c->ret;
+                       } else if (pfd.revents & POLLERR) {
+                               log_warning("Login POLLERR");
+                               c->ret = LOGIN_IO_ERROR;
+                               return c->ret;
+                       }
+
+               } else if (ret < 0) {
+                       log_error("Login poll error.");
+                       c->ret = LOGIN_FAILED;
+                       return c->ret;
+               }
+       } while (conn->current_stage != ISCSI_FULL_FEATURE_PHASE);
+
+       c->ret = LOGIN_OK;
+       if (c->auth_client && acl_finish(c->auth_client) !=
+           AUTH_STATUS_NO_ERROR) {
+               log_error("Login failed, error finishing c->auth_client");
+               if (c->ret == LOGIN_OK)
+                       c->ret = LOGIN_FAILED;
+       }
+
+       return c->ret;
+}
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/mgmt_ipc.c b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/mgmt_ipc.c
new file mode 100644 (file)
index 0000000..0ee513f
--- /dev/null
@@ -0,0 +1,590 @@
+/*
+ * iSCSI Administrator Utility Socket Interface
+ *
+ * Copyright (C) 2004 Dmitry Yusupov, Alex Aizman
+ * Copyright (C) 2006 Mike Christie
+ * Copyright (C) 2006 Red Hat, Inc. All rights reserved.
+ * maintained by open-iscsi@googlegroups.com
+ *
+ * Originally based on:
+ * (C) 2004 FUJITA Tomonori <tomof@acm.org>
+ *
+ * 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 <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <sys/un.h>
+#include <string.h>
+#include <stdbool.h>
+
+#include "iscsid.h"
+#include "idbm.h"
+#include "mgmt_ipc.h"
+#include "event_poll.h"
+#include "log.h"
+#include "transport.h"
+#include "sysdeps.h"
+#include "iscsi_ipc.h"
+#include "iscsi_err.h"
+#include "iscsi_util.h"
+#include "iscsid_req.h"
+
+#define PEERUSER_MAX   64
+#define EXTMSG_MAX     (64 * 1024)
+#define SD_SOCKET_FDS_START 3
+
+int
+mgmt_ipc_listen(void)
+{
+       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;
+       }
+
+       addr_len = setup_abstract_addr(&addr, iscsid_namespace);
+
+       if ((err = bind(fd, (struct sockaddr *) &addr, addr_len)) < 0 ) {
+               log_error("Can not bind IPC socket");
+               close(fd);
+               return err;
+       }
+
+       if ((err = listen(fd, 32)) < 0) {
+               log_error("Can not listen IPC socket");
+               close(fd);
+               return err;
+       }
+
+       return fd;
+}
+
+int mgmt_ipc_systemd(void)
+{
+       const char *env;
+
+       env = getenv("LISTEN_PID");
+
+       if (!env || ((pid_t)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)
+{
+       event_loop_exit(NULL);
+       if (fd >= 0)
+               close(fd);
+}
+
+static int 
+mgmt_ipc_session_login(queue_task_t *qtask)
+{
+       return session_login_task(&qtask->req.u.session.rec, qtask);
+}
+
+static int
+mgmt_ipc_session_getstats(queue_task_t *qtask)
+{
+       int sid = qtask->req.u.session.sid;
+       iscsi_session_t *session;
+       int rc;
+
+       if (!(session = session_find_by_sid(sid)))
+               return ISCSI_ERR_SESS_NOT_FOUND;
+
+       rc = ipc->get_stats(session->t->handle,
+               session->id, session->conn[0].id,
+               (void *)&qtask->rsp.u.getstats,
+               MGMT_IPC_GETSTATS_BUF_MAX);
+       if (rc) {
+               log_error("get_stats(): IPC error %d "
+                       "session [%02d]", rc, sid);
+               return ISCSI_ERR_INTERNAL;
+       }
+
+       mgmt_ipc_write_rsp(qtask, ISCSI_SUCCESS);
+       return ISCSI_SUCCESS;
+}
+
+static int
+mgmt_ipc_send_targets(queue_task_t *qtask)
+{
+       iscsiadm_req_t *req = &qtask->req;
+       int err;
+
+       err = iscsi_host_send_targets(qtask, req->u.st.host_no,
+                                         req->u.st.do_login,
+                                         &req->u.st.ss);
+       mgmt_ipc_write_rsp(qtask, err);
+       return ISCSI_SUCCESS;
+}
+
+static int
+mgmt_ipc_session_logout(queue_task_t *qtask)
+{
+       return session_logout_task(qtask->req.u.session.sid, qtask);
+}
+
+static int
+mgmt_ipc_session_sync(queue_task_t *qtask)
+{
+       struct ipc_msg_session *session= &qtask->req.u.session;
+
+       return iscsi_sync_session(&session->rec, qtask, session->sid);
+}
+
+static int
+mgmt_ipc_cfg_initiatorname(queue_task_t *qtask)
+{
+       if (dconfig->initiator_name)
+               strcpy(qtask->rsp.u.config.var, dconfig->initiator_name);
+       mgmt_ipc_write_rsp(qtask, ISCSI_SUCCESS);
+       return ISCSI_SUCCESS;
+}
+
+static int
+mgmt_ipc_session_info(queue_task_t *qtask)
+{
+       int sid = qtask->req.u.session.sid;
+       iscsi_session_t *session;
+       struct ipc_msg_session_state *info;
+
+       if (!(session = session_find_by_sid(sid))) {
+               log_debug(1, "session with sid %d not found!", sid);
+               return ISCSI_ERR_SESS_NOT_FOUND;
+       }
+
+       info = &qtask->rsp.u.session_state;
+       info->conn_state = session->conn[0].state;
+       info->session_state = session->r_stage;
+
+       mgmt_ipc_write_rsp(qtask, ISCSI_SUCCESS);
+       return ISCSI_SUCCESS;
+}
+
+static int
+mgmt_ipc_cfg_initiatoralias(queue_task_t *qtask)
+{
+       strcpy(qtask->rsp.u.config.var, dconfig->initiator_alias);
+       mgmt_ipc_write_rsp(qtask, ISCSI_SUCCESS);
+       return ISCSI_SUCCESS;
+}
+
+static int
+mgmt_ipc_cfg_filename(queue_task_t *qtask)
+{
+       strcpy(qtask->rsp.u.config.var, dconfig->config_file);
+       mgmt_ipc_write_rsp(qtask, ISCSI_SUCCESS);
+       return ISCSI_SUCCESS;
+}
+
+static int
+mgmt_ipc_conn_add(__attribute__((unused))queue_task_t *qtask)
+{
+       return ISCSI_ERR;
+}
+
+static int
+mgmt_ipc_immediate_stop(queue_task_t *qtask)
+{
+       event_loop_exit(qtask);
+       return ISCSI_SUCCESS;
+}
+
+static int
+mgmt_ipc_conn_remove(__attribute__((unused))queue_task_t *qtask)
+{
+       return ISCSI_ERR;
+}
+
+/*
+ * Parse a list of strings, encoded as a 32bit
+ * length followed by the string itself (not necessarily
+ * NUL-terminated).
+ */
+static int
+mgmt_ipc_parse_strings(queue_task_t *qtask, char ***result)
+{
+       char            *data, *endp, **argv = NULL;
+       unsigned int    left, argc;
+
+again:
+       data = qtask->payload;
+       left = qtask->req.payload_len;
+       endp = NULL;
+       argc = 0;
+
+       while (left) {
+               uint32_t len;
+
+               if (left < 4)
+                       return -1;
+               memcpy(&len, data, 4);
+               data += 4;
+
+               if (endp)
+                       *endp = '\0';
+
+               if (len > left)
+                       return -1;
+
+               if (argv) {
+                       argv[argc] = (char *) data;
+                       endp = data + len;
+               }
+               data += len;
+               argc++;
+       }
+
+       if (endp)
+               *endp = '\0';
+
+       if (argv == NULL) {
+               argv = malloc((argc + 1) * sizeof(char *));
+               *result = argv;
+               goto again;
+       }
+
+       argv[argc] = NULL;
+       return argc;
+}
+
+static int
+mgmt_ipc_notify_common(queue_task_t *qtask, int (*handler)(int, char **))
+{
+       char    **argv = NULL;
+       int     argc, err = ISCSI_ERR;
+
+       argc = mgmt_ipc_parse_strings(qtask, &argv);
+       if (argc > 0)
+               err = handler(argc, argv);
+
+       if (argv)
+               free(argv);
+       mgmt_ipc_write_rsp(qtask, err);
+       return ISCSI_SUCCESS;
+}
+
+/* Replace these dummies as you implement them
+   elsewhere */
+static int
+iscsi_discovery_add_node(__attribute__((unused))int argc,
+                        __attribute__((unused))char **argv)
+{
+       return ISCSI_SUCCESS;
+}
+
+static int
+iscsi_discovery_del_node(__attribute__((unused))int argc,
+                        __attribute__((unused))char **argv)
+{
+       return ISCSI_SUCCESS;
+}
+
+static int
+iscsi_discovery_add_portal(__attribute__((unused))int argc,
+                          __attribute__((unused))char **argv)
+{
+       return ISCSI_SUCCESS;
+}
+
+static int
+iscsi_discovery_del_portal(__attribute__((unused))int argc,
+                          __attribute__((unused))char **argv)
+{
+       return ISCSI_SUCCESS;
+}
+
+static int
+mgmt_ipc_notify_add_node(queue_task_t *qtask)
+{
+       return mgmt_ipc_notify_common(qtask, iscsi_discovery_add_node);
+}
+
+static int
+mgmt_ipc_notify_del_node(queue_task_t *qtask)
+{
+       return mgmt_ipc_notify_common(qtask, iscsi_discovery_del_node);
+}
+
+static int
+mgmt_ipc_notify_add_portal(queue_task_t *qtask)
+{
+       return mgmt_ipc_notify_common(qtask, iscsi_discovery_add_portal);
+}
+
+static int
+mgmt_ipc_notify_del_portal(queue_task_t *qtask)
+{
+       return mgmt_ipc_notify_common(qtask, iscsi_discovery_del_portal);
+}
+
+static int
+mgmt_peeruser(int sock, char *user)
+{
+       /* Linux style: use getsockopt(SO_PEERCRED) */
+       struct ucred peercred;
+       socklen_t so_len = sizeof(peercred);
+       struct passwd *pass;
+
+       errno = 0;
+       if (getsockopt(sock, SOL_SOCKET, SO_PEERCRED, &peercred,
+               &so_len) != 0 || so_len != sizeof(peercred)) {
+               /* We didn't get a valid credentials struct. */
+               log_error("peeruser_unux: error receiving credentials: %m");
+               return 0;
+       }
+
+       pass = getpwuid(peercred.uid);
+       if (pass == NULL) {
+               log_error("peeruser_unix: unknown local user with uid %d",
+                               (int) peercred.uid);
+               return 0;
+       }
+
+       strlcpy(user, pass->pw_name, PEERUSER_MAX);
+       return 1;
+}
+
+static bool
+mgmt_authorized_uid(int sock)
+{
+       int authorized = false;
+       struct ucred peercred = {0};
+       socklen_t so_len = sizeof(peercred);
+
+       errno = 0;
+       if (getsockopt(sock, SOL_SOCKET, SO_PEERCRED, &peercred,
+               &so_len) != 0 || so_len != sizeof(peercred)) {
+               /* We didn't get a valid credentials struct. */
+               log_error("Error receiving credentials: %m");
+               goto ret_auth;
+       }
+
+       /* Only UID==0 is authorized */
+       authorized = peercred.uid ? false: true;
+
+       if (!authorized) {
+               log_error("Unauthorized user with UID=%u", peercred.uid);
+       }
+
+ret_auth:
+       return authorized;
+}
+
+static void
+mgmt_ipc_destroy_queue_task(queue_task_t *qtask)
+{
+       if (qtask->mgmt_ipc_fd >= 0)
+               close(qtask->mgmt_ipc_fd);
+       if (qtask->payload)
+               free(qtask->payload);
+       if (qtask->allocated)
+               free(qtask);
+}
+
+/*
+ * Send the IPC response and destroy the queue_task.
+ * The recovery code uses a qtask which is allocated as
+ * part of a larger structure, and we don't want it to
+ * get freed when we come here. This is what qtask->allocated
+ * is for.
+ */
+void
+mgmt_ipc_write_rsp(queue_task_t *qtask, int err)
+{
+       if (!qtask)
+               return;
+       log_debug(4, "%s: rsp to fd %d", __FUNCTION__,
+                qtask->mgmt_ipc_fd);
+
+       if (qtask->mgmt_ipc_fd < 0) {
+               mgmt_ipc_destroy_queue_task(qtask);
+               return;
+       }
+
+       qtask->rsp.err = err;
+       if (write(qtask->mgmt_ipc_fd, &qtask->rsp, sizeof(qtask->rsp)) < 0) {
+               if (qtask->conn && qtask->conn->session)
+                       conn_error(qtask->conn, "IPC qtask write failed: %s", strerror(errno));
+               else
+                       log_error("IPC qtask write failed: %s", strerror(errno));
+       }
+       mgmt_ipc_destroy_queue_task(qtask);
+}
+
+static int
+mgmt_ipc_read_data(int fd, void *ptr, size_t len)
+{
+       int     n;
+
+       while (len) {
+               n = read(fd, ptr, len);
+               if (n < 0) {
+                       if (errno == EINTR)
+                               continue;
+                       return -EIO;
+               }
+               if (n == 0) {
+                       /* Client closed connection */
+                       return -EIO;
+               }
+               ptr += n;
+               len -= n;
+       }
+       return 0;
+}
+
+static int
+mgmt_ipc_read_req(queue_task_t *qtask)
+{
+       iscsiadm_req_t *req = &qtask->req;
+       int     rc;
+
+       rc = mgmt_ipc_read_data(qtask->mgmt_ipc_fd, req, sizeof(*req));
+       if (rc >= 0 && req->payload_len > 0) {
+               /* Limit what we accept */
+               if (req->payload_len > EXTMSG_MAX)
+                       return -EIO;
+
+               /* Remember the allocated pointer in the
+                * qtask - it will be freed by write_rsp.
+                * Note: we allocate one byte in excess
+                * so we can append a NULL byte. */
+               qtask->payload = malloc(req->payload_len + 1);
+               if (!qtask->payload)
+                       return -ENOMEM;
+
+               rc = mgmt_ipc_read_data(qtask->mgmt_ipc_fd,
+                               qtask->payload,
+                               req->payload_len);
+       }
+       return rc;
+}
+
+static mgmt_ipc_fn_t * mgmt_ipc_functions[__MGMT_IPC_MAX_COMMAND] = {
+[MGMT_IPC_SESSION_LOGIN]       = mgmt_ipc_session_login,
+[MGMT_IPC_SESSION_LOGOUT]      = mgmt_ipc_session_logout,
+[MGMT_IPC_SESSION_SYNC]                = mgmt_ipc_session_sync,
+[MGMT_IPC_SESSION_STATS]       = mgmt_ipc_session_getstats,
+[MGMT_IPC_SEND_TARGETS]                = mgmt_ipc_send_targets,
+[MGMT_IPC_SESSION_INFO]                = mgmt_ipc_session_info,
+[MGMT_IPC_CONN_ADD]            = mgmt_ipc_conn_add,
+[MGMT_IPC_CONN_REMOVE]         = mgmt_ipc_conn_remove,
+[MGMT_IPC_CONFIG_INAME]                = mgmt_ipc_cfg_initiatorname,
+[MGMT_IPC_CONFIG_IALIAS]       = mgmt_ipc_cfg_initiatoralias,
+[MGMT_IPC_CONFIG_FILE]         = mgmt_ipc_cfg_filename,
+[MGMT_IPC_IMMEDIATE_STOP]      = mgmt_ipc_immediate_stop,
+[MGMT_IPC_NOTIFY_ADD_NODE]     = mgmt_ipc_notify_add_node,
+[MGMT_IPC_NOTIFY_DEL_NODE]     = mgmt_ipc_notify_del_node,
+[MGMT_IPC_NOTIFY_ADD_PORTAL]   = mgmt_ipc_notify_add_portal,
+[MGMT_IPC_NOTIFY_DEL_PORTAL]   = mgmt_ipc_notify_del_portal,
+};
+
+static void mgmt_ipc_handle_check_auth(int accept_fd, bool auth_uid_only)
+{
+       unsigned int command;
+       int fd, err;
+       queue_task_t *qtask = NULL;
+       mgmt_ipc_fn_t *handler = NULL;
+       char user[PEERUSER_MAX];
+
+       qtask = calloc(1, sizeof(queue_task_t));
+       if (!qtask)
+               return;
+
+       if ((fd = accept(accept_fd, NULL, NULL)) < 0) {
+               free(qtask);
+               return;
+       }
+
+       qtask->allocated = 1;
+       qtask->mgmt_ipc_fd = fd;
+
+       if (auth_uid_only) {
+               if (!mgmt_authorized_uid(fd)) {
+                       err = ISCSI_ERR_ACCESS;
+                       goto err;
+               }
+       } else {
+               if (!mgmt_peeruser(fd, user) || strncmp(user, "root", PEERUSER_MAX)) {
+                       err = ISCSI_ERR_ACCESS;
+                       goto err;
+               }
+       }
+
+       if (mgmt_ipc_read_req(qtask) < 0) {
+               mgmt_ipc_destroy_queue_task(qtask);
+               return;
+       }
+
+       command = qtask->req.command;
+       qtask->rsp.command = command;
+
+       if (command > 0 &&
+           command < __MGMT_IPC_MAX_COMMAND)
+               handler = mgmt_ipc_functions[command];
+
+       if (handler != NULL) {
+               /* If the handler returns OK, this means it
+                * already sent the reply. */
+               err = handler(qtask);
+               if (err == ISCSI_SUCCESS)
+                       return;
+       } else {
+               log_error("unknown request: %s(%d) %u",
+                         __FUNCTION__, __LINE__, command);
+               err = ISCSI_ERR_INVALID_MGMT_REQ;
+       }
+
+err:
+       /* This will send the response, close the
+        * connection and free the qtask */
+       mgmt_ipc_write_rsp(qtask, err);
+}
+
+void mgmt_ipc_handle(int accept_fd)
+{
+       /* Default behavior. Full auth check. */
+       mgmt_ipc_handle_check_auth(accept_fd, false);
+}
+
+void mgmt_ipc_handle_uid_only(int accept_fd)
+{
+       /* Check only originating UID. */
+       mgmt_ipc_handle_check_auth(accept_fd, true);
+}
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/mgmt_ipc.h b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/mgmt_ipc.h
new file mode 100644 (file)
index 0000000..cc6ef1b
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * iSCSI Daemon/Admin Management IPC
+ *
+ * Copyright (C) 2004 Dmitry Yusupov, Alex Aizman
+ * 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 MGMT_IPC_H
+#define MGMT_IPC_H
+
+#include "types.h"
+#include "iscsi_if.h"
+#include "config.h"
+
+#define ISCSIADM_NAMESPACE     "ISCSIADM_ABSTRACT_NAMESPACE"
+#define PEERUSER_MAX           64
+
+typedef enum iscsiadm_cmd {
+       MGMT_IPC_UNKNOWN                = 0,
+       MGMT_IPC_SESSION_LOGIN          = 1,
+       MGMT_IPC_SESSION_LOGOUT         = 2,
+       MGMT_IPC_SESSION_ACTIVESTAT     = 4,
+       MGMT_IPC_CONN_ADD               = 5,
+       MGMT_IPC_CONN_REMOVE            = 6,
+       MGMT_IPC_SESSION_STATS          = 7,
+       MGMT_IPC_CONFIG_INAME           = 8,
+       MGMT_IPC_CONFIG_IALIAS          = 9,
+       MGMT_IPC_CONFIG_FILE            = 10,
+       MGMT_IPC_IMMEDIATE_STOP         = 11,
+       MGMT_IPC_SESSION_SYNC           = 12,
+       MGMT_IPC_SESSION_INFO           = 13,
+       MGMT_IPC_ISNS_DEV_ATTR_QUERY    = 14,
+       MGMT_IPC_SEND_TARGETS           = 15,
+       MGMT_IPC_NOTIFY_ADD_NODE        = 16,
+       MGMT_IPC_NOTIFY_DEL_NODE        = 17,
+       MGMT_IPC_NOTIFY_ADD_PORTAL      = 18,
+       MGMT_IPC_NOTIFY_DEL_PORTAL      = 19,
+
+       __MGMT_IPC_MAX_COMMAND
+} iscsiadm_cmd_e;
+
+/* IPC Request */
+typedef struct iscsiadm_req {
+       iscsiadm_cmd_e command;
+       uint32_t payload_len;
+
+       union {
+               /* messages */
+               struct ipc_msg_session {
+                       int sid;
+                       node_rec_t rec;
+               } session;
+               struct ipc_msg_conn {
+                       int sid;
+                       int cid;
+               } conn;
+               struct ipc_msg_send_targets {
+                       int host_no;
+                       int do_login;
+                       struct sockaddr_storage ss;
+               } st;
+               struct ipc_msg_set_host_param {
+                       int host_no;
+                       int param;
+                       /* TODO: make this variable len to support */
+                       char value[IFNAMSIZ + 1];
+
+               } set_host_param;
+       } u;
+} iscsiadm_req_t;
+
+/* IPC Response */
+typedef struct iscsiadm_rsp {
+       iscsiadm_cmd_e command;
+       int err;        /* ISCSI_ERR value */
+
+       union {
+#define MGMT_IPC_GETSTATS_BUF_MAX      (sizeof(struct iscsi_uevent) + \
+                                       sizeof(struct iscsi_stats) + \
+                                       sizeof(struct iscsi_stats_custom) * \
+                                               ISCSI_STATS_CUSTOM_MAX)
+               struct ipc_msg_getstats {
+                       struct iscsi_uevent ev;
+                       struct iscsi_stats stats;
+                       char custom[sizeof(struct iscsi_stats_custom) *
+                                       ISCSI_STATS_CUSTOM_MAX];
+               } getstats;
+               struct ipc_msg_config {
+                       char var[VALUE_MAXLEN];
+               } config;
+               struct ipc_msg_session_state {
+                       int session_state;
+                       int conn_state;
+               } session_state;
+       } u;
+} iscsiadm_rsp_t;
+
+struct queue_task;
+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);
+void mgmt_ipc_handle_uid_only(int accept_fd);
+
+#endif /* MGMT_IPC_H */
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/mntcheck.c b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/mntcheck.c
new file mode 100644 (file)
index 0000000..6ae03e0
--- /dev/null
@@ -0,0 +1,233 @@
+/*
+ * Common code for checking sessions for mnt use
+ *
+ * Copyright (C) 2014 - 2015 Chris Leech
+ * Copyright (C) 2014 - 2015 Red Hat, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * See the file COPYING included with this distribution for more details.
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <dirent.h>
+#include <libmount/libmount.h>
+
+#include "initiator.h"
+#include "transport.h"
+#include "iscsid.h"
+#include "iscsi_ipc.h"
+#include "log.h"
+#include "iscsi_sysfs.h"
+#include "iscsi_settings.h"
+#include "iface.h"
+#include "host.h"
+#include "sysdeps.h"
+#include "iscsi_err.h"
+#include "iscsi_net_util.h"
+
+static struct libmnt_table *mtab, *swaps;
+static struct libmnt_cache *mntcache;
+
+static void libmount_cleanup(void)
+{
+       mnt_free_table(mtab);
+       mnt_free_table(swaps);
+       mnt_free_cache(mntcache);
+       mtab = NULL;
+       swaps = NULL;
+       mntcache = NULL;
+}
+
+static int libmount_init(void)
+{
+       mnt_init_debug(0);
+       mtab = mnt_new_table();
+       swaps = mnt_new_table();
+       mntcache = mnt_new_cache();
+       if (!mtab || !swaps || !mntcache) {
+               libmount_cleanup();
+               return -ENOMEM;
+       }
+       mnt_table_set_cache(mtab, mntcache);
+       mnt_table_set_cache(swaps, mntcache);
+       mnt_table_parse_mtab(mtab, NULL);
+       mnt_table_parse_swaps(swaps, NULL);
+       return 0;
+}
+
+static int trans_filter(const struct dirent *d)
+{
+       if (!strcmp(".", d->d_name) || !strcmp("..", d->d_name))
+               return 0;
+       return 1;
+}
+
+static int subdir_filter(const struct dirent *d)
+{
+       if (!(d->d_type & DT_DIR))
+               return 0;
+       return trans_filter(d);
+}
+
+static int is_partition(const char *path)
+{
+       char *devtype;
+       int rc = 0;
+
+       devtype = sysfs_get_uevent_devtype(path);
+       if (!devtype)
+               return 0;
+       if (strcmp(devtype, "partition") == 0)
+               rc = 1;
+       free(devtype);
+       return rc;
+}
+
+static int blockdev_check_mnts(char *syspath)
+{
+       struct libmnt_fs *fs;
+       char *devname = NULL;
+       char *_devname = NULL;
+       int rc = 0;
+
+       devname = sysfs_get_uevent_devname(syspath);
+       if (!devname)
+               goto out;
+
+       _devname = calloc(1, PATH_MAX);
+       if (!_devname)
+               goto out;
+       snprintf(_devname, PATH_MAX, "/dev/%s", devname);
+
+       fs = mnt_table_find_source(mtab, _devname, MNT_ITER_FORWARD);
+       if (fs) {
+               rc = 1;
+               goto out;
+       }
+       fs = mnt_table_find_source(swaps, _devname, MNT_ITER_FORWARD);
+       if (fs)
+               rc = 1;
+out:
+       free(devname);
+       free(_devname);
+       return rc;
+}
+
+static int count_device_users(char *syspath);
+
+static int blockdev_get_partitions(char *syspath)
+{
+       struct dirent **parts = NULL;
+       int n, i;
+       int count = 0;
+
+       n = scandir(syspath, &parts, subdir_filter, alphasort);
+       for (i = 0; i < n; i++) {
+               char *newpath;
+
+               newpath = calloc(1, PATH_MAX);
+               if (!newpath)
+                       continue;
+               snprintf(newpath, PATH_MAX, "%s/%s", syspath, parts[i]->d_name);
+               free(parts[i]);
+               if (is_partition(newpath)) {
+                       count += count_device_users(newpath);
+               }
+               free(newpath);
+       }
+       free(parts);
+       return count;
+}
+
+static int blockdev_get_holders(char *syspath)
+{
+       char *path = NULL;
+       struct dirent **holds = NULL;
+       int n, i;
+       int count = 0;
+
+       path = calloc(1, PATH_MAX);
+       if (!path)
+               return 0;
+       snprintf(path, PATH_MAX, "%s/holders", syspath);
+
+       n = scandir(path, &holds, trans_filter, alphasort);
+       for (i = 0; i < n; i++) {
+               char *newpath;
+               char *rp;
+
+               newpath = calloc(1, PATH_MAX);
+               if (!newpath)
+                       continue;
+               snprintf(newpath, PATH_MAX, "%s/%s", path, holds[i]->d_name);
+
+               free(holds[i]);
+               rp = realpath(newpath, NULL);
+               if (rp)
+                       count += count_device_users(rp);
+               free(newpath);
+               free(rp);
+       }
+       free(path);
+       free(holds);
+       return count;
+}
+
+static int count_device_users(char *syspath)
+{
+       int count = 0;
+       count += blockdev_check_mnts(syspath);
+       count += blockdev_get_partitions(syspath);
+       count += blockdev_get_holders(syspath);
+       return count;
+};
+
+static void device_in_use(void *data, int host_no, int target, int lun)
+{
+       char *syspath = NULL;
+       char *devname = NULL;
+       int *count = data;
+
+       devname = iscsi_sysfs_get_blockdev_from_lun(host_no, target, lun);
+       if (!devname)
+               goto out;
+       syspath = calloc(1, PATH_MAX);
+       if (!syspath)
+               goto out;
+       snprintf(syspath, PATH_MAX, "/sys/class/block/%s", devname);
+       *count += count_device_users(syspath);
+out:
+       free(syspath);
+       free(devname);
+}
+
+int session_in_use(int sid)
+{
+       int host_no = -1, err = 0;
+       int count = 0;
+
+       if (libmount_init()) {
+               log_error("Failed to initialize libmount, "
+                         "not checking for active mounts on session [%d].", sid);
+               return 0;
+       }
+
+       host_no = iscsi_sysfs_get_host_no_from_sid(sid, &err);
+       if (!err)
+               iscsi_sysfs_for_each_device(&count, host_no, sid, device_in_use);
+
+       libmount_cleanup();
+       return count;
+}
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/netlink.c b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/netlink.c
new file mode 100644 (file)
index 0000000..22cad83
--- /dev/null
@@ -0,0 +1,1801 @@
+/*
+ * iSCSI Netlink/Linux Interface
+ *
+ * Copyright (C) 2004 Dmitry Yusupov, Alex Aizman
+ * Copyright (C) 2006 Mike Christie
+ * Copyright (C) 2006 Red Hat, Inc. All rights reserved.
+ * 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 <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <errno.h>
+#include <time.h>
+#include <inttypes.h>
+#include <asm/types.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <poll.h>
+#include <linux/netlink.h>
+
+#include "types.h"
+#include "iscsi_if.h"
+#include "log.h"
+#include "iscsi_ipc.h"
+#include "initiator.h"
+#include "iscsi_sysfs.h"
+#include "transport.h"
+#include "iscsi_netlink.h"
+#include "iscsi_err.h"
+#include "iscsi_timer.h"
+
+static int ctrl_fd;
+static struct sockaddr_nl src_addr, dest_addr;
+static void *xmitbuf = NULL;
+static int xmitlen = 0;
+static void *recvbuf = NULL;
+static int recvlen = 0;
+static void *nlm_sendbuf;
+static void *nlm_recvbuf;
+static void *pdu_sendbuf;
+static void *setparam_buf;
+static struct iscsi_ipc_ev_clbk *ipc_ev_clbk;
+
+static int ctldev_handle(void);
+
+#define NLM_BUF_DEFAULT_MAX (NLMSG_SPACE(ISCSI_DEF_MAX_RECV_SEG_LEN +  \
+                                       sizeof(struct iscsi_uevent) +   \
+                                       sizeof(struct iscsi_hdr)))
+
+#define PDU_SENDBUF_DEFAULT_MAX        (ISCSI_DEF_MAX_RECV_SEG_LEN +           \
+                                       sizeof(struct iscsi_uevent) +   \
+                                       sizeof(struct iscsi_hdr))
+
+#define NLM_SETPARAM_DEFAULT_MAX (NI_MAXHOST + 1 + sizeof(struct iscsi_uevent))
+
+struct iscsi_ping_event {
+       uint32_t host_no;
+       uint32_t pid;
+       int32_t status;
+       int active;
+};
+
+struct iscsi_ping_event ping_event;
+
+struct nlattr *iscsi_nla_alloc(uint16_t type, uint16_t len)
+{
+       struct nlattr *attr;
+
+       attr = calloc(1, ISCSI_NLA_TOTAL_LEN(len));
+       if (!attr)
+               return NULL; 
+
+       attr->nla_len = ISCSI_NLA_LEN(len);
+       attr->nla_type = type;
+       return attr;
+}
+
+static int
+kread(char *data, int count)
+{
+       log_debug(7, "in %s %u %u %p %p", __FUNCTION__, recvlen, count,
+                 data, recvbuf);
+
+       memcpy(data, recvbuf + recvlen, count);
+       recvlen += count;
+       return count;
+}
+
+static int
+nl_read(int ctrl_fd, char *data, int size, int flags)
+{
+       int rc;
+       struct iovec iov;
+       struct msghdr msg;
+
+       log_debug(7, "in %s", __FUNCTION__);
+
+       iov.iov_base = data;
+       iov.iov_len = size;
+
+       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
+nlpayload_read(int ctrl_fd, char *data, int count, int flags)
+{
+       int rc;
+       struct iovec iov;
+       struct msghdr msg;
+
+       log_debug(7, "in %s", __FUNCTION__);
+
+       iov.iov_base = nlm_recvbuf;
+       iov.iov_len = NLMSG_SPACE(count);
+
+       if (iov.iov_len > NLM_BUF_DEFAULT_MAX) {
+               log_error("Cannot read %zu bytes. nlm_recvbuf too small.",
+                         iov.iov_len);
+               return -1;
+       }
+       memset(iov.iov_base, 0, iov.iov_len);
+
+       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;
+
+       /*
+        * Netlink recvmsg call path:
+        *
+        *  - transport api callback
+        *  - iscsi_control_conn_error (should succeed)
+        *  - iscsi_unicast_skb (must succeed)
+        *  - netlink_unicast (must succeed)
+        *  - netlink_data_ready (must succeed)
+        *  - netlink_sendskb (must succeed)
+        *  - netlink_recvmsg (must succeed)
+        *  - sock_recvmsg (must succeed)
+        *  - sys_recvmsg (must succeed)
+        *  - sys_socketcall (must succeed)
+        *  - syscall_call (must succeed)
+        *
+        *  Note1: "must succeed" means succeed unless bug in daemon.
+        *        It also means - no sleep and memory allocation on
+        *        the path.
+        *
+        *  Note2: "should succeed" means will succeed in most of cases
+        *        because of mempool preallocation.
+        *
+        *  FIXME: if "Note2" than interface should generate iSCSI error
+        *        level 0 on its own. Interface must always succeed on this.
+        */
+       rc = recvmsg(ctrl_fd, &msg, flags);
+
+       if (data)
+               memcpy(data, NLMSG_DATA(iov.iov_base), count);
+
+       return rc;
+}
+
+static int
+kwritev(enum iscsi_uevent_e type, struct iovec *iovp, int count)
+{
+       int i, rc;
+       struct nlmsghdr *nlh;
+       struct msghdr msg;
+       int datalen = 0;
+
+       log_debug(7, "in %s", __FUNCTION__);
+
+       for (i = 0; i < count; i++) {
+               datalen += iovp[i].iov_len;
+       }
+
+       if (xmitbuf && type != ISCSI_UEVENT_SEND_PDU) {
+               for (i = 0; i < count; i++) {
+                       memcpy(xmitbuf + xmitlen,
+                              iovp[i].iov_base, iovp[i].iov_len);
+                       xmitlen += iovp[i].iov_len;
+               }
+               return datalen;
+       }
+
+       nlh = nlm_sendbuf;
+       memset(nlh, 0, NLMSG_SPACE(0));
+
+       datalen = 0;
+       for (i = 1; i < count; i++)
+               datalen += iovp[i].iov_len;
+
+       nlh->nlmsg_len = datalen + sizeof(*nlh);
+       nlh->nlmsg_pid = getpid();
+       nlh->nlmsg_flags = 0;
+       nlh->nlmsg_type = type;
+
+       iovp[0].iov_base = (void *)nlh;
+       iovp[0].iov_len = sizeof(*nlh);
+
+       memset(&msg, 0, sizeof(msg));
+       msg.msg_name= (void*)&dest_addr;
+       msg.msg_namelen = sizeof(dest_addr);
+       msg.msg_iov = iovp;
+       msg.msg_iovlen = count;
+
+       do {
+               /*
+                * Netlink down call path:
+                *
+                *  - transport api call
+                *  - iscsi_if_recv_msg (must succeed)
+                *  - iscsi_if_rx (must succeed)
+                *  - netlink_data_ready (must succeed)
+                *  - netlink_sendskb (must succeed)
+                *  - netlink_sendmsg (alloc_skb() might fail)
+                *  - sock_sendmsg (must succeed)
+                *  - sys_sendmsg (must succeed)
+                *  - sys_socketcall (must succeed)
+                *  - syscall_call (must succeed)
+                *
+                *  Note1: "must succeed" means succeed unless bug in daemon.
+                *        It also means - no sleep and memory allocation on
+                *        the path.
+                *
+                *  Note2: netlink_sendmsg() might fail because of OOM. Since
+                *         we are in user-space, we will sleep until we succeed.
+                */
+
+               rc = sendmsg(ctrl_fd, &msg, 0);
+               if (rc == -ENOMEM) {
+                       log_debug(1, "sendmsg: alloc_skb() failed");
+                       sleep(1);
+               } else if (rc < 0) {
+                       log_error("sendmsg: bug? ctrl_fd %d", ctrl_fd);
+                       exit(rc);
+               }
+       } while (rc < 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)
+ */
+static int
+__kipc_call(struct iovec *iovp, int count)
+{
+       int rc, iferr;
+       struct iscsi_uevent *ev = iovp[1].iov_base;
+       enum iscsi_uevent_e type = ev->type;
+
+       log_debug(7, "in %s", __FUNCTION__);
+
+       rc = kwritev(type, iovp, count);
+
+       do {
+               if ((rc = nlpayload_read(ctrl_fd, (void*)ev,
+                                        sizeof(*ev), MSG_PEEK)) < 0) {
+                       return rc;
+               }
+               if (ev->type != type) {
+                       log_debug(1, "expecting event %d, got %d, handling...",
+                                 type, ev->type);
+                       if (ev->type == ISCSI_KEVENT_IF_ERROR) {
+                               if ((rc = nlpayload_read(ctrl_fd, (void*)ev,
+                                                        sizeof(*ev), 0)) < 0) {
+                                       return rc;
+                               }
+                               /*
+                                * iferror is u32, but the kernel returns
+                                * negative errno values for errors.
+                                */
+                               iferr = ev->iferror;
+
+                               if (iferr == -ENOSYS)
+                                       /* not fatal so let caller handle log */
+                                       log_debug(1, "Received iferror %d: %s.",
+                                                 iferr, strerror(-iferr));
+                               else if (iferr < 0)
+                                       log_error("Received iferror %d: %s.",
+                                                  iferr, strerror(-iferr));
+                               else
+                                       log_error("Received iferror %d.",
+                                                  iferr);
+                               return ev->iferror;
+                       }
+                       /*
+                        * receive and queue async. event which as of
+                        * today could be:
+                        *      - CONN_ERROR
+                        *      - RECV_PDU
+                        */
+                       ctldev_handle();
+               } else if (ev->type == ISCSI_UEVENT_GET_STATS) {
+                       /* kget_stats() will read */
+                       return 0;
+               } 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) {
+                               return rc;
+                       }
+                       break;
+               }
+       } while (ev->type != type);
+
+       return rc;
+}
+
+static int
+ksendtargets(uint64_t transport_handle, uint32_t host_no, struct sockaddr *addr)
+{
+       int rc, addrlen;
+       struct iscsi_uevent *ev;
+       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_TGT_DSCVR;
+       ev->transport_handle = transport_handle;
+       ev->u.tgt_dscvr.type = ISCSI_TGT_DSCVR_SEND_TARGETS;
+       ev->u.tgt_dscvr.host_no = host_no;
+
+       if (addr->sa_family == PF_INET)
+               addrlen = sizeof(struct sockaddr_in);
+       else if (addr->sa_family == PF_INET6)
+               addrlen = sizeof(struct sockaddr_in6);
+       else {
+               log_error("%s unknown addr family %d",
+                         __FUNCTION__, addr->sa_family);
+               return -EINVAL;
+       }
+       memcpy(setparam_buf + sizeof(*ev), addr, addrlen);
+
+       iov[1].iov_base = ev;
+       iov[1].iov_len = sizeof(*ev) + addrlen;
+       rc = __kipc_call(iov, 2);
+       if (rc < 0) {
+               log_error("sendtargets failed rc%d", rc);
+               return rc;
+       }
+       return 0;
+}
+
+static int
+kcreate_session(uint64_t transport_handle, uint64_t ep_handle,
+               uint32_t initial_cmdsn, uint16_t cmds_max, uint16_t qdepth,
+               uint32_t *out_sid, uint32_t *hostno)
+{
+       int rc;
+       struct iscsi_uevent ev;
+       struct iovec iov[2];
+
+       log_debug(7, "in %s", __FUNCTION__);
+
+       memset(&ev, 0, sizeof(struct iscsi_uevent));
+
+       if (ep_handle == 0) {
+               ev.type = ISCSI_UEVENT_CREATE_SESSION;
+               ev.transport_handle = transport_handle;
+               ev.u.c_session.initial_cmdsn = initial_cmdsn;
+               ev.u.c_session.cmds_max = cmds_max;
+               ev.u.c_session.queue_depth = qdepth;
+       } else {
+               ev.type = ISCSI_UEVENT_CREATE_BOUND_SESSION;
+               ev.transport_handle = transport_handle;
+               ev.u.c_bound_session.initial_cmdsn = initial_cmdsn;
+               ev.u.c_bound_session.cmds_max = cmds_max;
+               ev.u.c_bound_session.queue_depth = qdepth;
+               ev.u.c_bound_session.ep_handle = ep_handle;
+       }
+
+       iov[1].iov_base = &ev;
+       iov[1].iov_len = sizeof(ev);
+       rc = __kipc_call(iov, 2);
+       if (rc < 0)
+               return rc;
+
+       *hostno = ev.r.c_session_ret.host_no;
+       *out_sid = ev.r.c_session_ret.sid;
+
+       return 0;
+}
+
+static int
+kdestroy_session(uint64_t transport_handle, uint32_t sid)
+{
+       int rc;
+       struct iscsi_uevent ev;
+       struct iovec iov[2];
+
+       log_debug(7, "in %s", __FUNCTION__);
+
+       memset(&ev, 0, sizeof(struct iscsi_uevent));
+
+       ev.type = ISCSI_UEVENT_DESTROY_SESSION;
+       ev.transport_handle = transport_handle;
+       ev.u.d_session.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
+kunbind_session(uint64_t transport_handle, uint32_t sid)
+{
+       int rc;
+       struct iscsi_uevent ev;
+       struct iovec iov[2];
+
+       log_debug(7, "in %s", __FUNCTION__);
+
+       memset(&ev, 0, sizeof(struct iscsi_uevent));
+
+       ev.type = ISCSI_UEVENT_UNBIND_SESSION;
+       ev.transport_handle = transport_handle;
+       ev.u.d_session.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
+kcreate_conn(uint64_t transport_handle, uint32_t sid,
+           uint32_t cid, uint32_t *out_cid)
+{
+       int rc;
+       struct iscsi_uevent ev;
+       struct iovec iov[2];
+
+       log_debug(7, "in %s", __FUNCTION__);
+
+       memset(&ev, 0, sizeof(struct iscsi_uevent));
+
+       ev.type = ISCSI_UEVENT_CREATE_CONN;
+       ev.transport_handle = transport_handle;
+       ev.u.c_conn.cid = cid;
+       ev.u.c_conn.sid = sid;
+
+       iov[1].iov_base = &ev;
+       iov[1].iov_len = sizeof(ev);
+       rc = __kipc_call(iov, 2);
+       if (rc < 0) {
+               log_debug(7, "returned %d", rc);
+               return rc;
+       }
+
+       if ((int)ev.r.c_conn_ret.cid == -1)
+               return -EIO;
+
+       *out_cid = ev.r.c_conn_ret.cid;
+       return 0;
+}
+
+static int
+kdestroy_conn(uint64_t transport_handle, uint32_t sid, uint32_t cid)
+{
+       int rc;
+       struct iscsi_uevent ev;
+       struct iovec iov[2];
+
+       log_debug(7, "in %s", __FUNCTION__);
+
+       memset(&ev, 0, sizeof(struct iscsi_uevent));
+
+       ev.type = ISCSI_UEVENT_DESTROY_CONN;
+       ev.transport_handle = transport_handle;
+       ev.u.d_conn.sid = sid;
+       ev.u.d_conn.cid = cid;
+
+       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
+kbind_conn(uint64_t transport_handle, uint32_t sid, uint32_t cid,
+         uint64_t transport_eph, int is_leading, int *retcode)
+{
+       int rc;
+       struct iscsi_uevent ev;
+       struct iovec iov[2];
+
+       log_debug(7, "in %s", __FUNCTION__);
+
+       memset(&ev, 0, sizeof(struct iscsi_uevent));
+
+       ev.type = ISCSI_UEVENT_BIND_CONN;
+       ev.transport_handle = transport_handle;
+       ev.u.b_conn.sid = sid;
+       ev.u.b_conn.cid = cid;
+       ev.u.b_conn.transport_eph = transport_eph;
+       ev.u.b_conn.is_leading = is_leading;
+
+       iov[1].iov_base = &ev;
+       iov[1].iov_len = sizeof(ev);
+       rc = __kipc_call(iov, 2);
+       if (rc < 0)
+               return rc;
+
+       *retcode = ev.r.retcode;
+
+       return 0;
+}
+
+static void
+ksend_pdu_begin(uint64_t transport_handle, uint32_t sid, uint32_t cid,
+                       int hdr_size, int data_size)
+{
+       struct iscsi_uevent *ev;
+       int total_xmitlen = sizeof(*ev) + hdr_size + data_size;
+
+       log_debug(7, "in %s", __FUNCTION__);
+
+       if (xmitbuf) {
+               log_error("send's begin state machine bug?");
+               exit(-EIO);
+       }
+
+       if (total_xmitlen > (int)PDU_SENDBUF_DEFAULT_MAX) {
+               log_error("BUG: Cannot send %d bytes.", total_xmitlen);
+               exit(-EINVAL);
+       }
+
+       xmitbuf = pdu_sendbuf;
+       memset(xmitbuf, 0, total_xmitlen);
+       xmitlen = sizeof(*ev);
+       ev = xmitbuf;
+       memset(ev, 0, sizeof(*ev));
+       ev->type = ISCSI_UEVENT_SEND_PDU;
+       ev->transport_handle = transport_handle;
+       ev->u.send_pdu.sid = sid;
+       ev->u.send_pdu.cid = cid;
+       ev->u.send_pdu.hdr_size = hdr_size;
+       ev->u.send_pdu.data_size = data_size;
+
+       log_debug(3, "send PDU began for hdr %d bytes and data %d bytes",
+               hdr_size, data_size);
+}
+
+static int
+ksend_pdu_end(__attribute__((unused))uint64_t transport_handle,
+             uint32_t sid, uint32_t cid, int *retcode)
+{
+       int rc;
+       struct iscsi_uevent *ev;
+       struct iovec iov[2];
+
+       log_debug(7, "in %s", __FUNCTION__);
+
+       if (!xmitbuf) {
+               log_error("send's end state machine bug?");
+               exit(-EIO);
+       }
+       ev = xmitbuf;
+       if (ev->u.send_pdu.sid != sid || ev->u.send_pdu.cid != cid) {
+               log_error("send's end state machine corruption?");
+               exit(-EIO);
+       }
+
+       iov[1].iov_base = xmitbuf;
+       iov[1].iov_len = xmitlen;
+
+       rc = __kipc_call(iov, 2);
+       if (rc < 0)
+               goto err;
+       if (ev->r.retcode) {
+               *retcode = ev->r.retcode;
+               goto err;
+       }
+       if (ev->type != ISCSI_UEVENT_SEND_PDU) {
+               log_error("bad event: bug on send_pdu_end?");
+               exit(-EIO);
+       }
+
+       log_debug(3, "send PDU finished for conn %d:%d",
+                 sid, cid);
+
+       xmitbuf = NULL;
+       return 0;
+
+err:
+       xmitbuf = NULL;
+       xmitlen = 0;
+       return rc;
+}
+
+static int
+kset_host_param(uint64_t transport_handle, uint32_t host_no,
+               enum iscsi_host_param param, void *value, int type)
+{
+       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_SET_HOST_PARAM;
+       ev->transport_handle = transport_handle;
+       ev->u.set_host_param.host_no = host_no;
+       ev->u.set_host_param.param = param;
+
+       param_str = setparam_buf + sizeof(*ev);
+       switch (type) {
+       case ISCSI_INT:
+               sprintf(param_str, "%d", *((int *)value));
+               break;
+       case ISCSI_STRING:
+               if (!strlen(value))
+                       return 0;
+               sprintf(param_str, "%s", (char *)value);
+               break;
+       default:
+               log_error("invalid type %d", type);
+               return -EINVAL;
+       }
+       ev->u.set_host_param.len = len = strlen(param_str) + 1;
+
+       iov[1].iov_base = ev;
+       iov[1].iov_len = sizeof(*ev) + len;
+       rc = __kipc_call(iov, 2);
+       if (rc < 0)
+               return rc;
+
+       return 0;
+}
+
+static int
+kset_param(uint64_t transport_handle, uint32_t sid, uint32_t cid,
+          enum iscsi_param param, void *value, int type)
+{
+       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_SET_PARAM;
+       ev->transport_handle = transport_handle;
+       ev->u.set_param.sid = sid;
+       ev->u.set_param.cid = cid;
+       ev->u.set_param.param = param;
+
+       param_str = setparam_buf + sizeof(*ev);
+       switch (type) {
+       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", type);
+               return -EINVAL;
+       }
+       ev->u.set_param.len = len = strlen(param_str) + 1;
+
+       iov[1].iov_base = ev;
+       iov[1].iov_len = sizeof(*ev) + len;
+       rc = __kipc_call(iov, 2);
+       if (rc < 0)
+               return rc;
+
+       return 0;
+}
+
+static int
+kstop_conn(uint64_t transport_handle, uint32_t sid, uint32_t cid, int flag)
+{
+       int rc;
+       struct iscsi_uevent ev;
+       struct iovec iov[2];
+
+       log_debug(7, "in %s", __FUNCTION__);
+
+       memset(&ev, 0, sizeof(struct iscsi_uevent));
+
+       ev.type = ISCSI_UEVENT_STOP_CONN;
+       ev.transport_handle = transport_handle;
+       ev.u.stop_conn.sid = sid;
+       ev.u.stop_conn.cid = cid;
+       ev.u.stop_conn.flag = flag;
+
+       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
+kstart_conn(uint64_t transport_handle, uint32_t sid, uint32_t cid,
+           int *retcode)
+{
+       int rc;
+       struct iscsi_uevent ev;
+       struct iovec iov[2];
+
+       log_debug(7, "in %s", __FUNCTION__);
+
+       memset(&ev, 0, sizeof(struct iscsi_uevent));
+
+       ev.type = ISCSI_UEVENT_START_CONN;
+       ev.transport_handle = transport_handle;
+       ev.u.start_conn.sid = sid;
+       ev.u.start_conn.cid = cid;
+
+       iov[1].iov_base = &ev;
+       iov[1].iov_len = sizeof(ev);
+       rc = __kipc_call(iov, 2);
+       if (rc < 0)
+               return rc;
+
+       *retcode = ev.r.retcode;
+       return 0;
+}
+
+static int
+krecv_pdu_begin(struct iscsi_conn *conn)
+{
+       int rc;
+
+       log_debug(7, "in %s", __FUNCTION__);
+
+       if (recvbuf) {
+               log_error("recv's begin state machine bug?");
+               return -EIO;
+       }
+
+       if (!conn->recv_context) {
+               rc = ipc->ctldev_handle();
+               if (rc == -ENXIO)
+                       /* event for some other conn */
+                       return -EAGAIN;
+               else if (rc < 0)
+                       /* fatal handling error or conn error */
+                       return rc;
+               /*
+                * Session create/destroy event for another conn
+                */
+               if (!conn->recv_context)
+                       return -EAGAIN;
+       }
+
+       recvbuf = conn->recv_context->data + sizeof(struct iscsi_uevent);
+       recvlen = 0;
+
+       log_debug(3, "recv PDU began, pdu handle %p", recvbuf);
+       return 0;
+}
+
+static int
+krecv_pdu_end(struct iscsi_conn *conn)
+{
+       log_debug(7, "in %s", __FUNCTION__);
+
+       if (!recvbuf) {
+               log_error("recv's end state machine bug?");
+               return -EIO;
+       }
+
+       log_debug(3, "recv PDU finished for pdu handle 0x%p",
+                 recvbuf);
+
+       ipc_ev_clbk->put_ev_context(conn->recv_context);
+       conn->recv_context = NULL;
+       recvbuf = NULL;
+       return 0;
+}
+
+int
+ktransport_ep_connect(iscsi_conn_t *conn, int non_blocking)
+{
+       int rc, addrlen;
+       struct iscsi_uevent *ev;
+       struct sockaddr *dst_addr = (struct sockaddr *)&conn->saddr;
+       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->transport_handle = conn->session->t->handle;
+
+       if (conn->bind_ep) {
+               ev->type = ISCSI_UEVENT_TRANSPORT_EP_CONNECT_THROUGH_HOST;
+               ev->u.ep_connect_through_host.non_blocking = non_blocking;
+               ev->u.ep_connect_through_host.host_no = conn->session->hostno;
+       } else {
+               ev->type = ISCSI_UEVENT_TRANSPORT_EP_CONNECT;
+               ev->u.ep_connect.non_blocking = non_blocking;
+       }
+
+       if (dst_addr->sa_family == PF_INET)
+               addrlen = sizeof(struct sockaddr_in);
+       else if (dst_addr->sa_family == PF_INET6)
+               addrlen = sizeof(struct sockaddr_in6);
+       else {
+               log_error("%s unknown addr family %d",
+                        __FUNCTION__, dst_addr->sa_family);
+               return -EINVAL;
+       }
+       memcpy(setparam_buf + sizeof(*ev), dst_addr, addrlen);
+
+       iov[1].iov_base = ev;
+       iov[1].iov_len = sizeof(*ev) + addrlen;
+       rc = __kipc_call(iov, 2);
+       if (rc < 0)
+               return rc;
+
+       if (!ev->r.ep_connect_ret.handle)
+               return -EIO;
+
+       conn->transport_ep_handle = ev->r.ep_connect_ret.handle;
+
+       log_debug(6, "%s got handle %llx",
+               __FUNCTION__, (unsigned long long)conn->transport_ep_handle);
+       return 0;
+}
+
+int
+ktransport_ep_poll(iscsi_conn_t *conn, int timeout_ms)
+{
+       int rc;
+       struct iscsi_uevent ev;
+       struct iovec iov[2];
+
+       log_debug(7, "in %s", __FUNCTION__);
+
+       memset(&ev, 0, sizeof(struct iscsi_uevent));
+
+       ev.type = ISCSI_UEVENT_TRANSPORT_EP_POLL;
+       ev.transport_handle = conn->session->t->handle;
+       ev.u.ep_poll.ep_handle  = conn->transport_ep_handle;
+       ev.u.ep_poll.timeout_ms = timeout_ms;
+
+       iov[1].iov_base = &ev;
+       iov[1].iov_len = sizeof(ev);
+       rc = __kipc_call(iov, 2);
+       if (rc < 0)
+               return rc;
+
+       return ev.r.retcode;
+}
+
+void
+ktransport_ep_disconnect(iscsi_conn_t *conn)
+{
+       int rc;
+       struct iscsi_uevent ev;
+       struct iovec iov[2];
+
+       log_debug(7, "in %s", __FUNCTION__);
+
+       if (conn->transport_ep_handle == (uint64_t)-1)
+               return;
+
+       memset(&ev, 0, sizeof(struct iscsi_uevent));
+
+       ev.type = ISCSI_UEVENT_TRANSPORT_EP_DISCONNECT;
+       ev.transport_handle = conn->session->t->handle;
+       ev.u.ep_disconnect.ep_handle = conn->transport_ep_handle;
+
+       iov[1].iov_base = &ev;
+       iov[1].iov_len = sizeof(ev);
+       rc = __kipc_call(iov, 2);
+       if (rc < 0) {
+               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
+               conn->transport_ep_handle = -1;
+}
+
+static int
+kget_stats(uint64_t transport_handle, uint32_t sid, uint32_t cid,
+          char *statsbuf, int statsbuf_max)
+{
+       int rc;
+       int ev_size;
+       struct iscsi_uevent ev;
+       char nlm_ev[NLMSG_SPACE(sizeof(struct iscsi_uevent))];
+       struct nlmsghdr *nlh;
+       struct iovec iov[2];
+
+       log_debug(7, "in %s", __FUNCTION__);
+
+       memset(&ev, 0, sizeof(struct iscsi_uevent));
+
+       ev.type = ISCSI_UEVENT_GET_STATS;
+       ev.transport_handle = transport_handle;
+       ev.u.get_stats.sid = sid;
+       ev.u.get_stats.cid = cid;
+
+       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));
+
+       log_debug(6, "message real length is %d bytes", nlh->nlmsg_len);
+
+       if (ev_size > statsbuf_max) {
+               log_error("destanation buffer for statistics is "
+                       "not big enough to fit %d bytes", statsbuf_max);
+               ev_size = statsbuf_max;
+       }
+
+       if ((rc = nlpayload_read(ctrl_fd, (void*)statsbuf, ev_size, 0)) < 0) {
+               log_error("can not read from NL socket, error %d", rc);
+               return rc;
+       }
+
+       return 0;
+}
+
+static int
+kset_net_config(uint64_t transport_handle, uint32_t host_no,
+               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_IFACE_PARAMS;
+       ev.transport_handle = transport_handle;
+       ev.u.set_iface_params.host_no = host_no;
+       /* first two iovs for nlmsg hdr and ev */
+       ev.u.set_iface_params.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 krecv_conn_state(struct iscsi_conn *conn, uint32_t *state)
+{
+       int rc;
+
+       rc = ipc->ctldev_handle();
+       if (rc == -ENXIO) {
+               /* event for some other conn */
+               rc = -EAGAIN;
+               goto exit;
+       } else if (rc < 0)
+               /* 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);
+       conn->recv_context = NULL;
+
+exit:
+       return rc;
+}
+
+
+
+
+static int
+ksend_ping(uint64_t transport_handle, uint32_t host_no, struct sockaddr *addr,
+          uint32_t iface_num, uint32_t iface_type, uint32_t pid, uint32_t size)
+{
+       int rc, addrlen;
+       struct iscsi_uevent *ev;
+       struct iovec iov[2];
+
+       log_debug(8, "in %s", __FUNCTION__);
+
+       memset(setparam_buf, 0, NLM_SETPARAM_DEFAULT_MAX);
+       ev = (struct iscsi_uevent *)setparam_buf;
+       ev->type = ISCSI_UEVENT_PING;
+       ev->transport_handle = transport_handle;
+       ev->u.iscsi_ping.host_no = host_no;
+       ev->u.iscsi_ping.iface_num = iface_num;
+       ev->u.iscsi_ping.iface_type = iface_type;
+       ev->u.iscsi_ping.payload_size = size;
+       ev->u.iscsi_ping.pid = pid;
+
+       if (addr->sa_family == PF_INET)
+               addrlen = sizeof(struct sockaddr_in);
+       else if (addr->sa_family == PF_INET6)
+               addrlen = sizeof(struct sockaddr_in6);
+       else {
+               log_error("%s unknown addr family %d",
+                         __FUNCTION__, addr->sa_family);
+               return -EINVAL;
+       }
+       memcpy(setparam_buf + sizeof(*ev), addr, addrlen);
+
+       iov[1].iov_base = ev;
+       iov[1].iov_len = sizeof(*ev) + addrlen;
+       rc = __kipc_call(iov, 2);
+       if (rc < 0)
+               return rc;
+
+       return 0;
+}
+
+static int kexec_ping(uint64_t transport_handle, uint32_t host_no,
+                     struct sockaddr *addr, uint32_t iface_num,
+                     uint32_t iface_type, uint32_t size, uint32_t *status)
+{
+       struct pollfd pfd;
+       struct timeval ping_timer;
+       int timeout, fd, rc;
+       uint32_t pid;
+
+       *status = 0;
+
+       fd = ipc->ctldev_open();
+       if (fd < 0) {
+               log_error("Could not open netlink socket.");
+               return ISCSI_ERR;
+       }
+
+       /* prepare to poll */
+       memset(&pfd, 0, sizeof(pfd));
+       pfd.fd = fd;
+       pfd.events = POLLIN | POLLPRI;
+
+       /* get unique ping id */
+       pid = rand();
+
+       rc = ksend_ping(transport_handle, host_no, addr, iface_num,
+                       iface_type, pid, size);
+       if (rc != 0) {
+               switch (rc) {
+               case -ENOSYS:
+                       rc = ISCSI_ERR_OP_NOT_SUPP;
+                       break;
+               case -EINVAL:
+                       rc = ISCSI_ERR_INVAL;
+                       break;
+               default:
+                       rc = ISCSI_ERR;
+               }
+               goto close_nl;
+       }
+
+       ping_event.host_no = -1;
+       ping_event.pid = -1;
+       ping_event.status = -1;
+       ping_event.active = -1;
+
+       iscsi_timer_set(&ping_timer, 30);
+
+       timeout = iscsi_timer_msecs_until(&ping_timer);
+
+       while (1) {
+               pfd.revents = 0;
+               rc = poll(&pfd, 1, timeout);
+
+               if (iscsi_timer_expired(&ping_timer)) {
+                       rc = ISCSI_ERR_TRANS_TIMEOUT;
+                       break;
+               }
+
+               if (rc > 0) {
+                       if (pfd.revents & (POLLIN | POLLPRI)) {
+                               timeout = iscsi_timer_msecs_until(&ping_timer);
+                               rc = ipc->ctldev_handle();
+
+                               if (ping_event.active != 1)
+                                       continue;
+
+                               if (pid != ping_event.pid)
+                                       continue;
+
+                               rc = 0;
+                               *status = ping_event.status;
+                               break;
+                       }
+
+                       if (pfd.revents & POLLHUP) {
+                               rc = ISCSI_ERR_TRANS;
+                               break;
+                       }
+
+                       if (pfd.revents & POLLNVAL) {
+                               rc = ISCSI_ERR_INTERNAL;
+                               break;
+                       }
+
+                       if (pfd.revents & POLLERR) {
+                               rc = ISCSI_ERR_INTERNAL;
+                               break;
+                       }
+               } else if (rc < 0) {
+                       rc = ISCSI_ERR_INTERNAL;
+                       break;
+               }
+       }
+
+close_nl:
+       ipc->ctldev_close();
+       return rc;
+}
+
+static int kget_chap(uint64_t transport_handle, uint32_t host_no,
+                    uint16_t chap_tbl_idx, uint32_t num_entries,
+                    char *chap_buf, uint32_t *valid_chap_entries)
+{
+       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_CHAP;
+       ev.transport_handle = transport_handle;
+       ev.u.get_chap.host_no = host_no;
+       ev.u.get_chap.chap_tbl_idx = chap_tbl_idx;
+       ev.u.get_chap.num_entries = num_entries;
+
+       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 *)chap_buf, ev_size, 0)) < 0) {
+               log_error("can not read from NL socket, error %d", rc);
+               return rc;
+       }
+
+       *valid_chap_entries = ev.u.get_chap.num_entries;
+
+       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)
+{
+       int rc = 0;
+       struct iscsi_uevent ev;
+       struct iovec iov[2];
+
+       memset(&ev, 0, sizeof(struct iscsi_uevent));
+
+       ev.type = ISCSI_UEVENT_DELETE_CHAP;
+       ev.transport_handle = transport_handle;
+       ev.u.delete_chap.host_no = host_no;
+       ev.u.delete_chap.chap_tbl_idx = chap_tbl_idx;
+
+       iov[1].iov_base = &ev;
+       iov[1].iov_len = sizeof(ev);
+
+       rc = __kipc_call(iov, 2);
+       if (rc < 0)
+               return rc;
+
+       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;
+
+       ev_size = nlh->nlmsg_len - NLMSG_ALIGN(sizeof(struct nlmsghdr));
+       nlpayload_read(ctrl_fd, NULL, ev_size, 0);
+}
+
+static int ctldev_handle(void)
+{
+       int rc, ev_size;
+       struct iscsi_uevent *ev;
+       iscsi_session_t *session = NULL;
+       iscsi_conn_t *conn = NULL;
+       char nlm_ev[NLMSG_SPACE(sizeof(struct iscsi_uevent))];
+       struct nlmsghdr *nlh;
+       struct iscsi_ev_context *ev_context;
+       uint32_t sid = 0, cid = 0;
+
+       log_debug(7, "in %s", __FUNCTION__);
+
+       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 = (struct iscsi_uevent *)NLMSG_DATA(nlm_ev);
+
+       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:
+       /* old kernels sent ISCSI_UEVENT_CREATE_SESSION on creation */
+       case ISCSI_UEVENT_CREATE_SESSION:
+               drop_data(nlh);
+               if (!ipc_ev_clbk)
+                       return 0;
+
+               if (ipc_ev_clbk->create_session)
+                       ipc_ev_clbk->create_session(ev->r.c_session_ret.host_no,
+                                                   ev->r.c_session_ret.sid);
+               return 0;
+       case ISCSI_KEVENT_DESTROY_SESSION:
+               drop_data(nlh);
+               if (!ipc_ev_clbk)
+                       return 0;
+
+               if (ipc_ev_clbk->destroy_session)
+                       ipc_ev_clbk->destroy_session(ev->r.d_session.host_no,
+                                                    ev->r.d_session.sid);
+               return 0;
+       case ISCSI_KEVENT_RECV_PDU:
+               sid = ev->r.recv_req.sid;
+               cid = ev->r.recv_req.cid;
+               break;
+       case ISCSI_KEVENT_CONN_ERROR:
+               sid = ev->r.connerror.sid;
+               cid = ev->r.connerror.cid;
+               break;
+       case ISCSI_KEVENT_CONN_LOGIN_STATE:
+               sid = ev->r.conn_login.sid;
+               cid = ev->r.conn_login.cid;
+               break;
+       case ISCSI_KEVENT_UNBIND_SESSION:
+               sid = ev->r.unbind_session.sid;
+               /* session wide event so cid is 0 */
+               cid = 0;
+               break;
+       case ISCSI_KEVENT_HOST_EVENT:
+               switch (ev->r.host_event.code) {
+               case ISCSI_EVENT_LINKUP:
+                       log_warning("Host%u: Link Up.",
+                                   ev->r.host_event.host_no);
+                       break;
+               case ISCSI_EVENT_LINKDOWN:
+                       log_warning("Host%u: Link Down.",
+                                   ev->r.host_event.host_no);
+                       break;
+               default:
+                       log_debug(7, "Host%u: Unknown host event: %u.",
+                                 ev->r.host_event.host_no,
+                                 ev->r.host_event.code);
+               }
+
+               drop_data(nlh);
+               return 0;
+       case ISCSI_KEVENT_PING_COMP:
+               ping_event.host_no = ev->r.ping_comp.host_no;
+               ping_event.pid = ev->r.ping_comp.pid;
+               ping_event.status = ev->r.ping_comp.status;
+               ping_event.active = 1;
+
+               drop_data(nlh);
+               return 0;
+       default:
+               if ((ev->type > ISCSI_UEVENT_MAX && ev->type < KEVENT_BASE) ||
+                   (ev->type > ISCSI_KEVENT_MAX))
+                       log_error("Unknown kernel event %d. You may want to "
+                                 " upgrade your iscsi tools.", ev->type);
+               else
+                       /*
+                        * If another app is using the interface we might
+                        * see their
+                        * stuff. Just drop it.
+                        */
+                       log_debug(7, "Got unknown event %d. Dropping.",
+                                 ev->type);
+               drop_data(nlh);
+               return 0;
+       }
+
+       /* verify connection */
+       session = session_find_by_sid(sid);
+       if (!session) {
+               /*
+                * this can happen normally when other apps are using the
+                * nl interface.
+                */
+               log_debug(1, "Could not verify connection %d:%d. Dropping "
+                          "event.", sid, cid);
+               drop_data(nlh);
+               return -ENXIO;
+       }
+       conn = &session->conn[0];
+
+       ev_size = nlh->nlmsg_len - NLMSG_ALIGN(sizeof(struct nlmsghdr));
+
+       ev_context = ipc_ev_clbk->get_ev_context(conn, ev_size);
+       if (!ev_context) {
+               log_error("Can not allocate memory for receive context.");
+               drop_data(nlh);
+               return -ENOMEM;
+       }
+
+       log_debug(6, "message real length is %d bytes, recv_handle %p",
+               nlh->nlmsg_len, ev_context->data);
+
+       if ((rc = nlpayload_read(ctrl_fd, ev_context->data,
+                               ev_size, 0)) < 0) {
+               ipc_ev_clbk->put_ev_context(ev_context);
+               log_error("can not read from NL socket, error %d", rc);
+               /* retry later */
+               return rc;
+       }
+
+       /*
+        * we sched these events because the handlers could call back
+        * into ctldev_handle
+        */
+       switch (ev->type) {
+       case ISCSI_KEVENT_RECV_PDU:
+               rc = ipc_ev_clbk->sched_ev_context(ev_context, conn, 0,
+                                                  EV_CONN_RECV_PDU);
+               break;
+       case ISCSI_KEVENT_CONN_ERROR:
+               memcpy(ev_context->data, &ev->r.connerror.error,
+                       sizeof(ev->r.connerror.error));
+               rc = ipc_ev_clbk->sched_ev_context(ev_context, conn, 0,
+                                                  EV_CONN_ERROR);
+               break;
+       case ISCSI_KEVENT_CONN_LOGIN_STATE:
+               memcpy(ev_context->data, &ev->r.conn_login.state,
+                       sizeof(ev->r.conn_login.state));
+               rc = ipc_ev_clbk->sched_ev_context(ev_context, conn, 0,
+                                                  EV_CONN_LOGIN);
+               break;
+       case ISCSI_KEVENT_UNBIND_SESSION:
+               rc = ipc_ev_clbk->sched_ev_context(ev_context, conn, 0,
+                                                  EV_CONN_STOP);
+               break;
+       default:
+               ipc_ev_clbk->put_ev_context(ev_context);
+               log_error("unknown kernel event %d", ev->type);
+               return -EEXIST;
+       }
+
+       if (rc)
+               ipc_ev_clbk->put_ev_context(ev_context);
+       return rc;
+}
+
+static int
+ctldev_open(void)
+{
+       log_debug(7, "in %s", __FUNCTION__);
+
+       nlm_sendbuf = calloc(1, NLM_BUF_DEFAULT_MAX);
+       if (!nlm_sendbuf) {
+               log_error("can not allocate nlm_sendbuf");
+               return -1;
+       }
+
+       nlm_recvbuf = calloc(1, NLM_BUF_DEFAULT_MAX);
+       if (!nlm_recvbuf) {
+               log_error("can not allocate nlm_recvbuf");
+               goto free_nlm_sendbuf;
+       }
+
+       pdu_sendbuf = calloc(1, PDU_SENDBUF_DEFAULT_MAX);
+       if (!pdu_sendbuf) {
+               log_error("can not allocate nlm_sendbuf");
+               goto free_nlm_recvbuf;
+       }
+
+       setparam_buf = calloc(1, NLM_SETPARAM_DEFAULT_MAX);
+       if (!setparam_buf) {
+               log_error("can not allocate setparam_buf");
+               goto free_pdu_sendbuf;
+       }
+
+       ctrl_fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ISCSI);
+       if (ctrl_fd < 0) {
+               log_error("can not create NETLINK_ISCSI socket [%s]",
+                         strerror(errno));
+               goto free_setparam_buf;
+       }
+
+       memset(&src_addr, 0, sizeof(src_addr));
+       src_addr.nl_family = AF_NETLINK;
+       src_addr.nl_pid = getpid();
+       src_addr.nl_groups = 1;
+       if (bind(ctrl_fd, (struct sockaddr *)&src_addr, sizeof(src_addr))) {
+               log_error("can not bind NETLINK_ISCSI socket [%s]",
+                         strerror(errno));
+               goto close_socket;
+       }
+
+       memset(&dest_addr, 0, sizeof(dest_addr));
+       dest_addr.nl_family = AF_NETLINK;
+       dest_addr.nl_pid = 0; /* kernel */
+       dest_addr.nl_groups = 0; /* unicast */
+
+       log_debug(7, "created NETLINK_ISCSI socket...");
+
+       return ctrl_fd;
+
+close_socket:
+       close(ctrl_fd);
+free_setparam_buf:
+       free(setparam_buf);
+free_pdu_sendbuf:
+       free(pdu_sendbuf);
+free_nlm_recvbuf:
+       free(nlm_recvbuf);
+free_nlm_sendbuf:
+       free(nlm_sendbuf);
+       return -1;
+}
+
+static void
+ctldev_close(void)
+{
+       log_debug(7, "in %s", __FUNCTION__);
+
+       if (ctrl_fd >= 0)
+               close(ctrl_fd);
+       free(setparam_buf);
+       free(pdu_sendbuf);
+       free(nlm_recvbuf);
+       free(nlm_sendbuf);
+}
+
+struct iscsi_ipc nl_ipc = {
+       .name                   = "Open-iSCSI Kernel IPC/NETLINK v.1",
+       .ctldev_bufmax          = NLM_BUF_DEFAULT_MAX,
+       .ctldev_open            = ctldev_open,
+       .ctldev_close           = ctldev_close,
+       .ctldev_handle          = ctldev_handle,
+       .sendtargets            = ksendtargets,
+       .create_session         = kcreate_session,
+       .destroy_session        = kdestroy_session,
+       .unbind_session         = kunbind_session,
+       .create_conn            = kcreate_conn,
+       .destroy_conn           = kdestroy_conn,
+       .bind_conn              = kbind_conn,
+       .set_param              = kset_param,
+       .set_host_param         = kset_host_param,
+       .get_param              = NULL,
+       .start_conn             = kstart_conn,
+       .stop_conn              = kstop_conn,
+       .get_stats              = kget_stats,
+       .writev                 = kwritev,
+       .send_pdu_begin         = ksend_pdu_begin,
+       .send_pdu_end           = ksend_pdu_end,
+       .read                   = kread,
+       .recv_pdu_begin         = krecv_pdu_begin,
+       .recv_pdu_end           = krecv_pdu_end,
+       .set_net_config         = kset_net_config,
+       .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;
+
+void ipc_register_ev_callback(struct iscsi_ipc_ev_clbk *ev_clbk)
+{
+       ipc_ev_clbk = ev_clbk;
+}
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/scsi.c b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/scsi.c
new file mode 100644 (file)
index 0000000..14767e2
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * The following is from the linux kernel scsi_error.c
+ *
+ *  scsi_error.c Copyright (C) 1997 Eric Youngdale
+ *
+ *  SCSI error/timeout handling
+ *      Initial versions: Eric Youngdale.  Based upon conversations with
+ *                        Leonard Zubkoff and David Miller at Linux Expo,
+ *                        ideas originating from all over the place.
+ *
+ *     Restructured scsi_unjam_host and associated functions.
+ *     September 04, 2002 Mike Anderson (andmike@us.ibm.com)
+ *
+ *     Forward port of Russell King's (rmk@arm.linux.org.uk) changes and
+ *     minor  cleanups.
+ *     September 30, 2002 Mike Anderson (andmike@us.ibm.com)
+ */
+
+#include <string.h>
+#include "scsi.h"
+
+/**
+ * scsi_normalize_sense - normalize main elements from either fixed or
+ *                     descriptor sense data format into a common format.
+ *
+ * @sense_buffer:      byte array containing sense data returned by device
+ * @sb_len:            number of valid bytes in sense_buffer
+ * @sshdr:             pointer to instance of structure that common
+ *                     elements are written to.
+ *
+ * Notes:
+ *     The "main elements" from sense data are: response_code, sense_key,
+ *     asc, ascq and additional_length (only for descriptor format).
+ *
+ *     Typically this function can be called after a device has
+ *     responded to a SCSI command with the CHECK_CONDITION status.
+ *
+ * Return value:
+ *     1 if valid sense data information found, else 0;
+ **/
+int scsi_normalize_sense(const uint8_t *sense_buffer, int sb_len,
+                         struct scsi_sense_hdr *sshdr)
+{
+       if (!sense_buffer || !sb_len)
+               return 0;
+
+       memset(sshdr, 0, sizeof(struct scsi_sense_hdr));
+
+       sshdr->response_code = (sense_buffer[0] & 0x7f);
+
+       if (!scsi_sense_valid(sshdr))
+               return 0;
+
+       if (sshdr->response_code >= 0x72) {
+               /*
+                * descriptor format
+                */
+               if (sb_len > 1)
+                       sshdr->sense_key = (sense_buffer[1] & 0xf);
+               if (sb_len > 2)
+                       sshdr->asc = sense_buffer[2];
+               if (sb_len > 3)
+                       sshdr->ascq = sense_buffer[3];
+               if (sb_len > 7)
+                       sshdr->additional_length = sense_buffer[7];
+       } else {
+               /* 
+                * fixed format
+                */
+               if (sb_len > 2)
+                       sshdr->sense_key = (sense_buffer[2] & 0xf);
+               if (sb_len > 7) {
+                       sb_len = (sb_len < (sense_buffer[7] + 8)) ?
+                                        sb_len : (sense_buffer[7] + 8);
+                       if (sb_len > 12)
+                               sshdr->asc = sense_buffer[12];
+                       if (sb_len > 13)
+                               sshdr->ascq = sense_buffer[13];
+               }
+       }
+
+       return 1;
+}
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/scsi.h b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/scsi.h
new file mode 100644 (file)
index 0000000..d8ef951
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * this is from the linux kernel scsi_eh.h
+ */
+#ifndef _SCSI_SCSI_H
+#define _SCSI_SCSI_H
+
+#include <stdint.h>
+
+/*
+ * This is a slightly modified SCSI sense "descriptor" format header.
+ * The addition is to allow the 0x70 and 0x71 response codes. The idea
+ * is to place the salient data from either "fixed" or "descriptor" sense
+ * format into one structure to ease application processing.
+ *
+ * The original sense buffer should be kept around for those cases
+ * in which more information is required (e.g. the LBA of a MEDIUM ERROR).
+ */
+struct scsi_sense_hdr {                /* See SPC-3 section 4.5 */
+       uint8_t response_code;  /* permit: 0x0, 0x70, 0x71, 0x72, 0x73 */
+       uint8_t sense_key;
+       uint8_t asc;
+       uint8_t ascq;
+       uint8_t byte4;
+       uint8_t byte5;
+       uint8_t byte6;
+       uint8_t additional_length;      /* always 0 for fixed sense format */
+};
+
+static inline int scsi_sense_valid(struct scsi_sense_hdr *sshdr)
+{
+       if (!sshdr)
+               return 0;
+
+       return (sshdr->response_code & 0x70) == 0x70;
+}
+
+extern int scsi_normalize_sense(const uint8_t *sense_buffer, int sb_len,
+                               struct scsi_sense_hdr *sshdr);
+
+#endif
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/session_info.c b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/session_info.c
new file mode 100644 (file)
index 0000000..0dae82f
--- /dev/null
@@ -0,0 +1,482 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdint.h>
+#include <inttypes.h>
+
+#include <libopeniscsiusr/libopeniscsiusr.h>
+
+#include "list.h"
+#include "log.h"
+#include "iscsi_sysfs.h"
+#include "version.h"
+#include "iscsi_settings.h"
+#include "mgmt_ipc.h"
+#include "session_info.h"
+#include "transport.h"
+#include "initiator.h"
+#include "iface.h"
+#include "iscsid_req.h"
+#include "iscsi_err.h"
+
+static int session_info_print_flat(struct iscsi_session *se);
+
+int session_info_create_list(void *data, struct session_info *info)
+{
+       struct session_link_info *link_info = data;
+       struct list_head *list = link_info->list;
+       struct session_info *new, *curr, *match = NULL;
+
+       if (link_info->match_fn && !link_info->match_fn(link_info->data, info))
+               return -1;
+
+       new = calloc(1, sizeof(*new));
+       if (!new)
+               return ISCSI_ERR_NOMEM;
+       memcpy(new, info, sizeof(*new));
+       INIT_LIST_HEAD(&new->list);
+
+       if (list_empty(list)) {
+               list_add_tail(&new->list, list);
+               return 0;
+       }
+
+       list_for_each_entry(curr, list, list) {
+               if (!strcmp(curr->targetname, info->targetname)) {
+                       match = curr;
+
+                       if (!strcmp(curr->address, info->address)) {
+                               match = curr;
+
+                               if (curr->port == info->port) {
+                                       match = curr;
+                                       break;
+                               }
+                       }
+               }
+       }
+
+       list_add_tail(&new->list, match ? match->list.next : list);
+       return 0;
+}
+
+void session_info_free_list(struct list_head *list)
+{
+       struct session_info *curr, *tmp;
+
+       list_for_each_entry_safe(curr, tmp, list, list) {
+               list_del(&curr->list);
+               free(curr);
+       }
+}
+
+static char *get_iscsi_node_type(uint32_t sid)
+{
+       int pid = iscsi_sysfs_session_user_created((int) sid);
+
+       if (!pid)
+               return "flash";
+       else
+               return "non-flash";
+}
+
+static int session_info_print_flat(struct iscsi_session *se)
+{
+       uint32_t sid = 0;
+       struct iscsi_transport *t = NULL;
+
+       sid = iscsi_session_sid_get(se);
+       t = iscsi_sysfs_get_transport_by_sid((int) sid);
+
+       if (strchr(iscsi_session_persistent_address_get(se), '.'))
+               printf("%s: [%" PRIu32 "] %s:%" PRIi32 ",%"PRIi32 " %s (%s)\n",
+                       t ? t->name : UNKNOWN_VALUE,
+                       sid, iscsi_session_persistent_address_get(se),
+                       iscsi_session_persistent_port_get(se),
+                       iscsi_session_tpgt_get(se),
+                       iscsi_session_target_name_get(se),
+                       get_iscsi_node_type(sid));
+       else
+               printf("%s: [%" PRIu32 "] [%s]:%" PRIi32 ",%" PRIi32
+                      " %s (%s)\n",
+                       t ? t->name : UNKNOWN_VALUE,
+                       sid, iscsi_session_persistent_address_get(se),
+                       iscsi_session_persistent_port_get(se),
+                       iscsi_session_tpgt_get(se),
+                       iscsi_session_target_name_get(se),
+                       get_iscsi_node_type(sid));
+       return 0;
+}
+
+static int print_iscsi_state(int sid, char *prefix, int tmo)
+{
+       iscsiadm_req_t req;
+       iscsiadm_rsp_t rsp;
+       int err;
+       char *state = NULL;
+       char state_buff[SCSI_MAX_STATE_VALUE];
+       static char *conn_state[] = {
+               "FREE",
+               "TRANSPORT WAIT",
+               "IN LOGIN",
+               "LOGGED IN",
+               "IN LOGOUT",
+               "LOGOUT REQUESTED",
+               "CLEANUP WAIT",
+       };
+       static char *session_state[] = {
+               "NO CHANGE",
+               "CLEANUP",
+               "REOPEN",
+               "REDIRECT",
+       };
+
+       memset(&req, 0, sizeof(iscsiadm_req_t));
+       req.command = MGMT_IPC_SESSION_INFO;
+       req.u.session.sid = sid;
+
+       err = iscsid_exec_req(&req, &rsp, 1, tmo);
+       /*
+        * for drivers like qla4xxx, iscsid does not display
+        * anything here since it does not know about it.
+        */
+       if (!err && rsp.u.session_state.conn_state >= 0 &&
+           rsp.u.session_state.conn_state <= ISCSI_CONN_STATE_CLEANUP_WAIT)
+               state = conn_state[rsp.u.session_state.conn_state];
+       printf("%s\t\tiSCSI Connection State: %s\n", prefix,
+              state ? state : "Unknown");
+       state = NULL;
+
+       memset(state_buff, 0, SCSI_MAX_STATE_VALUE);
+       if (!iscsi_sysfs_get_session_state(state_buff, sid))
+               printf("%s\t\tiSCSI Session State: %s\n", prefix, state_buff);
+       else
+               printf("%s\t\tiSCSI Session State: Unknown\n", prefix);
+
+       if (!err && rsp.u.session_state.session_state >= 0 &&
+          rsp.u.session_state.session_state <= R_STAGE_SESSION_REDIRECT)
+               state = session_state[rsp.u.session_state.session_state];
+       printf("%s\t\tInternal iscsid Session State: %s\n", prefix,
+              state ? state : "Unknown");
+       return 0;
+}
+
+static void print_iscsi_params(int sid, char *prefix)
+{
+       struct iscsi_session_operational_config session_conf;
+       struct iscsi_conn_operational_config conn_conf;
+
+       iscsi_sysfs_get_negotiated_session_conf(sid, &session_conf);
+       iscsi_sysfs_get_negotiated_conn_conf(sid, &conn_conf);
+
+       printf("%s\t\t************************\n", prefix);
+       printf("%s\t\tNegotiated iSCSI params:\n", prefix);
+       printf("%s\t\t************************\n", prefix);
+
+       if (is_valid_operational_value(conn_conf.HeaderDigest))
+               printf("%s\t\tHeaderDigest: %s\n", prefix,
+                       conn_conf.HeaderDigest ? "CRC32C" : "None");
+       if (is_valid_operational_value(conn_conf.DataDigest))
+               printf("%s\t\tDataDigest: %s\n", prefix,
+                       conn_conf.DataDigest ? "CRC32C" : "None");
+       if (is_valid_operational_value(conn_conf.MaxRecvDataSegmentLength))
+               printf("%s\t\tMaxRecvDataSegmentLength: %d\n", prefix,
+                       conn_conf.MaxRecvDataSegmentLength);
+       if (is_valid_operational_value(conn_conf.MaxXmitDataSegmentLength))
+               printf("%s\t\tMaxXmitDataSegmentLength: %d\n", prefix,
+                       conn_conf.MaxXmitDataSegmentLength);
+       if (is_valid_operational_value(session_conf.FirstBurstLength))
+               printf("%s\t\tFirstBurstLength: %d\n", prefix,
+                       session_conf.FirstBurstLength);
+       if (is_valid_operational_value(session_conf.MaxBurstLength))
+               printf("%s\t\tMaxBurstLength: %d\n", prefix,
+                       session_conf.MaxBurstLength);
+       if (is_valid_operational_value(session_conf.ImmediateData))
+               printf("%s\t\tImmediateData: %s\n", prefix,
+                       session_conf.ImmediateData ? "Yes" : "No");
+       if (is_valid_operational_value(session_conf.InitialR2T))
+               printf("%s\t\tInitialR2T: %s\n", prefix,
+                       session_conf.InitialR2T ? "Yes" : "No");
+       if (is_valid_operational_value(session_conf.MaxOutstandingR2T))
+               printf("%s\t\tMaxOutstandingR2T: %d\n", prefix,
+                       session_conf.MaxOutstandingR2T);
+}
+
+static void print_scsi_device_info(void *data, int host_no, int target, int lun)
+{
+       char *prefix = data;
+       char *blockdev, state[SCSI_MAX_STATE_VALUE];
+
+       printf("%s\t\tscsi%d Channel 00 Id %d Lun: %d\n", prefix, host_no,
+              target, lun);
+       blockdev = iscsi_sysfs_get_blockdev_from_lun(host_no, target, lun);
+       if (blockdev) {
+               printf("%s\t\t\tAttached scsi disk %s\t\t", prefix, blockdev);
+               free(blockdev);
+
+               if (!iscsi_sysfs_get_device_state(state, host_no, target, lun))
+                       printf("State: %s\n", state);
+               else
+                       printf("State: Unknown\n");
+       }
+}
+
+static int print_scsi_state(int sid, char *prefix, unsigned int flags)
+{
+       int host_no = -1, err = 0;
+       char state[SCSI_MAX_STATE_VALUE];
+
+       printf("%s\t\t************************\n", prefix);
+       printf("%s\t\tAttached SCSI devices:\n", prefix);
+       printf("%s\t\t************************\n", prefix);
+
+       host_no = iscsi_sysfs_get_host_no_from_sid(sid, &err);
+       if (err) {
+               printf("%s\t\tUnavailable\n", prefix);
+               return err;
+       }
+
+       if (flags & SESSION_INFO_HOST_DEVS) {
+               printf("%s\t\tHost Number: %d\t", prefix, host_no);
+               if (!iscsi_sysfs_get_host_state(state, host_no))
+                       printf("State: %s\n", state);
+               else
+                       printf("State: Unknown\n");
+       }
+
+       if (flags & SESSION_INFO_SCSI_DEVS)
+               iscsi_sysfs_for_each_device(prefix, host_no, sid,
+                                           print_scsi_device_info);
+       return 0;
+}
+
+void session_info_print_tree(struct iscsi_session **ses, uint32_t se_count,
+                            char *prefix, unsigned int flags, int do_show)
+{
+       struct iscsi_session *curr = NULL;
+       struct iscsi_session *prev = NULL;
+       const char *curr_targetname = NULL;
+       const char *curr_address = NULL;
+       const char *persistent_address = NULL;
+       const char *prev_targetname = NULL;
+       const char *prev_address = NULL;
+       int32_t curr_port = 0;
+       int32_t prev_port = 0;
+       uint32_t i = 0;
+       uint32_t sid = 0;
+       char *new_prefix = NULL;
+       int32_t tgt_reset_tmo = -1;
+       int32_t lu_reset_tmo = -1;
+       int32_t abort_tmo = -1;
+       const char *pass = NULL;
+
+       for (i = 0; i < se_count; ++i) {
+               curr = ses[i];
+               curr_targetname = iscsi_session_target_name_get(curr);
+               sid = iscsi_session_sid_get(curr);
+               if (prev != NULL)
+                       prev_targetname = iscsi_session_target_name_get(prev);
+               else
+                       prev_targetname = NULL;
+
+               if (! ((prev_targetname != NULL) &&
+                      (curr_targetname != NULL) &&
+                      (strcmp(prev_targetname, curr_targetname) == 0))) {
+                       printf("%sTarget: %s (%s)\n", prefix, curr_targetname,
+                               get_iscsi_node_type(sid));
+                       prev = NULL;
+               }
+               curr_address = iscsi_session_address_get(curr);
+               curr_port = iscsi_session_port_get(curr);
+
+               if (prev != NULL) {
+                       prev_address = iscsi_session_address_get(prev);
+                       prev_port = iscsi_session_port_get(prev);
+               } else {
+                       prev_address = NULL;
+                       prev_port = 0;
+               }
+               if (! ((prev_address != NULL) &&
+                      (curr_address != NULL) &&
+                      (prev_port != 0) &&
+                      (curr_port != 0) &&
+                      (strcmp(prev_address, curr_address) == 0) &&
+                      (curr_port == prev_port))) {
+                       if (strchr(curr_address, '.'))
+                               printf("%s\tCurrent Portal: %s:%" PRIi32
+                                      ",%" PRIi32 "\n",
+                                      prefix, curr_address, curr_port,
+                                      iscsi_session_tpgt_get(curr));
+                       else
+                               printf("%s\tCurrent Portal: [%s]:%" PRIi32
+                                      ",%" PRIi32 "\n",
+                                      prefix, curr_address, curr_port,
+                                      iscsi_session_tpgt_get(curr));
+                       persistent_address =
+                               iscsi_session_persistent_address_get(curr);
+
+                       if (strchr(persistent_address, '.'))
+                               printf("%s\tPersistent Portal: %s:%" PRIi32
+                                      ",%" PRIi32 "\n",
+                                      prefix, persistent_address,
+                                      iscsi_session_persistent_port_get(curr),
+                                      iscsi_session_tpgt_get(curr));
+                       else
+                               printf("%s\tPersistent Portal: [%s]:%" PRIi32
+                                      ",%" PRIi32 "\n",
+                                      prefix, persistent_address,
+                                      iscsi_session_persistent_port_get(curr),
+                                      iscsi_session_tpgt_get(curr));
+               } else
+                       printf("\n");
+
+               if (flags & SESSION_INFO_IFACE) {
+                       printf("%s\t\t**********\n", prefix);
+                       printf("%s\t\tInterface:\n", prefix);
+                       printf("%s\t\t**********\n", prefix);
+
+                       new_prefix = calloc(1, 1 + strlen(prefix) +
+                                           strlen("\t\t"));
+                       if (new_prefix == NULL) {
+                               printf("Could not print interface info. "
+                                       "Out of Memory.\n");
+                               return;
+                       } else {
+                               sprintf(new_prefix, "%s%s", prefix, "\t\t");
+                               iface_print(iscsi_session_iface_get(curr),
+                                           new_prefix);
+                       }
+                       free(new_prefix);
+               }
+
+               if (flags & SESSION_INFO_ISCSI_STATE) {
+                       printf("%s\t\tSID: %" PRIu32 "\n", prefix, sid);
+                       print_iscsi_state((int) sid, prefix, -1 /* tmo */);
+                       /* TODO(Gris Ge): It seems in the whole project,
+                        *                tmo is always -1, correct?
+                        */
+               }
+
+               if (flags & SESSION_INFO_ISCSI_TIM) {
+                       printf("%s\t\t*********\n", prefix);
+                       printf("%s\t\tTimeouts:\n", prefix);
+                       printf("%s\t\t*********\n", prefix);
+
+                       printf("%s\t\tRecovery Timeout: %" PRIi32 "\n", prefix,
+                              iscsi_session_recovery_tmo_get(curr));
+
+                       tgt_reset_tmo = iscsi_session_tgt_reset_tmo_get(curr);
+                       lu_reset_tmo = iscsi_session_lu_reset_tmo_get(curr);
+                       abort_tmo = iscsi_session_abort_tmo_get(curr);
+
+                       if (tgt_reset_tmo >= 0)
+                               printf("%s\t\tTarget Reset Timeout: %" PRIi32
+                                      "\n", prefix, tgt_reset_tmo);
+                       else
+                               printf("%s\t\tTarget Reset Timeout: %s\n",
+                                       prefix, UNKNOWN_VALUE);
+
+                       if (lu_reset_tmo >= 0)
+                               printf("%s\t\tLUN Reset Timeout: %" PRIi32 "\n",
+                                      prefix, lu_reset_tmo);
+                       else
+                               printf("%s\t\tLUN Reset Timeout: %s\n", prefix,
+                                       UNKNOWN_VALUE);
+
+                       if (abort_tmo >= 0)
+                               printf("%s\t\tAbort Timeout: %" PRIi32 "\n",
+                                      prefix, abort_tmo);
+                       else
+                               printf("%s\t\tAbort Timeout: %s\n", prefix,
+                                       UNKNOWN_VALUE);
+
+               }
+               if (flags & SESSION_INFO_ISCSI_AUTH) {
+                       printf("%s\t\t*****\n", prefix);
+                       printf("%s\t\tCHAP:\n", prefix);
+                       printf("%s\t\t*****\n", prefix);
+                       printf("%s\t\tusername: %s\n", prefix,
+                              strlen(iscsi_session_username_get(curr)) ?
+                              iscsi_session_username_get(curr) :
+                              UNKNOWN_VALUE);
+
+                       if (!do_show)
+                               printf("%s\t\tpassword: %s\n", prefix,
+                                       "********");
+                       else {
+                               pass = iscsi_session_password_get(curr);
+                               printf("%s\t\tpassword: %s\n", prefix,
+                                      strlen(pass) ?  pass : UNKNOWN_VALUE);
+                       }
+
+                       printf("%s\t\tusername_in: %s\n", prefix,
+                              strlen(iscsi_session_username_in_get(curr)) ?
+                              iscsi_session_username_in_get(curr) :
+                              UNKNOWN_VALUE);
+                       if (!do_show)
+                               printf("%s\t\tpassword_in: %s\n", prefix,
+                                       "********");
+                       else {
+                               pass = iscsi_session_password_in_get(curr);
+                               printf("%s\t\tpassword: %s\n", prefix,
+                                      strlen(pass) ?  pass : UNKNOWN_VALUE);
+                       }
+               }
+
+               if (flags & SESSION_INFO_ISCSI_PARAMS)
+                       print_iscsi_params((int) sid, prefix);
+
+               if (flags & (SESSION_INFO_SCSI_DEVS | SESSION_INFO_HOST_DEVS))
+                       print_scsi_state((int) sid, prefix, flags);
+
+               prev = curr;
+       }
+}
+
+int session_info_print(int info_level, struct iscsi_session **ses,
+                      uint32_t se_count, int do_show)
+{
+       int err = 0;
+       char *version;
+       unsigned int flags = 0;
+       uint32_t i = 0;
+
+       switch (info_level) {
+       case 0:
+       case -1:
+               for (i = 0; i < se_count; ++i) {
+                       err = session_info_print_flat(ses[i]);
+                       if (err != 0)
+                               break;
+               }
+               break;
+       case 3:
+               version = iscsi_sysfs_get_iscsi_kernel_version();
+               if (version) {
+                       printf("iSCSI Transport Class version %s\n",
+                               version);
+                       printf("version %s\n", ISCSI_VERSION_STR);
+                       free(version);
+               }
+
+               flags |= (SESSION_INFO_SCSI_DEVS | SESSION_INFO_HOST_DEVS);
+               /* fall through */
+       case 2:
+               flags |= (SESSION_INFO_ISCSI_PARAMS | SESSION_INFO_ISCSI_TIM
+                               | SESSION_INFO_ISCSI_AUTH);
+               /* fall through */
+       case 1:
+               flags |= (SESSION_INFO_ISCSI_STATE | SESSION_INFO_IFACE);
+               session_info_print_tree(ses, se_count, "", flags, do_show);
+               break;
+       default:
+               log_error("Invalid info level %d. Try 0 - 3.", info_level);
+               return ISCSI_ERR_INVAL;
+       }
+
+       if (err) {
+               log_error("Can not get list of active sessions (%d)", err);
+               return err;
+       }
+       return 0;
+}
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/session_info.h b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/session_info.h
new file mode 100644 (file)
index 0000000..cf2e714
--- /dev/null
@@ -0,0 +1,72 @@
+#ifndef SESSION_INFO_H
+#define SESSION_INFO_H
+#include <sys/types.h>
+
+#include <libopeniscsiusr/libopeniscsiusr.h>
+
+#include "sysfs.h"
+#include "types.h"
+#include "iscsi_proto.h"
+#include "config.h"
+
+struct list;
+
+struct session_timeout {
+       int abort_tmo;
+       int lu_reset_tmo;
+       int recovery_tmo;
+       int tgt_reset_tmo;
+};
+
+struct session_CHAP {
+       char username[AUTH_STR_MAX_LEN];
+       char password[AUTH_STR_MAX_LEN];
+       char username_in[AUTH_STR_MAX_LEN];
+       char password_in[AUTH_STR_MAX_LEN];
+};
+
+struct session_info {
+       struct list_head list;
+       /* local info */
+       struct iface_rec iface;
+       int sid;
+       int iscsid_req_tmo;
+
+       struct session_timeout tmo;
+       struct session_CHAP chap;
+
+       /* remote info */
+       char targetname[TARGET_NAME_MAXLEN + 1];
+       int tpgt;
+       char address[NI_MAXHOST + 1];
+       int port;
+       char persistent_address[NI_MAXHOST + 1];
+       int persistent_port;
+};
+
+typedef int (session_match_info_fn_t)(void *data, struct session_info *info);
+
+struct session_link_info {
+       struct list_head *list;
+       session_match_info_fn_t *match_fn;
+       void *data;
+};
+
+#define SESSION_INFO_IFACE             0x1
+#define SESSION_INFO_ISCSI_PARAMS      0x2
+#define SESSION_INFO_ISCSI_STATE       0x4
+#define SESSION_INFO_SCSI_DEVS         0x8
+#define SESSION_INFO_HOST_DEVS         0x10
+#define SESSION_INFO_ISCSI_TIM          0x20
+#define SESSION_INFO_ISCSI_AUTH         0x40
+
+extern int session_info_create_list(void *data, struct session_info *info);
+extern void session_info_free_list(struct list_head *list);
+extern int session_info_print(int info_level, struct iscsi_session **ses,
+                             uint32_t se_count, int do_show);
+
+extern void session_info_print_tree(struct iscsi_session **ses,
+                                   uint32_t se_count, char *prefix,
+                                   unsigned int flags, int do_show);
+
+#endif
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/session_mgmt.c b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/session_mgmt.c
new file mode 100644 (file)
index 0000000..0500f15
--- /dev/null
@@ -0,0 +1,475 @@
+/*
+ * iSCSI session management helpers
+ *
+ * Copyright (C) 2010 Mike Christie
+ * Copyright (C) 2010 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2011 Dell Inc.
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include "idbm.h"
+#include "list.h"
+#include "iscsi_util.h"
+#include "mgmt_ipc.h"
+#include "session_info.h"
+#include "iscsi_sysfs.h"
+#include "log.h"
+#include "iscsid_req.h"
+#include "iscsi_err.h"
+
+static void log_login_msg(struct node_rec *rec, int rc)
+{
+       if (rc) {
+               log_error("Could not login to [iface: %s, target: %s, "
+                         "portal: %s,%d].", rec->iface.name,
+                         rec->name, rec->conn[0].address,
+                         rec->conn[0].port);
+               iscsi_err_print_msg(rc);
+       } else
+               log_info("Login to [iface: %s, target: %s, portal: "
+                        "%s,%d] successful.", rec->iface.name,
+                        rec->name, rec->conn[0].address,
+                        rec->conn[0].port);
+}
+
+struct iscsid_async_req {
+       struct list_head list;
+       void *data;
+       int fd;
+};
+
+/**
+ * iscsid_reqs_close - close open async requests
+ * @list: list of async reqs
+ *
+ * This just closes the socket to the daemon.
+ */
+static void iscsid_reqs_close(struct list_head *list)
+{
+       struct iscsid_async_req *tmp, *curr;
+
+       list_for_each_entry_safe(curr, tmp, list, list) {
+               close(curr->fd);
+               list_del(&curr->list);
+               free(curr);
+       }
+}
+
+static int iscsid_login_reqs_wait(struct list_head *list)
+{
+       struct iscsid_async_req *tmp, *curr;
+       struct node_rec *rec;
+       int ret = 0;
+
+       list_for_each_entry_safe(curr, tmp, list, list) {
+               int err;
+
+               rec = curr->data;
+               err = iscsid_req_wait(MGMT_IPC_SESSION_LOGIN, curr->fd);
+               if (err && !ret)
+                       ret = err;
+               log_login_msg(rec, err);
+               list_del(&curr->list);
+               free(curr);
+       }
+       return ret;
+}
+
+/**
+ * __iscsi_login_portal - request iscsid to login to portal
+ * @data: If set, copies the session.multiple value to the portal record
+ *        so it is propagated to iscsid.
+ * @list: If async, list to add session to
+ * @rec: portal rec to log into
+ */
+static int
+__iscsi_login_portal(void *data, struct list_head *list, struct node_rec *rec)
+{
+       struct iscsid_async_req *async_req = NULL;
+       int rc = 0, fd;
+
+       if (data && !rec->session.multiple) {
+               struct node_rec *pattern_rec = data;
+               rec->session.multiple = pattern_rec->session.multiple;
+       }
+
+       log_info("Logging in to [iface: %s, target: %s, portal: %s,%d]%s",
+                rec->iface.name, rec->name, rec->conn[0].address,
+                rec->conn[0].port,
+                (rec->session.multiple ? " (multiple)" : ""));
+
+       if (list) {
+               async_req = calloc(1, sizeof(*async_req));
+               if (!async_req)
+                       log_info("Could not allocate memory for async login "
+                                "handling. Using sequential login instead.");
+               else
+                       INIT_LIST_HEAD(&async_req->list);
+       }
+
+       if (async_req)
+               rc = iscsid_req_by_rec_async(MGMT_IPC_SESSION_LOGIN,
+                                            rec, &fd);
+       else
+               rc = iscsid_req_by_rec(MGMT_IPC_SESSION_LOGIN, rec);
+
+       if (rc) {
+               log_login_msg(rec, rc);
+               if (async_req)
+                       free(async_req);
+               return rc;
+       }
+
+       if (async_req) {
+               list_add_tail(&async_req->list, list);
+               async_req->fd = fd;
+               async_req->data = rec;
+       } else
+               log_login_msg(rec, rc);
+
+       return 0;
+}
+
+/**
+ * iscsi_login_portal - request iscsid to login to portal multiple
+ * times, based on the session.nr_sessions in the portal record.
+ * @data: If set, session.multiple will cause an additional session to
+ *        be created regardless of the value of session.nr_sessions
+ * @list: If async, list to add session to
+ * @rec: portal rec to log into
+ */
+int iscsi_login_portal(void *data, struct list_head *list, struct node_rec *rec)
+{
+       struct node_rec *pattern_rec = data;
+       int rc = 0, session_count = 0, i;
+
+       /*
+        * If pattern_rec->session.multiple is set, just add a single new
+        * session by passing things along to __iscsi_login_portal
+        */
+       if (pattern_rec && pattern_rec->session.multiple)
+               return __iscsi_login_portal(data, list, rec);
+
+       /*
+        * Count the current number of sessions, and only create those
+        * that are missing.
+        */
+       rc = iscsi_sysfs_for_each_session(rec, &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_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 = ISCSI_ERR_SESS_EXISTS;
+               goto done;
+       }
+
+       /*
+        * Ensure the record's 'multiple' flag is set so __iscsi_login_portal
+        * will allow multiple logins, but only if configured for more
+        * than one 
+        */
+       if (rec->session.nr_sessions > 1)
+               rec->session.multiple = 1;
+       for (i = session_count; i < rec->session.nr_sessions; ++i) {
+               log_debug(1, "%s: Creating session %d/%d", rec->iface.name,
+                         i + 1, rec->session.nr_sessions);
+               int err = __iscsi_login_portal(pattern_rec, list, rec);
+               if (err && !rc)
+                       rc = err;
+       }
+
+done:
+       return rc;
+}
+
+/**
+ * iscsi_login_portal_nowait - request iscsid to login to portal
+ * @rec: portal rec to log into
+ *
+ * This sends the login request, but does not wait for the result.
+ */
+int iscsi_login_portal_nowait(struct node_rec *rec)
+{
+       struct list_head list;
+       int err;
+
+       INIT_LIST_HEAD(&list);
+       err = iscsi_login_portal(NULL, &list, rec);
+       if (err > 0)
+               return err;
+       iscsid_reqs_close(&list);
+       return 0;
+}
+
+/**
+ * __iscsi_login_portals - login into portals on @rec_list,
+ * @data: data to pass to login_fn
+ * @nr_found: returned with number of portals logged into
+ * @wait: bool indicating if the fn should wait for the result
+ * @rec_list: list of portals to log into
+ * @clear_list: If set, delete and free rec_list after iterating through.
+ * @login_fn: list iter function
+ *
+ * This will loop over the list of portals and login. It
+ * will attempt to login asynchronously, and then wait for
+ * them to complete if wait is set.
+ */
+static
+int __iscsi_login_portals(void *data, int *nr_found, int wait,
+                       struct list_head *rec_list, int clear_list,
+                       int (*login_fn)(void *, struct list_head *,
+                                        struct node_rec *))
+{
+       struct node_rec *curr_rec, *tmp;
+       struct list_head login_list;
+       int ret = 0, err;
+
+       *nr_found = 0;
+       INIT_LIST_HEAD(&login_list);
+
+       list_for_each_entry(curr_rec, rec_list, list) {
+               err = login_fn(data, &login_list, curr_rec);
+               if (err > 0 && !ret)
+                       ret = err;
+               if (!err)
+                       (*nr_found)++;
+       }
+       if (wait) {
+               err = iscsid_login_reqs_wait(&login_list);
+               if (err && !ret)
+                       ret = err;
+       } else
+               iscsid_reqs_close(&login_list);
+
+       if (clear_list) {
+               list_for_each_entry_safe(curr_rec, tmp, rec_list, list) {
+                       list_del(&curr_rec->list);
+                       free(curr_rec);
+               }
+       }
+       return ret;
+}
+
+/**
+ * iscsi_login_portals - login into portals on @rec_list,
+ * @data: data to pass to login_fn
+ * @nr_found: returned with number of portals logged into
+ * @wait: bool indicating if the fn should wait for the result
+ * @rec_list: list of portals to log into.  This list is deleted after
+ *            iterating through it.
+ * @login_fn: list iter function
+ *
+ * This will loop over the list of portals and login. It
+ * will attempt to login asynchronously, and then wait for
+ * them to complete if wait is set.
+ */
+int iscsi_login_portals(void *data, int *nr_found, int wait,
+                       struct list_head *rec_list,
+                       int (*login_fn)(void *, struct list_head *,
+                                        struct node_rec *))
+{
+       return __iscsi_login_portals(data, nr_found, wait, rec_list,
+                                    1, login_fn);
+}
+
+/**
+ * iscsi_login_portals_safe - login into portals on @rec_list, but do not
+ *                           clear out rec_list.
+ */
+int iscsi_login_portals_safe(void *data, int *nr_found, int wait,
+                       struct list_head *rec_list,
+                       int (*login_fn)(void *, struct list_head *,
+                                        struct node_rec *))
+{
+       return __iscsi_login_portals(data, nr_found, wait, rec_list,
+                                    0, login_fn);
+}
+
+static void log_logout_msg(struct session_info *info, int rc)
+{
+       if (rc) {
+               log_error("Could not logout of [sid: %d, target: %s, "
+                         "portal: %s,%d].", info->sid,
+                         info->targetname,
+                         info->persistent_address, info->port);
+               iscsi_err_print_msg(rc);
+       } else
+               log_info("Logout of [sid: %d, target: %s, "
+                        "portal: %s,%d] successful.",
+                        info->sid, info->targetname,
+                        info->persistent_address, info->port);
+}
+
+static int iscsid_logout_reqs_wait(struct list_head *list)
+{
+       struct iscsid_async_req *tmp, *curr;
+       struct session_info *info;
+       int ret = 0;
+
+       list_for_each_entry_safe(curr, tmp, list, list) {
+               int err;
+
+               info  = curr->data;
+               err = iscsid_req_wait(MGMT_IPC_SESSION_LOGOUT, curr->fd);
+               log_logout_msg(info, err);
+               if (err)
+                       ret = err;
+               list_del(&curr->list);
+               free(curr);
+       }
+       return ret;
+}
+
+/**
+ * iscsi_logout_portal - logout of portal
+ * @info: session to log out of
+ * @list: if async, this is the list to add the logout req to
+ */
+int iscsi_logout_portal(struct session_info *info, struct list_head *list)
+{
+       struct iscsid_async_req *async_req = NULL;
+       int fd, rc;
+
+       /* TODO: add fn to add session prefix info like dev_printk */
+       log_info("Logging out of session [sid: %d, target: %s, portal: "
+                "%s,%d]",
+                info->sid, info->targetname, info->persistent_address,
+                info->port);
+
+       if (list) {
+               async_req = calloc(1, sizeof(*async_req));
+               if (!async_req)
+                       log_info("Could not allocate memory for async logout "
+                                "handling. Using sequential logout instead.");
+       }
+
+       if (!async_req)
+               rc = iscsid_req_by_sid(MGMT_IPC_SESSION_LOGOUT, info->sid);
+       else {
+               INIT_LIST_HEAD(&async_req->list);
+               rc = iscsid_req_by_sid_async(MGMT_IPC_SESSION_LOGOUT,
+                                            info->sid, &fd);
+       }
+
+       /* we raced with another app or instance of iscsiadm */
+       if (rc) {
+               log_logout_msg(info, rc);
+               if (async_req)
+                       free(async_req);
+               return rc;
+       }
+
+       if (async_req) {
+               list_add_tail(&async_req->list, list);
+               async_req->fd = fd;
+               async_req->data = info;
+       } else
+               log_logout_msg(info, rc);
+
+       return 0;
+}
+
+/**
+ * iscsi_logout_portals - logout portals
+ * @data: data to pass to iter logout_fn
+ * @nr_found: number of sessions logged out
+ * @wait: bool indicating if the fn should wait for the result
+ * @logout_fn: logout iter function
+ *
+ * This will loop over the list of sessions and run the logout fn
+ * on them. It will attempt to logout asynchronously, and then wait for
+ * them to complete if wait is set.
+ */
+int iscsi_logout_portals(void *data, int *nr_found, int wait,
+                        int (*logout_fn)(void *, struct list_head *,
+                                         struct session_info *))
+{
+       struct session_info *curr_info;
+       struct session_link_info link_info;
+       struct list_head session_list, logout_list;
+       int ret = 0, err;
+
+       INIT_LIST_HEAD(&session_list);
+       INIT_LIST_HEAD(&logout_list);
+
+       memset(&link_info, 0, sizeof(link_info));
+       link_info.list = &session_list;
+       link_info.data = NULL;
+       link_info.match_fn = NULL;
+       *nr_found = 0;
+
+       err = iscsi_sysfs_for_each_session(&link_info, nr_found,
+                                          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));
+       else if (err && list_empty(&session_list)) {
+               log_error("Could not read session info.");
+               return err;
+       } else if (list_empty(&session_list))
+               return ISCSI_ERR_NO_OBJS_FOUND;
+       ret = err;
+       *nr_found = 0;
+
+       list_for_each_entry(curr_info, &session_list, list) {
+               err = logout_fn(data, &logout_list, curr_info);
+               if (err > 0 && !ret)
+                       ret = err;
+               if (!err)
+                       (*nr_found)++;
+       }
+
+       if (!*nr_found) {
+               ret = ISCSI_ERR_NO_OBJS_FOUND;
+               goto free_list;
+       }
+
+       if (wait) {
+               err = iscsid_logout_reqs_wait(&logout_list);
+               if (err && !ret)
+                       ret = err;
+       } else
+               iscsid_reqs_close(&logout_list);
+
+       if (ret)
+               log_error("Could not logout of all requested sessions");
+
+free_list:
+       session_info_free_list(&session_list);
+       return ret;
+}
+
+/* TODO merge with initiator.c implementation */
+/* And add locking */
+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,
+                                        0))
+               return 1;
+       return 0;
+}
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/session_mgmt.h b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/session_mgmt.h
new file mode 100644 (file)
index 0000000..a28bfa4
--- /dev/null
@@ -0,0 +1,26 @@
+#ifndef _SESSION_MGMT_H_
+#define _SESSION_MGMT_H_
+
+struct node_rec;
+struct list_head;
+struct session_info;
+
+extern int iscsi_login_portal(void *data, struct list_head *list,
+                             struct node_rec *rec);
+extern int iscsi_login_portal_nowait(struct node_rec *rec);
+extern int iscsi_login_portals(void *data, int *nr_found, int wait,
+                              struct list_head *rec_list,
+                              int (*login_fn)(void *, struct list_head *,
+                                               struct node_rec *));
+extern int iscsi_login_portals_safe(void *data, int *nr_found, int wait,
+                              struct list_head *rec_list,
+                              int (*login_fn)(void *, struct list_head *,
+                                               struct node_rec *));
+extern int iscsi_logout_portal(struct session_info *info,
+                              struct list_head *list);
+extern int iscsi_logout_portals(void *data, int *nr_found, int wait,
+                               int (*logout_fn)(void *, struct list_head *,
+                                                struct session_info *));
+extern int iscsi_check_for_running_session(struct node_rec *rec);
+
+#endif
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/sysfs.c b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/sysfs.c
new file mode 100644 (file)
index 0000000..7f26572
--- /dev/null
@@ -0,0 +1,726 @@
+/*
+ * This is from udev-121's udev_sysfs.c
+ *
+ * Copyright (C) 2005-2006 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ *     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 version 2 of the License.
+ *
+ *     This program is distributed in the hope that it will be useful, but
+ *     WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *     General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License along
+ *     with this program; if not, write to the Free Software Foundation, Inc.,
+ *     51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <inttypes.h>
+#include <sys/stat.h>
+
+#include "log.h"
+#include "sysdeps.h"
+#include "sysfs.h"
+
+/*
+ * We take this file from udev so we want to make as few changes are possible,
+ * so we can maintain patches.
+ *
+ * This is from udev_utils_string.c
+ */
+static void remove_trailing_chars(char *path, char c)
+{
+       size_t len;
+
+       len = strlen(path);
+       while (len > 0 && path[len-1] == c)
+               path[--len] = '\0';
+}
+
+/* this converts udevs logging to ours. */
+#define dbg(format, arg...)                                            \
+       do {                                                            \
+               log_debug(3, "%s: " format, __FUNCTION__,## arg);       \
+       } while (0)
+
+/*
+ * Begin udev_sysfs.c code
+ */
+char sysfs_path[PATH_SIZE];
+
+/* device cache */
+static LIST_HEAD(dev_list);
+
+int sysfs_init(void)
+{
+       const char *env;
+
+       env = getenv("SYSFS_PATH");
+       if (env) {
+               strlcpy(sysfs_path, env, sizeof(sysfs_path));
+               remove_trailing_chars(sysfs_path, '/');
+       } else
+               strlcpy(sysfs_path, "/sys", sizeof(sysfs_path));
+       dbg("sysfs_path='%s'", sysfs_path);
+
+       INIT_LIST_HEAD(&dev_list);
+       return 0;
+}
+
+void sysfs_cleanup(void)
+{
+       struct sysfs_device *dev_loop;
+       struct sysfs_device *dev_temp;
+
+       list_for_each_entry_safe(dev_loop, dev_temp, &dev_list, node) {
+               list_del_init(&dev_loop->node);
+               free(dev_loop);
+       }
+}
+
+void sysfs_device_set_values(struct sysfs_device *dev, const char *devpath,
+                            const char *subsystem, const char *driver)
+{
+       char *pos;
+
+       strlcpy(dev->devpath, devpath, sizeof(dev->devpath));
+       if (subsystem != NULL)
+               strlcpy(dev->subsystem, subsystem, sizeof(dev->subsystem));
+       if (driver != NULL)
+               strlcpy(dev->driver, driver, sizeof(dev->driver));
+
+       /* set kernel name */
+       pos = strrchr(dev->devpath, '/');
+       if (pos == NULL)
+               return;
+       strlcpy(dev->kernel, &pos[1], sizeof(dev->kernel));
+       dbg("kernel='%s'", dev->kernel);
+
+       /* some devices have '!' in their name, change that to '/' */
+       pos = dev->kernel;
+       while (pos[0] != '\0') {
+               if (pos[0] == '!')
+                       pos[0] = '/';
+               pos++;
+       }
+
+       /* get kernel number */
+       pos = &dev->kernel[strlen(dev->kernel)];
+       while (isdigit(pos[-1]))
+               pos--;
+       strlcpy(dev->kernel_number, pos, sizeof(dev->kernel_number));
+       dbg("kernel_number='%s'", dev->kernel_number);
+}
+
+int sysfs_resolve_link(char *devpath, size_t size)
+{
+       char link_path[PATH_SIZE];
+       char link_target[PATH_SIZE];
+       int len;
+       int i;
+       int back;
+
+       strlcpy(link_path, sysfs_path, sizeof(link_path));
+       strlcat(link_path, devpath, sizeof(link_path));
+       len = readlink(link_path, link_target, sizeof(link_target) - 1);
+       if (len <= 0)
+               return -1;
+       link_target[len] = '\0';
+       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", devpath, &link_target[back * 3], back);
+       for (i = 0; i <= back; i++) {
+               char *pos = strrchr(devpath, '/');
+
+               if (pos == NULL)
+                       return -1;
+               pos[0] = '\0';
+       }
+       dbg("after moving back '%s'", devpath);
+       strlcat(devpath, "/", size);
+       strlcat(devpath, &link_target[back * 3], size);
+       return 0;
+}
+
+struct sysfs_device *sysfs_device_get(const char *devpath)
+{
+       char path[PATH_SIZE];
+       char devpath_real[PATH_SIZE];
+       struct sysfs_device *dev;
+       struct sysfs_device *dev_loop;
+       struct stat statbuf;
+       char link_path[PATH_SIZE];
+       char link_target[PATH_SIZE];
+       int len;
+       char *pos;
+
+       if (!devpath)
+               return NULL;
+
+       /* we handle only these devpathes */
+       if (strncmp(devpath, "/devices/", 9) != 0 &&
+           strncmp(devpath, "/subsystem/", 11) != 0 &&
+           strncmp(devpath, "/module/", 8) != 0 &&
+           strncmp(devpath, "/bus/", 5) != 0 &&
+           strncmp(devpath, "/class/", 7) != 0 &&
+           strncmp(devpath, "/block/", 7) != 0)
+               return NULL;
+
+       dbg("open '%s'", devpath);
+       strlcpy(devpath_real, devpath, sizeof(devpath_real));
+       remove_trailing_chars(devpath_real, '/');
+       if (devpath[0] == '\0' )
+               return NULL;
+
+       /* 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'", dev_loop->devpath);
+                       return dev_loop;
+               }
+       }
+
+       /* if we got a link, resolve it to the real device */
+       strlcpy(path, sysfs_path, sizeof(path));
+       strlcat(path, devpath_real, sizeof(path));
+       if (lstat(path, &statbuf) != 0) {
+               dbg("stat '%s' failed: %s", path, strerror(errno));
+               return NULL;
+       }
+       if (S_ISLNK(statbuf.st_mode)) {
+               if (sysfs_resolve_link(devpath_real, sizeof(devpath_real)) != 0)
+                       return NULL;
+
+               /* 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'", dev_loop->devpath);
+                               return dev_loop;
+                       }
+               }
+       }
+
+       /* it is a new device */
+       dbg("new uncached device '%s'", devpath_real);
+       dev = malloc(sizeof(struct sysfs_device));
+       if (dev == NULL)
+               return NULL;
+       memset(dev, 0x00, sizeof(struct sysfs_device));
+
+       sysfs_device_set_values(dev, devpath_real, NULL, NULL);
+
+       /* get subsystem name */
+       strlcpy(link_path, sysfs_path, sizeof(link_path));
+       strlcat(link_path, dev->devpath, sizeof(link_path));
+       strlcat(link_path, "/subsystem", sizeof(link_path));
+       len = readlink(link_path, link_target, sizeof(link_target) - 1);
+       if (len > 0) {
+               /* get subsystem from "subsystem" link */
+               link_target[len] = '\0';
+               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));
+       } else if (strstr(dev->devpath, "/drivers/") != NULL) {
+               strlcpy(dev->subsystem, "drivers", sizeof(dev->subsystem));
+       } else if (strncmp(dev->devpath, "/module/", 8) == 0) {
+               strlcpy(dev->subsystem, "module", sizeof(dev->subsystem));
+       } else if (strncmp(dev->devpath, "/subsystem/", 11) == 0) {
+               pos = strrchr(dev->devpath, '/');
+               if (pos == &dev->devpath[10])
+                       strlcpy(dev->subsystem, "subsystem", sizeof(dev->subsystem));
+       } else if (strncmp(dev->devpath, "/class/", 7) == 0) {
+               pos = strrchr(dev->devpath, '/');
+               if (pos == &dev->devpath[6])
+                       strlcpy(dev->subsystem, "subsystem", sizeof(dev->subsystem));
+       } else if (strncmp(dev->devpath, "/bus/", 5) == 0) {
+               pos = strrchr(dev->devpath, '/');
+               if (pos == &dev->devpath[4])
+                       strlcpy(dev->subsystem, "subsystem", sizeof(dev->subsystem));
+       }
+
+       /* get driver name */
+       strlcpy(link_path, sysfs_path, sizeof(link_path));
+       strlcat(link_path, dev->devpath, sizeof(link_path));
+       strlcat(link_path, "/driver", sizeof(link_path));
+       len = readlink(link_path, link_target, sizeof(link_target) - 1);
+       if (len > 0) {
+               link_target[len] = '\0';
+               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'", dev->devpath, dev->subsystem, dev->driver);
+       list_add(&dev->node, &dev_list);
+
+       return dev;
+}
+
+struct sysfs_device *sysfs_device_get_parent(struct sysfs_device *dev)
+{
+       char parent_devpath[PATH_SIZE];
+       char *pos;
+
+       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'", parent_devpath);
+
+       /* strip last element */
+       pos = strrchr(parent_devpath, '/');
+       if (pos == NULL || pos == parent_devpath)
+               return NULL;
+       pos[0] = '\0';
+
+       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");
+                       goto device_link;
+               }
+       }
+       if (strcmp(parent_devpath, "/block") == 0) {
+               dbg("/block top level, look for device link");
+               goto device_link;
+       }
+
+       /* are we at the top level? */
+       pos = strrchr(parent_devpath, '/');
+       if (pos == NULL || pos == parent_devpath)
+               return NULL;
+
+       /* get parent and remember it */
+       dev->parent = sysfs_device_get(parent_devpath);
+       return dev->parent;
+
+device_link:
+       strlcpy(parent_devpath, dev->devpath, sizeof(parent_devpath));
+       strlcat(parent_devpath, "/device", sizeof(parent_devpath));
+       if (sysfs_resolve_link(parent_devpath, sizeof(parent_devpath)) != 0)
+               return NULL;
+
+       /* get parent and remember it */
+       dev->parent = sysfs_device_get(parent_devpath);
+       return dev->parent;
+}
+
+struct sysfs_device *sysfs_device_get_parent_with_subsystem(struct sysfs_device *dev, const char *subsystem)
+{
+       struct sysfs_device *dev_parent;
+
+       dev_parent = sysfs_device_get_parent(dev);
+       while (dev_parent != NULL) {
+               if (strcmp(dev_parent->subsystem, subsystem) == 0)
+                       return dev_parent;
+               dev_parent = sysfs_device_get_parent(dev_parent);
+       }
+       return NULL;
+}
+
+char *sysfs_attr_get_value(const char *devpath, const char *attr_name)
+{
+       char path_full[PATH_SIZE];
+       char value[NAME_SIZE] = { '\0', };
+       struct stat statbuf;
+       int fd;
+       ssize_t size;
+       size_t sysfs_len;
+
+       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;
+       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) != 0) {
+               dbg("stat '%s' failed: %s", path_full, strerror(errno));
+               goto out;
+       }
+
+       if (S_ISLNK(statbuf.st_mode)) {
+               /* links return the last element of the target path */
+               char link_target[PATH_SIZE];
+               int len;
+               const char *pos;
+
+               len = readlink(path_full, link_target, sizeof(link_target) - 1);
+               if (len > 0) {
+                       link_target[len] = '\0';
+                       pos = strrchr(link_target, '/');
+                       if (pos != NULL) {
+                               dbg("cache '%s' with link value '%s'", path_full, value);
+                               strlcpy(value, &pos[1], NAME_SIZE);
+                       }
+               }
+               goto out;
+       }
+
+       /* skip directories */
+       if (S_ISDIR(statbuf.st_mode))
+               goto out;
+
+       /* skip non-readable files */
+       if ((statbuf.st_mode & S_IRUSR) == 0)
+               goto out;
+
+       /* read attribute value */
+       fd = open(path_full, O_RDONLY);
+       if (fd < 0) {
+               dbg("attribute '%s' can not be opened", path_full);
+               goto out;
+       }
+       size = read(fd, value, sizeof(value));
+       close(fd);
+       if (size < 0)
+               goto out;
+       if (size == sizeof(value))
+               goto out;
+
+       /* got a valid value, store and return it */
+       value[size] = '\0';
+       remove_trailing_chars(value, '\n');
+
+out:
+       if (value[0] == '\0')
+               return NULL;
+       return strdup(value);
+}
+
+int sysfs_lookup_devpath_by_subsys_id(char *devpath_full, size_t len, const char *subsystem, const char *id)
+{
+       size_t sysfs_len;
+       char path_full[PATH_SIZE];
+       char *path;
+       struct stat statbuf;
+
+       sysfs_len = strlcpy(path_full, sysfs_path, sizeof(path_full));
+       path = &path_full[sysfs_len];
+
+       if (strcmp(subsystem, "subsystem") == 0) {
+               strlcpy(path, "/subsystem/", sizeof(path_full) - sysfs_len);
+               strlcat(path, id, sizeof(path_full) - sysfs_len);
+               if (stat(path_full, &statbuf) == 0)
+                       goto found;
+
+               strlcpy(path, "/bus/", sizeof(path_full) - sysfs_len);
+               strlcat(path, id, sizeof(path_full) - sysfs_len);
+               if (stat(path_full, &statbuf) == 0)
+                       goto found;
+               goto out;
+
+               strlcpy(path, "/class/", sizeof(path_full) - sysfs_len);
+               strlcat(path, id, sizeof(path_full) - sysfs_len);
+               if (stat(path_full, &statbuf) == 0)
+                       goto found;
+       }
+
+       if (strcmp(subsystem, "module") == 0) {
+               strlcpy(path, "/module/", sizeof(path_full) - sysfs_len);
+               strlcat(path, id, sizeof(path_full) - sysfs_len);
+               if (stat(path_full, &statbuf) == 0)
+                       goto found;
+               goto out;
+       }
+
+       if (strcmp(subsystem, "drivers") == 0) {
+               char subsys[NAME_SIZE];
+               char *driver;
+
+               strlcpy(subsys, id, sizeof(subsys));
+               driver = strchr(subsys, ':');
+               if (driver != NULL) {
+                       driver[0] = '\0';
+                       driver = &driver[1];
+                       strlcpy(path, "/subsystem/", sizeof(path_full) - sysfs_len);
+                       strlcat(path, subsys, sizeof(path_full) - sysfs_len);
+                       strlcat(path, "/drivers/", sizeof(path_full) - sysfs_len);
+                       strlcat(path, driver, sizeof(path_full) - sysfs_len);
+                       if (stat(path_full, &statbuf) == 0)
+                               goto found;
+
+                       strlcpy(path, "/bus/", sizeof(path_full) - sysfs_len);
+                       strlcat(path, subsys, sizeof(path_full) - sysfs_len);
+                       strlcat(path, "/drivers/", sizeof(path_full) - sysfs_len);
+                       strlcat(path, driver, sizeof(path_full) - sysfs_len);
+                       if (stat(path_full, &statbuf) == 0)
+                               goto found;
+               }
+               goto out;
+       }
+
+       strlcpy(path, "/subsystem/", sizeof(path_full) - sysfs_len);
+       strlcat(path, subsystem, sizeof(path_full) - sysfs_len);
+       strlcat(path, "/devices/", sizeof(path_full) - sysfs_len);
+       strlcat(path, id, sizeof(path_full) - sysfs_len);
+       if (stat(path_full, &statbuf) == 0)
+               goto found;
+
+       strlcpy(path, "/bus/", sizeof(path_full) - sysfs_len);
+       strlcat(path, subsystem, sizeof(path_full) - sysfs_len);
+       strlcat(path, "/devices/", sizeof(path_full) - sysfs_len);
+       strlcat(path, id, sizeof(path_full) - sysfs_len);
+       if (stat(path_full, &statbuf) == 0)
+               goto found;
+
+       strlcpy(path, "/class/", sizeof(path_full) - sysfs_len);
+       strlcat(path, subsystem, sizeof(path_full) - sysfs_len);
+       strlcat(path, "/", sizeof(path_full) - sysfs_len);
+       strlcat(path, id, sizeof(path_full) - sysfs_len);
+       if (stat(path_full, &statbuf) == 0)
+               goto found;
+
+       strlcpy(path, "/firmware/", sizeof(path_full) - sysfs_len);
+       strlcat(path, subsystem, sizeof(path_full) - sysfs_len);
+       strlcat(path, "/", sizeof(path_full) - sysfs_len);
+       strlcat(path, id, sizeof(path_full) - sysfs_len);
+       if (stat(path_full, &statbuf) == 0)
+               goto found;
+
+out:
+       return 0;
+found:
+       if (S_ISLNK(statbuf.st_mode))
+               sysfs_resolve_link(path, sizeof(path_full) - sysfs_len);
+       strlcpy(devpath_full, path, len);
+       return 1;
+}
+
+
+char *sysfs_get_value(const char *id, char *subsys, char *param)
+{
+       char devpath[PATH_SIZE];
+       char *sysfs_value;
+
+       if (!sysfs_lookup_devpath_by_subsys_id(devpath, sizeof(devpath),
+                                              subsys, id)) {
+               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",
+                         param, devpath);
+               return NULL;
+       }
+
+       if (!strncmp(sysfs_value, "<NULL>", 6) ||
+           !strncmp(sysfs_value, "(null)", 6)) {
+               free(sysfs_value);
+               return NULL;
+       }
+
+       return sysfs_value;
+}
+
+int sysfs_get_uint(char *id, char *subsys, char *param,
+                  unsigned int *value)
+{
+       char *sysfs_value;
+
+       *value = -1;
+       sysfs_value = sysfs_get_value(id, subsys, param);
+       if (!sysfs_value)
+               return EIO;
+
+       errno = 0;
+       *value = strtoul(sysfs_value, NULL, 0);
+       free(sysfs_value);
+       if (errno)
+               return errno;
+       return 0;
+}
+
+int sysfs_get_int(const char *id, char *subsys, char *param, int *value)
+{
+       char *sysfs_value;
+
+       *value = -1;
+       sysfs_value = sysfs_get_value(id, subsys, param);
+       if (!sysfs_value)
+               return EIO;
+
+       *value = atoi(sysfs_value);
+       free(sysfs_value);
+       return 0;
+}
+
+int sysfs_get_str(char *id, char *subsys, char *param, char *value,
+                 int value_size)
+{
+       char *sysfs_value;
+       int len;
+
+       value[0] = '\0';
+       sysfs_value = sysfs_get_value(id, subsys, param);
+       if (!sysfs_value)
+               return EIO;
+       if (!strlen(sysfs_value)) {
+               free(sysfs_value);
+               return EIO;
+       }
+
+       len = strlen(sysfs_value);
+       if (len && (sysfs_value[len - 1] == '\n'))
+               sysfs_value[len - 1] = '\0';
+       strncpy(value, sysfs_value, value_size);
+       value[value_size - 1] = '\0';
+       free(sysfs_value);
+       return 0;
+}
+
+int sysfs_get_uint64(char *id, char *subsys, char *param, uint64_t *value)
+{
+       char *sysfs_value;
+
+       *value = -1;
+       sysfs_value = sysfs_get_value(id, subsys, param);
+       if (!sysfs_value)
+               return EIO;
+
+       if (sscanf(sysfs_value, "%" PRIu64 "\n", value) != 1) {
+               free(sysfs_value);
+               return EINVAL;
+       }
+       free(sysfs_value);
+       return 0;
+}
+
+int sysfs_get_uint8(char *id, char *subsys, char *param,
+                   uint8_t *value)
+{
+       char *sysfs_value;
+
+       *value = -1;
+       sysfs_value = sysfs_get_value(id, subsys, param);
+       if (!sysfs_value)
+               return EIO;
+
+       *value = (uint8_t)atoi(sysfs_value);
+       free(sysfs_value);
+       return 0;
+}
+
+int sysfs_get_uint16(char *id, char *subsys, char *param,
+                    uint16_t *value)
+{
+       char *sysfs_value;
+
+       *value = -1;
+       sysfs_value = sysfs_get_value(id, subsys, param);
+       if (!sysfs_value)
+               return EIO;
+
+       *value = (uint16_t)atoi(sysfs_value);
+       free(sysfs_value);
+       return 0;
+}
+
+int sysfs_set_param(char *id, char *subsys, char *attr_name,
+                   char *write_buf, ssize_t buf_size)
+{
+       struct stat statbuf;
+       char devpath[PATH_SIZE];
+       size_t sysfs_len;
+       char path_full[PATH_SIZE];
+       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",
+                         subsys, id);
+               return EIO;
+       }
+
+       sysfs_len = strlcpy(path_full, sysfs_path, sizeof(path_full));
+       if(sysfs_len >= sizeof(path_full))
+               sysfs_len = sizeof(path_full) - 1;
+       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", path_full);
+               return errno;
+       }
+
+       if ((statbuf.st_mode & S_IWUSR) == 0) {
+               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", path_full, errno);
+               return errno;
+       }
+
+       if (write(fd, write_buf, buf_size) == -1)
+               rc = errno;
+       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/pkgs/open-iscsi/open-iscsi-2.1.8/usr/sysfs.h b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/sysfs.h
new file mode 100644 (file)
index 0000000..462060e
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * This is from udev-121 udev.h
+ *
+ * Copyright (C) 2003 Greg Kroah-Hartman <greg@kroah.com>
+ * Copyright (C) 2003-2006 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ *     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 version 2 of the License.
+ *
+ *     This program is distributed in the hope that it will be useful, but
+ *     WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *     General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License along
+ *     with this program; if not, write to the Free Software Foundation, Inc.,
+ *     51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ */
+
+#ifndef _SYSFS_
+#define _SYSFS_
+
+#include <stdint.h>
+#include "list.h"
+#include "string.h"
+
+#define PATH_SIZE                              512
+#define NAME_SIZE                              256
+
+struct sysfs_device {
+       struct list_head node;                  /* for device cache */
+       struct sysfs_device *parent;            /* already cached parent*/
+       char devpath[PATH_SIZE];
+       char subsystem[NAME_SIZE];              /* $class, $bus, drivers, module */
+       char kernel[NAME_SIZE];                 /* device instance name */
+       char kernel_number[NAME_SIZE];
+       char driver[NAME_SIZE];                 /* device driver name */
+};
+
+extern char sysfs_path[PATH_SIZE];
+extern int sysfs_init(void);
+extern void sysfs_cleanup(void);
+extern void sysfs_device_set_values(struct sysfs_device *dev, const char *devpath,
+                                   const char *subsystem, const char *driver);
+extern struct sysfs_device *sysfs_device_get(const char *devpath);
+extern struct sysfs_device *sysfs_device_get_parent(struct sysfs_device *dev);
+extern struct sysfs_device *sysfs_device_get_parent_with_subsystem(struct sysfs_device *dev, const char *subsystem);
+extern char *sysfs_attr_get_value(const char *devpath, const char *attr_name);
+extern int sysfs_resolve_link(char *path, size_t size);
+extern int sysfs_lookup_devpath_by_subsys_id(char *devpath, size_t len, const char *subsystem, const char *id);
+
+extern char *sysfs_get_value(const char *id, char *subsys, char *param);
+extern int sysfs_get_uint(char *id, char *subsys, char *param,
+                         unsigned int *value);
+extern int sysfs_get_int(const char *id, char *subsys, char *param, int *value);
+extern int sysfs_get_str(char *id, char *subsys, char *param, char *value,
+                        int value_size);
+extern int sysfs_get_uint64(char *id, char *subsys, char *param,
+                           uint64_t *value);
+extern int sysfs_get_uint8(char *id, char *subsys, char *param,
+                          uint8_t *value);
+extern int sysfs_get_uint16(char *id, char *subsys, char *param,
+                           uint16_t *value);
+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/pkgs/open-iscsi/open-iscsi-2.1.8/usr/transport.c b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/transport.c
new file mode 100644 (file)
index 0000000..4004582
--- /dev/null
@@ -0,0 +1,256 @@
+/*
+ * iSCSI transport
+ *
+ * Copyright (C) 2006 Mike Christie
+ * Copyright (C) 2006 Red Hat, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <libkmod.h>
+#include <net/if.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include "sysdeps.h"
+#include "iscsi_err.h"
+#include "initiator.h"
+#include "transport.h"
+#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"
+
+struct iscsi_transport_template iscsi_tcp = {
+       .name           = "tcp",
+       .ep_connect     = iscsi_io_tcp_connect,
+       .ep_poll        = iscsi_io_tcp_poll,
+       .ep_disconnect  = iscsi_io_tcp_disconnect,
+};
+
+struct iscsi_transport_template iscsi_iser = {
+       .name           = "iser",
+       .rdma           = 1,
+       .ep_connect     = ktransport_ep_connect,
+       .ep_poll        = ktransport_ep_poll,
+       .ep_disconnect  = ktransport_ep_disconnect,
+       .create_conn    = iser_create_conn,
+};
+
+struct iscsi_transport_template cxgb3i = {
+       .name           = "cxgb3i",
+       .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,
+       .create_conn    = cxgbi_create_conn,
+};
+
+struct iscsi_transport_template cxgb4i = {
+       .name           = "cxgb4i",
+       .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,
+       .create_conn    = cxgbi_create_conn,
+};
+
+struct iscsi_transport_template bnx2i = {
+       .name           = "bnx2i",
+       .set_host_ip    = SET_HOST_IP_REQ,
+       .use_boot_info  = 1,
+        .bind_ep_required = 1,
+       .ep_connect     = ktransport_ep_connect,
+       .ep_poll        = ktransport_ep_poll,
+       .ep_disconnect  = ktransport_ep_disconnect,
+       .set_net_config = uip_broadcast_params,
+       .exec_ping      = uip_broadcast_ping_req,
+};
+
+struct iscsi_transport_template be2iscsi = {
+       .name           = "be2iscsi",
+        .bind_ep_required = 1,
+       .sync_vlan_settings = 1,
+       .create_conn    = be2iscsi_create_conn,
+       .ep_connect     = ktransport_ep_connect,
+       .ep_poll        = ktransport_ep_poll,
+       .ep_disconnect  = ktransport_ep_disconnect,
+};
+
+struct iscsi_transport_template qla4xxx = {
+       .name           = "qla4xxx",
+       .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,
+};
+
+struct iscsi_transport_template qedi = {
+       .name           = "qedi",
+       .set_host_ip    = SET_HOST_IP_REQ,
+       .use_boot_info  = 1,
+       .bind_ep_required = 1,
+       .no_netdev = 1,
+       .ep_connect     = ktransport_ep_connect,
+       .ep_poll        = ktransport_ep_poll,
+       .ep_disconnect  = ktransport_ep_disconnect,
+       .set_net_config = uip_broadcast_params,
+       .exec_ping      = uip_broadcast_ping_req,
+};
+
+static struct iscsi_transport_template *iscsi_transport_templates[] = {
+       &iscsi_tcp,
+       &iscsi_iser,
+       &cxgb3i,
+       &cxgb4i,
+       &bnx2i,
+       &qla4xxx,
+       &be2iscsi,
+       &ocs,
+       &qedi,
+       NULL
+};
+
+int transport_probe_for_offload(void)
+{
+       struct if_nameindex *ifni;
+       char transport_name[ISCSI_TRANSPORT_NAME_MAXLEN];
+       int i, sockfd;
+       struct ifreq if_hwaddr;
+
+       ifni = if_nameindex();
+       if (!ifni) {
+               log_error("Could not search for transport modules: %s",
+                         strerror(errno));
+               return ISCSI_ERR_TRANS_NOT_FOUND;
+       }
+
+       sockfd = socket(AF_INET, SOCK_DGRAM, 0);
+       if (sockfd < 0) {
+               log_error("Could not open socket for ioctl: %s",
+                         strerror(errno));
+               goto free_ifni;
+       }
+
+       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->if_name);
+
+               strlcpy(if_hwaddr.ifr_name, n->if_name, IFNAMSIZ);
+               if (ioctl(sockfd, SIOCGIFHWADDR, &if_hwaddr) < 0)
+                       continue;
+
+               /* check for ARPHRD_ETHER (ethernet) */
+               if (if_hwaddr.ifr_hwaddr.sa_family != 1)
+                       continue;
+
+               if (net_get_transport_name_from_netdev(n->if_name,
+                                                      transport_name))
+                       continue;
+
+               transport_load_kmod(transport_name);
+       }
+       close(sockfd);
+
+free_ifni:
+       if_freenameindex(ifni);
+       return 0;
+}
+
+/*
+ * Most distros still do not have wide libkmod use, so
+ * use modprobe for now
+ */
+int transport_load_kmod(char *transport_name)
+{
+       struct kmod_ctx *ctx;
+       struct kmod_module *mod;
+       int rc;
+
+       ctx = kmod_new(NULL, NULL);
+       if (!ctx) {
+               log_error("Could not load transport module %s. Out of "
+                         "memory.", transport_name);
+               return ISCSI_ERR_NOMEM;
+       }
+
+       kmod_load_resources(ctx);
+
+       /*
+        * dumb dumb dumb - named iscsi_tcp and ib_iser differently from
+        * transport name
+        */
+       if (!strcmp(transport_name, "tcp"))
+               rc = kmod_module_new_from_name(ctx, "iscsi_tcp", &mod);
+       else if (!strcmp(transport_name, "iser"))
+               rc = kmod_module_new_from_name(ctx, "ib_iser", &mod);
+       else
+               rc = kmod_module_new_from_name(ctx, transport_name, &mod);
+       if (rc) {
+               log_error("Failed to load module %s.", transport_name);
+               rc = ISCSI_ERR_TRANS_NOT_FOUND;
+               goto unref_mod;
+       }
+
+       rc = kmod_module_probe_insert_module(mod, KMOD_PROBE_APPLY_BLACKLIST,
+                                            NULL, NULL, NULL, NULL);
+       if (rc) {
+               log_error("Could not insert module %s. Kmod error %d",
+                         transport_name, rc);
+               rc = ISCSI_ERR_TRANS_NOT_FOUND;
+       }
+       kmod_module_unref(mod);
+
+unref_mod:
+       kmod_unref(ctx);
+       return rc;
+}
+
+int set_transport_template(struct iscsi_transport *t)
+{
+       struct iscsi_transport_template *tmpl;
+       int j;
+
+       for (j = 0; iscsi_transport_templates[j] != NULL; j++) {
+               tmpl = iscsi_transport_templates[j];
+
+               if (!strcmp(tmpl->name, t->name)) {
+                       t->template = tmpl;
+                       log_debug(3, "Matched transport %s", t->name);
+                       return 0;
+               }
+       }
+
+       log_error("Could not find template for %s. An updated iscsiadm "
+                 "is probably needed.", t->name);
+       return ENOSYS;
+}
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/transport.h b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/transport.h
new file mode 100644 (file)
index 0000000..0702756
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * iSCSI transport
+ *
+ * Copyright (C) 2006 Mike Christie
+ * Copyright (C) 2006 Red Hat, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+#ifndef ISCSI_TRANSPORT_H
+#define ISCSI_TRANSPORT_H
+
+#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;
+
+struct iscsi_transport_template {
+       const char *name;
+       uint8_t rdma;
+       /*
+        * Drivers should set this if they require iscsid to set
+        * the host's ip address.
+        */
+       uint8_t set_host_ip;
+       uint8_t use_boot_info;
+        uint8_t bind_ep_required;
+       uint8_t no_netdev;
+       /* be2iscsi has a single host vlan setting,
+        * but uses 2 ifaces for ipv4 and ipv6 settings; keep them in sync */
+       uint8_t sync_vlan_settings;
+       int (*ep_connect) (struct iscsi_conn *conn, int non_blocking);
+       int (*ep_poll) (struct iscsi_conn *conn, int timeout_ms);
+       void (*ep_disconnect) (struct iscsi_conn *conn);
+       void (*create_conn) (struct iscsi_conn *conn);
+       int (*set_net_config) (struct iscsi_transport *t,
+                              struct iface_rec *iface,
+                              struct iscsi_session *session);
+       int (*exec_ping) (struct iscsi_transport *t,
+                         struct iface_rec *iface, int datalen,
+                         struct sockaddr_storage *dst_addr, uint32_t *status);
+};
+
+/* represents data path provider */
+struct iscsi_transport {
+       struct list_head list;
+       uint64_t handle;
+       uint32_t caps;
+       char name[ISCSI_TRANSPORT_NAME_MAXLEN];
+       struct list_head sessions;
+       struct iscsi_transport_template *template;
+};
+
+extern int set_transport_template(struct iscsi_transport *t);
+extern int transport_load_kmod(char *transport_name);
+extern int transport_probe_for_offload(void);
+
+#endif
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/types.h b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/types.h
new file mode 100644 (file)
index 0000000..9d9ba86
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2002-2003 Ardis Technolgies <roman@ardistech.com>
+ *
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#ifndef TYPES_H
+#define TYPES_H
+
+#include <netinet/in.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <limits.h>
+
+/*
+ * using the __be types allows stricter static
+ * typechecking in the kernel using sparse
+ */
+typedef uint16_t __be16;
+typedef uint32_t __be32;
+
+#endif /* TYPES_H */
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/uip_mgmt_ipc.c b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/uip_mgmt_ipc.c
new file mode 100644 (file)
index 0000000..003fe42
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * uIP iSCSI Daemon/Admin Management IPC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * See the file COPYING included with this distribution for more details.
+ */
+
+#include <string.h>
+#include <fcntl.h>
+
+#include "log.h"
+#include "uip_mgmt_ipc.h"
+#include "iscsid_req.h"
+#include "iscsi_err.h"
+
+int uip_broadcast_params(__attribute__((unused))struct iscsi_transport *t,
+                        struct iface_rec *iface,
+                        __attribute__((unused))struct iscsi_session *session)
+{
+       struct iscsid_uip_broadcast broadcast;
+
+       log_debug(3, "broadcasting to uip");
+
+       memset(&broadcast, 0, sizeof(broadcast));
+
+       broadcast.header.command = ISCSID_UIP_IPC_GET_IFACE;
+       broadcast.header.payload_len = sizeof(*iface);
+
+       memcpy(&broadcast.u.iface_rec, iface, sizeof(*iface));
+
+       return uip_broadcast(&broadcast,
+                            sizeof(iscsid_uip_broadcast_header_t) +
+                            sizeof(*iface), O_NONBLOCK, NULL);
+}
+
+int uip_broadcast_ping_req(__attribute__((unused))struct iscsi_transport *t,
+                          struct iface_rec *iface, int datalen,
+                          struct sockaddr_storage *dst_addr, uint32_t *status)
+{
+       struct iscsid_uip_broadcast broadcast;
+       int len = 0;
+
+       log_debug(3, "broadcasting ping request to uip\n");
+
+       memset(&broadcast, 0, sizeof(broadcast));
+
+       broadcast.header.command = ISCSID_UIP_IPC_PING;
+       len = sizeof(*iface) + sizeof(*dst_addr) + sizeof(datalen);
+       broadcast.header.payload_len = len;
+
+       memcpy(&broadcast.u.ping_rec.ifrec, iface, sizeof(*iface));
+
+       if (dst_addr->ss_family == PF_INET) {
+               len = sizeof(struct sockaddr_in);
+       } else if (dst_addr->ss_family == PF_INET6) {
+               len = sizeof(struct sockaddr_in6);
+       } else {
+               log_error("%s unknown addr family %d\n",
+                         __FUNCTION__, dst_addr->ss_family);
+               return ISCSI_ERR_INVAL;
+       }
+
+       memcpy(&broadcast.u.ping_rec.ipaddr, dst_addr, len);
+       broadcast.u.ping_rec.datalen = datalen;
+
+       return uip_broadcast(&broadcast,
+                            sizeof(iscsid_uip_broadcast_header_t) +
+                            broadcast.header.payload_len, 0, status);
+}
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/uip_mgmt_ipc.h b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/uip_mgmt_ipc.h
new file mode 100644 (file)
index 0000000..916113d
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * uIP iSCSI Daemon/Admin Management IPC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * See the file COPYING included with this distribution for more details.
+ */
+#ifndef UIP_MGMT_IPC_H
+#define UIP_MGMT_IPC_H
+
+#include "types.h"
+#include "iscsi_if.h"
+#include "config.h"
+#include "mgmt_ipc.h"
+
+#include "initiator.h"
+#include "transport.h"
+
+#define ISCSID_UIP_NAMESPACE   "ISCSID_UIP_ABSTRACT_NAMESPACE"
+
+typedef enum iscsid_uip_cmd {
+       ISCSID_UIP_IPC_UNKNOWN                  = 0,
+       ISCSID_UIP_IPC_GET_IFACE                = 1,
+       ISCSID_UIP_IPC_PING                     = 2,
+
+       __ISCSID_UIP_IPC_MAX_COMMAND
+} iscsid_uip_cmd_e;
+
+typedef struct iscsid_uip_broadcast_header {
+       iscsid_uip_cmd_e command;
+       uint32_t payload_len;
+} iscsid_uip_broadcast_header_t;
+
+/* IPC Request */
+typedef struct iscsid_uip_broadcast {
+       struct iscsid_uip_broadcast_header header;
+
+       union {
+               /* messages */
+               struct ipc_broadcast_iface_rec {
+                       struct iface_rec rec;
+               } iface_rec;
+
+               struct ipc_broadcast_ping_rec {
+                       struct iface_rec ifrec;
+                       struct sockaddr_storage ipaddr;
+                       int datalen;
+                       int *status;
+               } ping_rec;
+       } u;
+} iscsid_uip_broadcast_t;
+
+typedef enum iscsid_uip_mgmt_ipc_err {
+       ISCSID_UIP_MGMT_IPC_OK                     = 0,
+       ISCSID_UIP_MGMT_IPC_ERR                    = 1,
+       ISCSID_UIP_MGMT_IPC_ERR_NOT_FOUND          = 2,
+       ISCSID_UIP_MGMT_IPC_ERR_NOMEM              = 3,
+       ISCSID_UIP_MGMT_IPC_DEVICE_UP              = 4,
+       ISCSID_UIP_MGMT_IPC_DEVICE_INITIALIZING    = 5,
+} iscsid_uip_mgmt_ipc_err_e;
+
+/* IPC Response */
+typedef struct iscsid_uip_mgmt_rsp {
+       iscsid_uip_cmd_e command;
+       iscsid_uip_mgmt_ipc_err_e err;
+       enum iscsi_ping_status_code ping_sc;
+} iscsid_uip_rsp_t;
+
+extern int uip_broadcast_params(struct iscsi_transport *t,
+                               struct iface_rec *iface,
+                               struct iscsi_session *session);
+
+extern int uip_broadcast_ping_req(struct iscsi_transport *t,
+                                 struct iface_rec *iface, int datalen,
+                                 struct sockaddr_storage *dst_addr,
+                                 uint32_t *status);
+
+#endif /* UIP_MGMT_IPC_H */
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/usr/version.h b/pkgs/open-iscsi/open-iscsi-2.1.8/usr/version.h
new file mode 100644 (file)
index 0000000..f8be671
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef ISCSI_VERSION_DEF
+#define ISCSI_VERSION_DEF
+
+/*
+ * iSCSI tools version.
+ * This may not be the same value as the kernel versions because
+ * some other maintainer could merge a patch without going through us
+ *
+ * Version string should be set by the build system, else we have problems
+ */
+#ifndef        ISCSI_VERSION_STR
+#error Must set ISCSI_VERSION_STR
+#endif
+#define ISCSI_VERSION_FILE     "/sys/module/scsi_transport_iscsi/version"
+
+#endif
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/utils/.gitignore b/pkgs/open-iscsi/open-iscsi-2.1.8/utils/.gitignore
new file mode 100644 (file)
index 0000000..7b4beea
--- /dev/null
@@ -0,0 +1,4 @@
+iscsi-iname
+50-iscsi-firmware-login.rules
+iscsi-gen-initiatorname.sh
+iscsi_fw_login.sh
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/utils/50-iscsi-firmware-login.rules.template b/pkgs/open-iscsi/open-iscsi-2.1.8/utils/50-iscsi-firmware-login.rules.template
new file mode 100644 (file)
index 0000000..9fa1e7d
--- /dev/null
@@ -0,0 +1,15 @@
+# This file contains the rules to handle iscsi firmware changes
+
+# DO NOT WRAP THIS LINE
+#
+# old udev does not understand some of it,
+# and would end up skipping only some lines, not the full rule.
+# which can cause all sort of trouble with strange-named device nodes
+# for completely unrelated devices,
+# resulting in unusable network lookback, etc.
+#
+# in case this is "accidentally" installed on a system with old udev,
+# having it as one single line avoids those problems.
+#
+# DO NOT WRAP THIS LINE
+SUBSYSTEM=="iscsi_boot*", ACTION=="add", DEVPATH=="*/target*", RUN+="@SBINDIR@/iscsi_fw_login"
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/utils/Makefile b/pkgs/open-iscsi/open-iscsi-2.1.8/utils/Makefile
new file mode 100644 (file)
index 0000000..b4f09b3
--- /dev/null
@@ -0,0 +1,82 @@
+# This Makefile will work only with GNU make.
+#
+# Make file for the util sub-directory
+#
+# This make file does not control the sysdeps
+# subdirectory, which is controlled
+# from the top-level make file.
+#
+
+SED ?= sed
+INSTALL = install
+CHMOD = chmod
+
+DESTDIR ?=
+SBINDIR ?= /sbin
+etcdir = /etc
+HOMEDIR ?= $(etcdir)/iscsi
+
+RULESDIR ?= $(etcdir)/udev/rules.d
+
+CFLAGS ?= -O2 -fno-inline -g
+CFLAGS += -Wall -Wextra -Wstrict-prototypes
+
+PROGRAMS       = iscsi-iname
+PROGRAMS_DEST  = $(addprefix $(DESTDIR)$(SBINDIR)/,$(PROGRAMS))
+
+SCRIPTS_SOURCES                = iscsi_discovery.sh iscsi_offload.sh
+SCRIPTS_TEMPLATES      = iscsi_fw_login.sh.template iscsi-gen-initiatorname.sh.template
+SCRIPTS_GENERATED      = $(SCRIPTS_TEMPLATES:.template=)
+SCRIPTS_DEST           = $(addprefix $(DESTDIR)$(SBINDIR)/,$(basename $(SCRIPTS_GENERATED))) \
+                         $(addprefix $(DESTDIR)$(SBINDIR)/,$(basename $(SCRIPTS_SOURCES)))
+
+RULESFILES_TEMPLATES   = 50-iscsi-firmware-login.rules.template
+RULESFILES_GENERATED   = $(RULESFILES_TEMPLATES:.template=)
+RULESFILES_DEST                = $(addprefix $(DESTDIR)$(RULESDIR)/,$(RULESFILES_GENERATED))
+
+OBJS = iscsi-iname.o md5.o
+
+all: $(PROGRAMS) $(SCRIPTS_GENERATED) $(RULESFILES_GENERATED)
+
+$(SCRIPTS_GENERATED): %.sh: %.sh.template
+       $(SED) -e 's:@SBINDIR@:$(SBINDIR):' -e 's:@HOMEDIR@:$(HOMEDIR):' $? > $@
+       $(CHMOD) 755 $@
+
+$(RULESFILES_GENERATED): %.rules: %.rules.template
+       $(SED) -e 's:@SBINDIR@:$(SBINDIR):' $? > $@
+
+iscsi-iname: $(OBJS)
+       $(CC) $(CFLAGS) $(LDFLAGS) $^ $(DBM_LIB) -o $@
+
+install: $(DESTDIR)$(SBINDIR) $(DESTDIR)$(RULESDIR) \
+       $(PROGRAMS_DEST) $(SCRIPTS_DEST) $(RULESFILES_DEST)
+
+$(PROGRAMS_DEST): $(DESTDIR)$(SBINDIR)/%: %
+       $(INSTALL) -m 755 $? $@
+
+$(SCRIPTS_DEST): $(DESTDIR)$(SBINDIR)/%: %.sh
+       $(INSTALL) -m 755 $? $@
+
+install_udev_rules: $(RULESFILES_DEST)
+
+$(RULESFILES_DEST): $(DESTDIR)$(RULESDIR)/%: %
+       $(INSTALL) -m 644 $? $@
+
+$(DESTDIR)$(SBINDIR) $(DESTDIR)$(RULESDIR):
+       [ -d $@ ] || $(INSTALL) -d $@
+
+clean:
+       $(RM) $(OBJS)
+       $(RM) $(PROGRAMS)
+       $(RM) .depend
+
+distclean:
+       $(RM) $(SCRIPTS_GENERATED)
+       $(RM) $(RULESFILES_GENERATED)
+
+.PHONY: all install clean distclean depend install_udev_rules
+
+depend:
+       $(CC) $(CFLAGS) -M `ls *.c` > .depend
+
+-include .depend
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/utils/iscsi-gen-initiatorname.sh.template b/pkgs/open-iscsi/open-iscsi-2.1.8/utils/iscsi-gen-initiatorname.sh.template
new file mode 100644 (file)
index 0000000..5c2bfdf
--- /dev/null
@@ -0,0 +1,188 @@
+#!/bin/bash
+#
+# iscsi-gen-initiatorname
+#
+# Generate a default iSCSI Initiatorname for Linux installations.
+#
+# Copyright (c) 2022 Hannes Reinecke, SUSE Labs
+# This script is licensed under the GPL.
+#
+# external programs required:
+#   * iscsi-iname (if needed to generate a new InitiatorName)
+#
+
+NAME=${0##*/}
+INAME_DIR="@HOMEDIR@"
+INAME_FILE="$INAME_DIR/initiatorname.iscsi"
+
+# our default IQN prefix
+DEFAULT_IQN_PREFIX="iqn.1996-04.de.suse:01"
+
+#
+# set up comments for initiatorname files using variables
+# instead of HERE documents, since we may be running when
+# temp filename space is read-only
+#
+
+KERNEL_COMMENTS="\
+##
+## iSCSI Initiatorname taken from Kernel Command line.
+##
+## DO NOT EDIT OR REMOVE THIS FILE!
+## If you remove this file, the iSCSI daemon will not start.
+## Any change here may be overwritten at next boot, if
+## the kernel command-line parameter is passed in, again.
+## If a different initiatorname is required please change the
+## initiatorname on the kernel command line and call:
+##   # iscsi-gen-initiatorname -f
+## to recreate an updated version of this file.
+##"
+
+IBFT_COMMENTS="\
+##
+## 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:
+##   # iscsi-gen-initiatorname -f
+## to recreate an updated version of this file.
+##"
+
+NORMAL_COMMENTS="\
+##
+## 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."
+
+# where iBFT initiator name file would live, if present
+IBFT_SYSFS_DIR=/sys/firmware/ibft/initiator
+
+#
+# print usage and exit
+#
+# usage: usage_and_exit EXIT_VALUE
+#
+usage_and_exit()
+{
+    xit_val=$1
+
+    echo "Usage: $NAME [OPTIONS] -- generate an iSCSI initiatorname"
+    echo "Where OPTIONS are from:"
+    echo "   -h          print usage and exit"
+    echo "   -f          overwrite existing InitiatorName, if any"
+    echo "   -p IQN-PRE  set prefix for generated IQN (default ${DEFAULT_IQN_PREFIX})"
+    exit $xit_val
+}
+
+#
+# get kernel command-line-supplied initiatorname, if any
+#
+# usage: INAME=$(kernel_supplied_initiatorname)
+#
+kernel_supplied_initiatorname()
+{
+    kcl="$(</proc/cmdline)"
+    if [[ "$kcl" =~ rd.initiatorname ]] ; then
+       kcl=${kcl##*rd.initiatorname=}
+       echo ${kcl%% *}
+    else
+       echo ""
+    fi
+}
+
+#
+# start
+#
+
+while getopts "hfp:" o ; do
+    case "${o}" in
+       h) usage_and_exit 0 ;;
+       f) FORCE=1 ;;
+       p) IQN_PREFIX=${OPTARG} ;;
+       ?) usage_and_exit 1 ;;
+    esac
+done
+shift $(($OPTIND-1))
+
+if [ "$#" -gt 0 ] ; then
+    echo "Error: Invalid argument(s): $*" 1>&2
+    usage_and_exit 1
+fi
+
+if [ "$EUID" -ne 0 ] ; then
+    echo "Error: You must be root to run this command" 1>&2
+    usage_and_exit 1
+fi
+
+# use prefix passed in, if any, else our default
+: ${IQN_PREFIX:=${DEFAULT_IQN_PREFIX}}
+
+# get kernel command-line-supplied initiator name, if any
+KERNEL_INAME="$(kernel_supplied_initiatorname)"
+
+# get the iBFT initiator name, if present
+[ -d $IBFT_SYSFS_DIR ] && read IBFT_INAME < $IBFT_SYSFS_DIR/initiator-name
+
+# get the systemd-supplied initiator name, if present (as InitiatorName)
+[ -r "$INAME_FILE" ] && . "$INAME_FILE"
+
+# if we have a local initiator name and "force" is not set end it now
+if [ "$InitiatorName" -a -z "$FORCE" ] ; then
+    echo "Error: you cannot overwrite the current InitiatorName unless 'force' is set." 1>&2
+    usage_and_exit 1
+fi
+
+# ensure we can write the initiator name file
+if [ -r "$INAME_FILE" ] ; then
+    if [ ! -w "$INAME_FILE" ] ; then
+       echo "Error: cannot update InitiatorName, write protected: $INAME_FILE" 1>&1
+       echo "Please ensure the filesystem is read/write." 1>&2
+       exit 1
+    fi
+    # the file exists but we can write over it
+elif [ ! -w "$INAME_DIR" ] ; then
+    echo "Error: no write permission in directory: $INAME_DIR" 1>&2
+    echo "Please ensure the filesystem is read/write." 1>&2
+    exit 1
+fi
+
+# if we have both iBFT and kernel command line initiator names that
+# do not match end it now
+if [ "$IBFT_INAME" -a "$KERNEL_INAME" -a "$IBFT_INAME" != "$KERNEL_INAME" ] ; then
+    echo "Error: Kernel cmdline Initiator Name: $KERNEL_INAME" 1>&2
+    echo "  does not match iBFT Initiator Name: $IBFT_INAME" 1>&2
+    echo "Please ensure they both match, or remove the kernel parameter, then" 1>&2
+    echo "  run '$NAME [-f]' to update iSCSI InitiatorName" 1>&2
+    exit 1
+fi
+
+# now we know we want to write the initiator name
+
+# handle a write failure on this first write attempt to the initiator name
+# file, in *case* it we somehow missed that it is not writable
+echo "##" > $INAME_FILE || exit 1
+
+if [ "$KERNEL_INAME" ] ; then
+    echo "## $INAME_FILE" >> $INAME_FILE
+    echo "$KERNEL_COMMENTS" >> $INAME_FILE
+    echo "InitiatorName=$KERNEL_INAME" >> $INAME_FILE
+elif [ "$IBFT_INAME" ] ; then
+    echo "## $INAME_FILE" >> $INAME_FILE
+    echo "$IBFT_COMMENTS" >> $INAME_FILE
+    echo "InitiatorName=$IBFT_INAME" >> $INAME_FILE
+else
+    echo "## $INAME_FILE" >> $INAME_FILE
+    echo "$NORMAL_COMMENTS" >> $INAME_FILE
+    # create a unique initiator name using iscsi-iname
+    INAME=$(@SBINDIR@/iscsi-iname -p "$IQN_PREFIX")
+    echo "InitiatorName=$INAME" >> $INAME_FILE
+fi
+
+chmod 0600 $INAME_FILE
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/utils/iscsi-iname.c b/pkgs/open-iscsi/open-iscsi-2.1.8/utils/iscsi-iname.c
new file mode 100644 (file)
index 0000000..c241aaf
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ * iSCSI InitiatorName creation utility
+ * Copyright (C) 2001 Cisco Systems, Inc.
+ * maintained by linux-iscsi-devel@lists.sourceforge.net
+ *
+ * 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.
+ *
+ * $Id: iscsi-iname.c,v 1.1.2.3 2005/03/15 06:33:44 wysochanski Exp $
+ *
+ * iscsi-iname.c - Compute an iSCSI InitiatorName for this host.
+ * Note that to ensure uniqueness, the system time is
+ * a factor.  This name must be cached and only regenerated
+ * if there is no cached value.
+ */
+
+#include <stdint.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/utsname.h>
+#include <sys/time.h>
+#include <getopt.h>
+#include <stdbool.h>
+
+#include "md5.h"
+
+#define RANDOM_NUM_GENERATOR   "/dev/urandom"
+
+#define DEFAULT_PREFIX         "iqn.2016-04.com.open-iscsi"
+
+/* iSCSI names have a maximum length of 223 characters, we reserve 13 to append
+ * a seperator and 12 characters (6 random bytes in hex representation) */
+#define PREFIX_MAX_LEN 210
+
+static void usage(void)
+{
+       fprintf(stderr, "Usage: iscsi-iname [OPTIONS]\n");
+       fprintf(stderr, "Where OPTIONS are from:\n");
+       fprintf(stderr, "    -p/--prefix <prefix>          -- set IQN prefix [%s]\n",
+                       DEFAULT_PREFIX);
+       fprintf(stderr, "    -g/--generate-iname-prefix    -- generate the InitiatorName= prefix\n");
+       fprintf(stderr, "where <prefix> has max length of %d\n",
+               PREFIX_MAX_LEN);
+}
+
+int
+main(int argc, char *argv[])
+{
+       struct timeval time;
+       struct utsname system_info;
+       long hostid;
+       struct MD5Context context;
+       unsigned char digest[16];
+       unsigned char *bytes = digest;
+       unsigned char entropy[16];
+       int e;
+       int fd;
+       char *prefix = DEFAULT_PREFIX;
+       int c;
+       char *short_options = "p:gh";
+       struct option const long_options[] = {
+               {"help", no_argument, NULL, 'h'},
+               {"prefix", required_argument, NULL, 'p'},
+               {"generate-iname-prefix", no_argument, NULL, 'g'},
+               {NULL, 0, NULL, 0}
+       };
+       bool generate_iname_prefix = false;
+
+       /* initialize */
+       memset(digest, 0, sizeof (digest));
+       memset(&context, 0, sizeof (context));
+       MD5Init(&context);
+
+       /* take a prefix if given, otherwise use a default. */
+       while ((c = getopt_long(argc, argv, short_options, long_options, NULL)) >= 0) {
+               switch (c) {
+               case 'p':
+                       prefix = optarg;
+                       if (strnlen(prefix, PREFIX_MAX_LEN + 1) > PREFIX_MAX_LEN) {
+                               fprintf(stderr, "error: prefix too long\n");
+                               usage();
+                               exit(1);
+                       }
+                       break;
+               case 'h':
+                       usage();
+                       exit(0);
+               case 'g':
+                       generate_iname_prefix = true;
+                       break;
+               default:
+               case '?':
+                       usage();
+                       exit(1);
+               }
+       }
+       if (optind < argc) {
+               fprintf(stderr, "unknown argument(s)\n");
+               usage();
+               exit(1);
+       }
+
+       /* try to feed some entropy from the pool to MD5 in order to get
+        * uniqueness properties
+        */
+
+       fd = open(RANDOM_NUM_GENERATOR, O_RDONLY);
+       if (fd != -1) {
+               e = read(fd, &entropy, 16);
+               if (e >= 1)
+                       MD5Update(&context, (md5byte *)entropy, e);
+               close(fd);
+       }
+
+       /* time the name is created is a factor in order to get
+        * uniqueness properties
+        */
+       if (gettimeofday(&time, NULL) < 0) {
+               perror("error: gettimeofday failed");
+               return 1;
+       }
+       MD5Update(&context, (md5byte *) & time.tv_sec, sizeof (time.tv_sec));
+       MD5Update(&context, (md5byte *) & time.tv_usec, sizeof (time.tv_usec));
+
+       /* hostid */
+       hostid = gethostid();
+       MD5Update(&context, (md5byte *) & hostid, sizeof (hostid));
+
+       /* get the hostname and system name */
+       if (uname(&system_info) < 0) {
+               perror("error: uname failed");
+               return 1;
+       }
+       MD5Update(&context, (md5byte *) system_info.sysname,
+                 sizeof (system_info.sysname));
+       MD5Update(&context, (md5byte *) system_info.nodename,
+                 sizeof (system_info.nodename));
+       MD5Update(&context, (md5byte *) system_info.release,
+                 sizeof (system_info.release));
+       MD5Update(&context, (md5byte *) system_info.version,
+                 sizeof (system_info.version));
+       MD5Update(&context, (md5byte *) system_info.machine,
+                 sizeof (system_info.machine));
+
+       /* compute the md5 hash of all the bits we just collected */
+       MD5Final(digest, &context);
+
+       /* vary which md5 bytes we pick (though we probably don't need to do
+        * this, since hopefully MD5 produces results such that each byte is as
+        * good as any other).
+        */
+
+       fd = open(RANDOM_NUM_GENERATOR, O_RDONLY);
+       if (fd != -1) {
+               if (read(fd, entropy, 1) == 1)
+                       bytes = &digest[(entropy[0] % (sizeof(digest) - 6))];
+               close(fd);
+       }
+
+       /* print the prefix followed by 6 bytes of the MD5 hash */
+       printf("%s%s:%x%x%x%x%x%x\n",
+               generate_iname_prefix ? "InitiatorName=" : "",
+               prefix,
+               bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5]);
+       return 0;
+}
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/utils/iscsi_discovery.sh b/pkgs/open-iscsi/open-iscsi-2.1.8/utils/iscsi_discovery.sh
new file mode 100755 (executable)
index 0000000..be2f390
--- /dev/null
@@ -0,0 +1,195 @@
+#!/bin/bash
+#
+# Copyright (C) Voltaire Ltd. 2006.  ALL RIGHTS RESERVED.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#
+# Author: Dan Bar Dov <danb@voltaire.com>
+
+# iscsi_discovery:
+#    * does a send-targets discovery to the given IP
+#    * set the transport type to the preferred transport (or tcp is -t flag is not used)
+#    * tries to login
+#    * if succeeds,
+#          o logout,
+#          o mark record autmatic (unless -m flag is used)
+#    * else
+#          o reset transport type to TCP
+#          o try to login
+#          o if succeeded
+#                + logout
+#                + mark record automatic (unless -m flag is used)
+#
+
+usage()
+{
+       echo "Usage: $0 <IP> [-p <port>] [-d] [-t <tcp|iser> [-f]] [-m] [-l]"
+       echo "Options:"
+       echo  "-p               set the port number (default is 3260)."
+       echo  "-d               print debugging information"
+       echo  "-t               set transport (default is tcp)."
+       echo  "-f               force specific transport -disable the fallback to tcp (default is fallback enabled)."
+       echo  "                 force the transport specified by the argument of the -t flag."
+       echo  "-m               manual startup - will set manual startup (default is automatic startup)."
+       echo  "-l               login to the new discovered nodes (default is false)."
+}
+
+dbg()
+{
+       $debug && echo $@
+}
+
+initialize()
+{
+       trap "exit" 2
+       debug=false
+       force="0"
+       log_out="1"
+       startup_manual="0"
+       #set default transport to tcp
+       transport=tcp
+       #set default port to 3260
+       port=3260;
+}
+
+parse_cmdline()
+{
+       if [ $# -lt 1 ]; then
+               usage
+               exit 1
+       fi
+
+       # check if the IP address is valid
+       ip=`echo $1 | awk -F'.' '$1 != "" && $1 <=255 && $2 != "" && $2 <= 255 && $3 != "" && $3 <= 255 && $4 != "" && $4 <= 255 {print $0}'`
+       if [ -z "$ip" ]; then
+               echo "$1 is not a vaild IP address!"
+               exit 1
+       fi
+       shift
+       while getopts "dfmlt:p:" options; do
+        case $options in
+               d ) debug=true;;
+               f ) force="1";;
+               t ) transport=$OPTARG;;
+               p ) port=$OPTARG;;
+               m ) startup_manual="1";;
+               l ) log_out=0;;
+               \? ) usage
+                       exit 1;;
+               * )  usage
+                       exit 1;;
+        esac
+       done
+}
+
+discover()
+{
+       # If open-iscsi is already logged in to the portal, exit
+       if [ $(iscsiadm -m session | grep -c ${ip}:${port}) -ne 0 ]; then
+               echo "Please logout from all targets on ${ip}:${port} before trying to run discovery on that portal"
+               exit 2
+       fi
+
+       connected=0
+       discovered=0
+
+       dbg "starting discovery to $ip"
+       disc="$(iscsiadm -m discovery --type sendtargets --portal ${ip}:${port})"
+       echo "${disc}" | while read portal target
+       do
+               portal=${portal%,*}
+               select_transport
+       done
+
+       discovered=$(echo "${disc}" | wc -l)
+       if [ ${discovered} = 0 ]; then
+               echo "failed to discover targets at ${ip}"
+               exit 2
+       else
+               echo "discovered ${discovered} targets at ${ip}"
+       fi
+}
+
+try_login()
+{
+       if [ "$startup_manual" != "1" ]; then
+               iscsiadm -m node --targetname ${target} --portal ${portal} --op update -n node.conn[0].startup -v automatic
+       fi
+       iscsiadm -m node --targetname ${target} --portal ${portal} --login >/dev/null 2>&1
+       ret=$?
+       if [ ${ret} = 0 ]; then
+               echo "Set target ${target} to automatic login over ${transport} to portal ${portal}"
+               ((connected++))
+               if [ "$log_out" = "1" ]; then
+                       iscsiadm -m node --targetname ${target} --portal ${portal} --logout
+               fi
+       else
+               echo "Cannot login over ${transport} to portal ${portal}"
+               iscsiadm -m node --targetname ${target} --portal ${portal} --op update -n node.conn[0].startup -v manual
+       fi
+       return ${ret}
+}
+
+set_transport()
+{
+       transport=$1
+       case "$transport" in
+       iser)
+               # iSER does not use digest
+               iscsiadm -m node --targetname ${target} --portal ${portal} \
+                       --op update -n node.conn[0].iscsi.HeaderDigest -v None
+               iscsiadm -m node --targetname ${target} --portal ${portal} \
+                       --op update -n node.conn[0].iscsi.DataDigest -v None
+               ;;
+       cxgb3i)
+               # cxgb3i supports <= 16K packet (BHS + AHS + pdu payload + digests)
+               iscsiadm -m node --targetname ${target} --portal ${portal} \
+                       --op update -n node.conn[0].iscsi.MaxRecvDataSegmentLength \
+                       -v 8192
+               ;;
+       esac
+       transport_name=`iscsiadm  -m node -p ${portal} -T ${target} |awk '/transport_name/ {print $1}'`
+       iscsiadm -m node --targetname ${target} --portal ${portal} \
+                       --op update -n ${transport_name} -v ${transport}
+}
+
+select_transport()
+{
+       set_transport $transport
+       dbg "Testing $transport-login to target ${target} portal ${portal}"
+       try_login;
+       if [ $? != 0 -a  "$force" = "0" ]; then
+               set_transport tcp
+               dbg "starting to test tcp-login to target ${target} portal ${portal}"
+               try_login;
+       fi
+}
+
+check_iscsid()
+{
+       #check if iscsid is running
+       pidof iscsid &>/dev/null
+       ret=$?
+       if [ $ret -ne 0 ]; then
+               echo "iscsid is not running"
+               echo "Exiting..."
+               exit 1
+       fi
+}
+
+check_iscsid
+initialize
+parse_cmdline "$@"
+discover
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/utils/iscsi_fw_login.sh.template b/pkgs/open-iscsi/open-iscsi-2.1.8/utils/iscsi_fw_login.sh.template
new file mode 100644 (file)
index 0000000..aae9e4c
--- /dev/null
@@ -0,0 +1,12 @@
+#!/bin/bash
+#
+# iscsi_fw_login -- login to iscsi firmware targets, if any
+#
+# This script is called when udev discovers a new iscsi
+# firmware target
+#
+
+ARGS="-m fw -l"
+ISCSIADM="@SBINDIR@/iscsiadm"
+
+$ISCSIADM $ARGS
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/utils/iscsi_offload.sh b/pkgs/open-iscsi/open-iscsi-2.1.8/utils/iscsi_offload.sh
new file mode 100755 (executable)
index 0000000..1869fe1
--- /dev/null
@@ -0,0 +1,384 @@
+#!/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
+    local olemacoffset=$3
+
+    ifmac=$(ip addr show dev $if | sed -n 's/ *link\/ether \(.*\) brd.*/\1/p')
+    m5=$(( 0x${ifmac##*:} ))
+    m5=$(( $m5 + $olemacoffset ))
+    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
+       ;;
+    qed*)
+       mod=qedi
+       ;;
+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 1)
+elif [ "$mod" = "qla4xxx" ] ; then
+    mac=$(iscsi_macaddress_from_pcifn $pcipath $IFNAME 1)
+elif [ "$mod" = "qede" -o "$mod" = "qedi" ] ; then
+    mac=$(iscsi_macaddress_from_pcifn $pcipath $IFNAME 4)
+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/pkgs/open-iscsi/open-iscsi-2.1.8/utils/md5.c b/pkgs/open-iscsi/open-iscsi-2.1.8/utils/md5.c
new file mode 100644 (file)
index 0000000..cbe8d08
--- /dev/null
@@ -0,0 +1,242 @@
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest.  This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ *
+ * Changed so as no longer to depend on Colin Plumb's `usual.h' header
+ * definitions; now uses stuff from dpkg's config.h.
+ *  - Ian Jackson <ijackson@nyx.cs.du.edu>.
+ * Still in the public domain.
+ */
+
+#include <string.h>
+
+#include "md5.h"
+
+#if (__BYTE_ORDER == __BIG_ENDIAN)
+/*
+ * we can compile this away for little endian since
+ * it does not do anything on those archs
+ */
+void
+byteSwap(uint32_t * buf, unsigned words)
+{
+       md5byte *p = (md5byte *) buf;
+
+       do {
+               *buf++ = (uint32_t) ((unsigned) p[3] << 8 | p[2]) << 16 |
+                   ((unsigned) p[1] << 8 | p[0]);
+               p += 4;
+       } while (--words);
+}
+#else
+#define byteSwap(buf,words)
+#endif
+
+/*
+ * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+void
+MD5Init(struct MD5Context *ctx)
+{
+       ctx->buf[0] = 0x67452301;
+       ctx->buf[1] = 0xefcdab89;
+       ctx->buf[2] = 0x98badcfe;
+       ctx->buf[3] = 0x10325476;
+
+       ctx->bytes[0] = 0;
+       ctx->bytes[1] = 0;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void
+MD5Update(struct MD5Context *ctx, md5byte const *buf, unsigned len)
+{
+       uint32_t t;
+
+       /* Update byte count */
+
+       t = ctx->bytes[0];
+       if ((ctx->bytes[0] = t + len) < t)
+               ctx->bytes[1]++;        /* Carry from low to high */
+
+       t = 64 - (t & 0x3f);    /* Space available in ctx->in (at least 1) */
+       if (t > len) {
+               memcpy((md5byte *) ctx->in + 64 - t, buf, len);
+               return;
+       }
+       /* First chunk is an odd size */
+       memcpy((md5byte *) ctx->in + 64 - t, buf, t);
+       byteSwap(ctx->in, 16);
+       MD5Transform(ctx->buf, ctx->in);
+       buf += t;
+       len -= t;
+
+       /* Process data in 64-byte chunks */
+       while (len >= 64) {
+               memcpy(ctx->in, buf, 64);
+               byteSwap(ctx->in, 16);
+               MD5Transform(ctx->buf, ctx->in);
+               buf += 64;
+               len -= 64;
+       }
+
+       /* Handle any remaining bytes of data. */
+       memcpy(ctx->in, buf, len);
+}
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern 
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+void
+MD5Final(md5byte digest[16], struct MD5Context *ctx)
+{
+       int count = ctx->bytes[0] & 0x3f;       /* Number of bytes in ctx->in */
+       md5byte *p = (md5byte *) ctx->in + count;
+
+       /* Set the first char of padding to 0x80.  There is always room. */
+       *p++ = 0x80;
+
+       /* Bytes of padding needed to make 56 bytes (-8..55) */
+       count = 56 - 1 - count;
+
+       if (count < 0) {        /* Padding forces an extra block */
+               memset(p, 0, count + 8);
+               byteSwap(ctx->in, 16);
+               MD5Transform(ctx->buf, ctx->in);
+               p = (md5byte *) ctx->in;
+               count = 56;
+       }
+       memset(p, 0, count);
+       byteSwap(ctx->in, 14);
+
+       /* Append length in bits and transform */
+       ctx->in[14] = ctx->bytes[0] << 3;
+       ctx->in[15] = ctx->bytes[1] << 3 | ctx->bytes[0] >> 29;
+       MD5Transform(ctx->buf, ctx->in);
+
+       byteSwap(ctx->buf, 4);
+       memcpy(digest, ctx->buf, 16);
+       memset(ctx, 0, sizeof (*ctx));  /* In case it's sensitive */
+}
+
+#ifndef ASM_MD5
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f,w,x,y,z,in,s) \
+        (w += f(x,y,z) + in, w = (w<<s | w>>(32-s)) + x)
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data.  MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+void
+MD5Transform(uint32_t buf[4], uint32_t const in[16])
+{
+       register uint32_t a, b, c, d;
+
+       a = buf[0];
+       b = buf[1];
+       c = buf[2];
+       d = buf[3];
+
+       MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
+       MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
+       MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
+       MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
+       MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
+       MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
+       MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
+       MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
+       MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
+       MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
+       MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+       MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+       MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+       MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+       MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+       MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+       MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
+       MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
+       MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+       MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
+       MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
+       MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
+       MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+       MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
+       MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
+       MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+       MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
+       MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
+       MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+       MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
+       MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
+       MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+       MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
+       MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
+       MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+       MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+       MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
+       MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
+       MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
+       MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+       MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+       MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
+       MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
+       MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
+       MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
+       MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+       MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+       MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
+
+       MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
+       MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
+       MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+       MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
+       MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+       MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
+       MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+       MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
+       MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
+       MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+       MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
+       MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+       MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
+       MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+       MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
+       MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
+
+       buf[0] += a;
+       buf[1] += b;
+       buf[2] += c;
+       buf[3] += d;
+}
+
+#endif
diff --git a/pkgs/open-iscsi/open-iscsi-2.1.8/utils/md5.h b/pkgs/open-iscsi/open-iscsi-2.1.8/utils/md5.h
new file mode 100644 (file)
index 0000000..7a204e9
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * This is the header file for the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest.  This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ *
+ * Changed so as no longer to depend on Colin Plumb's `usual.h'
+ * header definitions; now uses stuff from dpkg's config.h
+ *  - Ian Jackson <ijackson@nyx.cs.du.edu>.
+ * Still in the public domain.
+ */
+
+#ifndef MD5_H
+#define MD5_H
+
+#include <stdint.h>
+
+#define md5byte unsigned char
+
+struct MD5Context {
+       uint32_t buf[4];
+       uint32_t bytes[2];
+       uint32_t in[16];
+};
+
+void MD5Init(struct MD5Context *context);
+void MD5Update(struct MD5Context *context, md5byte const *buf, unsigned len);
+void MD5Final(unsigned char digest[16], struct MD5Context *context);
+void MD5Transform(uint32_t buf[4], uint32_t const in[16]);
+
+#endif                         /* !MD5_H */