diff --git a/Distribution/package.sh b/Distribution/package.sh
index ab498fb7..92825be4 100755
--- a/Distribution/package.sh
+++ b/Distribution/package.sh
@@ -1,7 +1,7 @@
# Package parameters
NAME="iSCSI Initiator for OS X"
BUNDLE_ID="com.github.iscsi-osx.iSCSIInitiator"
-VERSION="1.0.0-beta3"
+VERSION="1.0.0-beta4"
# Output of final DMG
RELEASE="../Release"
diff --git a/Source/Kernel/Info.plist b/Source/Kernel/Info.plist
index 4a560c89..a1385813 100644
--- a/Source/Kernel/Info.plist
+++ b/Source/Kernel/Info.plist
@@ -56,7 +56,7 @@
IOProviderClass
${NAME_PREFIX_U}_iSCSIInitiator
IOUserClientClass
- ${NAME_PREFIX_U}_iSCSIInitiatorClient
+ ${NAME_PREFIX_U}_iSCSIHBAUserClient
Protocol Characteristics
Physical Interconnect
diff --git a/Source/Kernel/iSCSIHBATypes.h b/Source/Kernel/iSCSIHBATypes.h
new file mode 100644
index 00000000..6a62efa3
--- /dev/null
+++ b/Source/Kernel/iSCSIHBATypes.h
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2016, Nareg Sinenian
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.
+ */
+
+#ifndef __ISCSI_HBA_TYPES_H__
+#define __ISCSI_HBA_TYPES_H__
+
+// If used in user-space, this header will need to include additional
+// headers that define primitive fixed-size types. If used with the kernel,
+// IOLib must be included for kernel memory allocation
+#ifdef KERNEL
+#include
+#else
+#include
+#include
+#endif
+
+// Kernel and user iSCSI types (shared)
+#include "iSCSITypesShared.h"
+#include "iSCSIKernelClasses.h"
+
+#include
+
+/*! Notification types send from the kernel to the user-space daemon. */
+enum iSCSIHBANotificationTypes {
+
+ /*! An asynchronous iSCSI message. */
+ kiSCSIHBANotificationAsyncMessage,
+
+ /*! Notifies clients that the kernel extension or controller is going
+ * shut down. Clients should release all resources. */
+ kiSCSIHBANotificationTerminate,
+
+ /*! Notifies clients that a network connnectivity issue has
+ * caused the specified connection and session to be dropped. */
+ kiSCSIHBANotificationTimeout,
+
+ /*! Invalid notification message. */
+ kiSCSIHBANotificationInvalid
+};
+
+
+/*! Used to pass notifications from the kernel to the user-space daemon.
+ * The notification type is one of the notification types listed in
+ * the enumerated type iSCSINotificationTypes. */
+typedef struct {
+
+ /*! Message haeder. */
+ mach_msg_header_t header;
+
+ /*! The notification type. */
+ UInt8 notificationType;
+
+ /*! Parameter associated with the notification (notification-specific). */
+ UInt64 parameter1;
+
+ /*! Parameter associated with the notification (notification-specific). */
+ UInt64 parameter2;
+
+ /*! Session identifier. */
+ SessionIdentifier sessionId;
+
+ /*! Connection identifier. */
+ ConnectionIdentifier connectionId;
+
+} iSCSIHBANotificationMessage;
+
+
+/*! Used to pass notifications from the kernel to the user-space daemon.
+ * The notification type is one of the notification types listed in
+ * the enumerated type iSCSINotificationTypes. */
+typedef struct {
+
+ /*! The notification type. */
+ UInt8 notificationType;
+
+ /*! An asynchronous event code, see iSCSIPDUAsyncEvent. */
+ UInt64 asyncEvent;
+
+ /*! The logical unit identifier associated with the notification (this
+ * field is only populated for SCSI async messages and ignored for all
+ * other types of asyncEvents). */
+ UInt64 LUN;
+
+ /*! Session identifier. */
+ SessionIdentifier sessionId;
+
+ /*! Connection identifier. */
+ ConnectionIdentifier connectionId;
+
+} iSCSIHBANotificationAsyncMessage;
+
+
+/*! Function pointer indices. These are the functions that can be called
+ * indirectly by calling IOCallScalarMethod(). */
+enum functionNames {
+ kiSCSIOpenInitiator,
+ kiSCSICloseInitiator,
+ kiSCSICreateSession,
+ kiSCSIReleaseSession,
+ kiSCSISetSessionParameter,
+ kiSCSIGetSessionParameter,
+ kiSCSICreateConnection,
+ kiSCSIReleaseConnection,
+ kiSCSIActivateConnection,
+ kiSCSIActivateAllConnections,
+ kiSCSIDeactivateConnection,
+ kiSCSIDeactivateAllConnections,
+ kiSCSISendBHS,
+ kiSCSISendData,
+ kiSCSIRecvBHS,
+ kiSCSIRecvData,
+ kiSCSISetConnectionParameter,
+ kiSCSIGetConnectionParameter,
+ kiSCSIGetConnection,
+ kiSCSIGetNumConnections,
+ kiSCSIGetSessionIdForTargetIQN,
+ kiSCSIGetConnectionIdForPortalAddress,
+ kiSCSIGetSessionIds,
+ kiSCSIGetConnectionIds,
+ kiSCSICreateTargetIQNForSessionId,
+ kiSCSIGetPortalAddressForConnectionId,
+ kiSCSIGetPortalPortForConnectionId,
+ kiSCSIGetHostInterfaceForConnectionId,
+ kiSCSIInitiatorNumMethods
+};
+
+#endif /* defined(__ISCSI_HBA_TYPES_H__) */
diff --git a/Source/Kernel/iSCSIHBAUserClient.cpp b/Source/Kernel/iSCSIHBAUserClient.cpp
new file mode 100644
index 00000000..a010a356
--- /dev/null
+++ b/Source/Kernel/iSCSIHBAUserClient.cpp
@@ -0,0 +1,1521 @@
+/*
+ * Copyright (c) 2016, Nareg Sinenian
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.
+ */
+
+#include "iSCSIVirtualHBA.h"
+#include "iSCSIHBAUserClient.h"
+#include "iSCSITypesShared.h"
+#include "iSCSITypesKernel.h"
+#include
+
+/*! Required IOKit macro that defines the constructors, destructors, etc. */
+OSDefineMetaClassAndStructors(iSCSIHBAUserClient,IOUserClient);
+
+/*! The superclass is defined as a macro to follow IOKit conventions. */
+#define super IOUserClient
+
+/*! Array of methods that can be called by user-space. */
+const IOExternalMethodDispatch iSCSIHBAUserClient::methods[kiSCSIInitiatorNumMethods] = {
+ {
+ (IOExternalMethodAction) &iSCSIHBAUserClient::OpenInitiator,
+ 0, // Scalar input count
+ 0, // Structure input size
+ 0, // Scalar output count
+ 0 // Structure output size
+ },
+ {
+ (IOExternalMethodAction) &iSCSIHBAUserClient::CloseInitiator,
+ 0,
+ 0,
+ 0,
+ 0
+ },
+ {
+ (IOExternalMethodAction) &iSCSIHBAUserClient::CreateSession,
+ 1, // Number of parameters in struct
+ kIOUCVariableStructureSize, // Packed parameters for session
+ 3, // Returned identifiers, error code
+ 0
+ },
+ {
+ (IOExternalMethodAction) &iSCSIHBAUserClient::ReleaseSession,
+ 1, // Session ID
+ 0,
+ 0,
+ 0
+ },
+ {
+ (IOExternalMethodAction) &iSCSIHBAUserClient::SetSessionParameter,
+ 3, // Session ID, param ID, param value
+ 0,
+ 0,
+ 0
+ },
+ {
+ (IOExternalMethodAction) &iSCSIHBAUserClient::GetSessionParameter,
+ 2, // Session ID, param ID
+ 0,
+ 1, // param to get
+ 0
+ },
+ {
+ (IOExternalMethodAction) &iSCSIHBAUserClient::CreateConnection,
+ 2, // Session ID, number of params
+ kIOUCVariableStructureSize, // Packed parameters for connection
+ 2, // Returned connection identifier, error code
+ 0
+ },
+ {
+ (IOExternalMethodAction) &iSCSIHBAUserClient::ReleaseConnection,
+ 2, // Session ID, connection ID
+ 0,
+ 0,
+ 0
+ },
+ {
+ (IOExternalMethodAction) &iSCSIHBAUserClient::ActivateConnection,
+ 2, // Session ID, connection ID
+ 0,
+ 0,
+ 0
+ },
+ {
+ (IOExternalMethodAction) &iSCSIHBAUserClient::ActivateAllConnections,
+ 1, // Session ID
+ 0,
+ 0, // Return value
+ 0
+ },
+ {
+ (IOExternalMethodAction) &iSCSIHBAUserClient::DeactivateConnection,
+ 2, // Session ID, connection ID
+ 0,
+ 0, // Return value
+ 0
+ },
+ {
+ (IOExternalMethodAction) &iSCSIHBAUserClient::DeactivateAllConnections,
+ 1, // Session ID
+ 0,
+ 0, // Return value
+ 0
+ },
+ {
+ (IOExternalMethodAction) &iSCSIHBAUserClient::SendBHS,
+ 0, // Session ID, connection ID
+ sizeof(struct __iSCSIPDUCommonBHS), // Buffer to send
+ 0, // Return value
+ 0
+ },
+ {
+ (IOExternalMethodAction) &iSCSIHBAUserClient::SendData,
+ 2, // Session ID, connection ID
+ kIOUCVariableStructureSize, // Data is a variable size block
+ 0,
+ 0
+ },
+ {
+ (IOExternalMethodAction) &iSCSIHBAUserClient::RecvBHS,
+ 2, // Session ID, connection ID
+ 0,
+ 0,
+ sizeof(struct __iSCSIPDUCommonBHS), // Receive buffer
+ },
+ {
+ (IOExternalMethodAction) &iSCSIHBAUserClient::RecvData,
+ 2, // Session ID, connection ID
+ 0,
+ 0,
+ kIOUCVariableStructureSize, // Receive buffer
+ },
+ {
+ (IOExternalMethodAction) &iSCSIHBAUserClient::SetConnectionParameter,
+ 4, // Session ID, connection ID, param ID, param value
+ 0,
+ 0,
+ 0
+ },
+ {
+ (IOExternalMethodAction) &iSCSIHBAUserClient::GetConnectionParameter,
+ 3, // Session ID, connection ID, param ID
+ 0,
+ 1, // param to get
+ 0
+ },
+ {
+ (IOExternalMethodAction) &iSCSIHBAUserClient::GetConnection,
+ 1, // Session ID
+ 0,
+ 1, // Returned connection identifier
+ 0
+ },
+ {
+ (IOExternalMethodAction) &iSCSIHBAUserClient::GetNumConnections,
+ 1, // Session ID
+ 0,
+ 1, // Returned number of connections
+ 0
+ },
+ {
+ (IOExternalMethodAction) &iSCSIHBAUserClient::GetSessionIdForTargetIQN,
+ 0,
+ kIOUCVariableStructureSize, // Target name
+ 1, // Returned session identifier
+ 0
+ },
+ {
+ (IOExternalMethodAction) &iSCSIHBAUserClient::GetConnectionIdForPortalAddress,
+ 1, // Session ID
+ kIOUCVariableStructureSize, // Connection address structure
+ 1, // Returned connection identifier
+ 0
+ },
+ {
+ (IOExternalMethodAction) &iSCSIHBAUserClient::GetSessionIds,
+ 0,
+ 0,
+ 1, // Returned session count
+ kIOUCVariableStructureSize // List of session identifiers
+ },
+ {
+ (IOExternalMethodAction) &iSCSIHBAUserClient::GetConnectionIds,
+ 1, // Session ID
+ 0,
+ 1, // Returned connection count
+ kIOUCVariableStructureSize // List of connection ids
+ },
+ {
+ (IOExternalMethodAction) &iSCSIHBAUserClient::GetTargetIQNForSessionId,
+ 1, // Session ID
+ 0,
+ 0,
+ kIOUCVariableStructureSize // Target name
+ },
+ {
+ (IOExternalMethodAction) &iSCSIHBAUserClient::GetPortalAddressForConnectionId,
+ 2, // Session ID, connection ID
+ 0,
+ 0,
+ kIOUCVariableStructureSize // Portal address (C string)
+ },
+ {
+ (IOExternalMethodAction) &iSCSIHBAUserClient::GetPortalPortForConnectionId,
+ 2, // Session ID, connection ID
+ 0,
+ 0, // Returned connection count
+ kIOUCVariableStructureSize // connection address structures
+ },
+ {
+ (IOExternalMethodAction) &iSCSIHBAUserClient::GetHostInterfaceForConnectionId,
+ 2, // Session ID, connection ID
+ 0,
+ 0, // Returned connection count
+ kIOUCVariableStructureSize // connection address structures
+ }
+};
+
+IOReturn iSCSIHBAUserClient::externalMethod(uint32_t selector,
+ IOExternalMethodArguments * args,
+ IOExternalMethodDispatch * dispatch,
+ OSObject * target,
+ void * ref)
+{
+ // Sanity check the selector
+ if(selector >= kiSCSIInitiatorNumMethods)
+ return kIOReturnUnsupported;
+
+
+ // Call the appropriate function for the current instance of the class
+ return super::externalMethod(selector,
+ args,
+ (IOExternalMethodDispatch *)&iSCSIHBAUserClient::methods[selector],
+ this,
+ ref);
+}
+
+
+// Called as a result of user-space call to IOServiceOpen()
+bool iSCSIHBAUserClient::initWithTask(task_t owningTask,
+ void * securityToken,
+ UInt32 type,
+ OSDictionary * properties)
+{
+ // Save owning task, securty token and type so that we can validate user
+ // as a root user (UID 0) for secure operations (e.g., adding an iSCSI
+ // target requires privileges).
+ this->owningTask = owningTask;
+ this->securityToken = securityToken;
+ this->type = type;
+ this->accessLock = IOLockAlloc();
+ this->notificationPort = MACH_PORT_NULL;
+
+ // Perform any initialization tasks here
+ return super::initWithTask(owningTask,securityToken,type,properties);
+}
+
+//Called after initWithTask as a result of call to IOServiceOpen()
+bool iSCSIHBAUserClient::start(IOService * provider)
+{
+ // Check to ensure that the provider is actually an iSCSI initiator
+ if((this->provider = OSDynamicCast(iSCSIVirtualHBA,provider)) == NULL)
+ return false;
+
+ return super::start(provider);
+}
+
+void iSCSIHBAUserClient::stop(IOService * provider)
+{
+ super::stop(provider);
+}
+
+// Called as a result of user-space call to IOServiceClose()
+IOReturn iSCSIHBAUserClient::clientClose()
+{
+ // Tell HBA to release any resources that aren't active (e.g.,
+ // connections we started to establish but didn't activate)
+
+ // Ensure that the connection has been closed (in case the user calls
+ // IOServiceClose() before calling our close() method
+ close();
+
+ if(accessLock) {
+ IOLockFree(accessLock);
+ accessLock = NULL;
+ }
+
+ // Terminate ourselves
+ terminate();
+
+ return kIOReturnSuccess;
+}
+
+// Called if the user-space client is terminated without calling
+// IOServiceClose() or close()
+IOReturn iSCSIHBAUserClient::clientDied()
+{
+ // Tell HBA to release any resources that aren't active (e.g.,
+ // connections we started to establish but didn't activate)
+
+ // Close the provider (decrease retain count)
+ close();
+
+ return super::clientDied();
+}
+
+/*! Invoked when a user-space application registers a notification port
+ * with this user client.
+ * @param port the port associated with the client connection.
+ * @param type the type.
+ * @param refCon a user reference value.
+ * @return an error code indicating the result of the operation. */
+IOReturn iSCSIHBAUserClient::registerNotificationPort(mach_port_t port,
+ UInt32 type,
+ io_user_reference_t refCon)
+{
+ notificationPort = port;
+ return kIOReturnSuccess;
+}
+
+/*! Send a notification message to the user-space application.
+ * @param message details regarding the notification message.
+ * @return an error code indicating the result of the operation. */
+IOReturn iSCSIHBAUserClient::sendNotification(iSCSIHBANotificationMessage * message)
+{
+ if(notificationPort == MACH_PORT_NULL)
+ return kIOReturnNotOpen;
+
+ if(isInactive() || provider == NULL)
+ return kIOReturnNotAttached;
+
+ message->header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND,0);
+ message->header.msgh_size = sizeof(iSCSIHBANotificationMessage);
+ message->header.msgh_remote_port = notificationPort;
+ message->header.msgh_local_port = MACH_PORT_NULL;
+ message->header.msgh_reserved = 0;
+ message->header.msgh_id = 0;
+
+ mach_msg_send_from_kernel_proper(&message->header,message->header.msgh_size);
+ return kIOReturnSuccess;
+}
+
+/*! Sends a notification message to the user indicating that an
+ * iSCSI asynchronous event has occured.
+ * @param sessionId the session identifier.
+ * @param connectionId the connection identifier.
+ * @param event the asynchronsou event.
+ * @return an error code indicating the result of the operation. */
+IOReturn iSCSIHBAUserClient::sendAsyncMessageNotification(SessionIdentifier sessionId,
+ ConnectionIdentifier connectionId,
+ enum iSCSIPDUAsyncMsgEvent event)
+{
+ iSCSIHBANotificationAsyncMessage message;
+ message.notificationType = kiSCSIHBANotificationAsyncMessage;
+ message.asyncEvent = event;
+ message.sessionId = sessionId;
+ message.connectionId = connectionId;
+
+ return sendNotification((iSCSIHBANotificationMessage*)&message);
+}
+
+/*! Notifies clients that a network connnectivity issue has
+ * caused the specified connection and session to be dropped.
+ * @param sessionId session identifier.
+ * @param connectionId conncetion identifier.
+ * @return an error code indicating the result of the operation. */
+IOReturn iSCSIHBAUserClient::sendTimeoutMessageNotification(SessionIdentifier sessionId,
+ ConnectionIdentifier connectionId)
+{
+ iSCSIHBANotificationMessage message;
+ message.notificationType = kiSCSIHBANotificationTimeout;
+ message.sessionId = sessionId;
+ message.connectionId = connectionId;
+
+ return sendNotification((iSCSIHBANotificationMessage*)&message);
+}
+
+/*! Sends a notification message to the user indicating that the kernel
+ * extension will be terminating.
+ * @return an error code indicating the result of the operation. */
+IOReturn iSCSIHBAUserClient::sendTerminateMessageNotification()
+{
+ iSCSIHBANotificationMessage message;
+ message.notificationType = kiSCSIHBANotificationTerminate;
+
+ return sendNotification(&message);
+}
+
+// Invoked from user space remotely by calling iSCSIInitiatorOpen()
+IOReturn iSCSIHBAUserClient::open()
+{
+ // Ensure that we are attached to a provider
+ if(isInactive() || provider == NULL)
+ return kIOReturnNotAttached;
+
+ // Open the provider (iSCSIInitiator) for this client
+ if(provider->open(this))
+ return kIOReturnSuccess;
+
+ // At this point we couldn't open the client for the provider for some
+ // other reason
+ return kIOReturnNotOpen;
+}
+
+// Invoked from user space remotely by calling iSCSIInitiatorClose()
+IOReturn iSCSIHBAUserClient::close()
+{
+ // If we're not active or have no provider we're not attached
+ if(isInactive() || provider == NULL)
+ return kIOReturnNotAttached;
+
+ // If the provider isn't open for us then return not open
+ else if(!provider->isOpen(this))
+ return kIOReturnNotOpen;
+
+ // At this point we're attached & open, close the connection
+ provider->close(this);
+
+ return kIOReturnSuccess;
+}
+
+/*! Dispatched function called from the device interface to this user
+ * client .*/
+IOReturn iSCSIHBAUserClient::OpenInitiator(iSCSIHBAUserClient * target,
+ void * reference,
+ IOExternalMethodArguments * args)
+{
+ return target->open();
+}
+
+/*! Dispatched function called from the device interface to this user
+ * client .*/
+IOReturn iSCSIHBAUserClient::CloseInitiator(iSCSIHBAUserClient * target,
+ void * reference,
+ IOExternalMethodArguments * args)
+{
+ return target->close();
+}
+
+/*! Dispatched function invoked from user-space to create new session. */
+IOReturn iSCSIHBAUserClient::CreateSession(iSCSIHBAUserClient * target,
+ void * reference,
+ IOExternalMethodArguments * args)
+{
+ // Create a new session and return session ID
+ SessionIdentifier sessionId;
+ ConnectionIdentifier connectionId;
+
+ // Unpack the struct to get targetIQN, portalAddress, etc.
+ UInt64 kNumParams = *args->scalarInput;
+
+ // We expect six input arguments to CreateSession...
+ if(kNumParams < 6)
+ return kIOReturnBadArgument;
+
+ void * params[kNumParams];
+ size_t paramSize[kNumParams];
+ size_t header = sizeof(UInt64*)*kNumParams;
+ UInt8 * inputPos = ((UInt8*)args->structureInput)+header;
+
+ for(int idx = 0; idx < kNumParams; idx++) {
+ paramSize[idx] = ((UInt64*)args->structureInput)[idx];
+ params[idx] = inputPos;
+ inputPos += paramSize[idx];
+ }
+
+ OSString * targetIQN = OSString::withCString((const char *)params[0]);
+ OSString * portalAddress = OSString::withCString((const char *)params[1]);
+ OSString * portalPort = OSString::withCString((const char *)params[2]);
+ OSString * hostInterface = OSString::withCString((const char *)params[3]);
+ const sockaddr_storage * remoteAddress = (struct sockaddr_storage*)params[4];
+ const sockaddr_storage * localAddress = (struct sockaddr_storage*)params[5];
+
+ IOLockLock(target->accessLock);
+
+ // Create a connection
+ errno_t error = target->provider->CreateSession(
+ targetIQN,portalAddress,portalPort,hostInterface,remoteAddress,
+ localAddress,&sessionId,&connectionId);
+
+ IOLockUnlock(target->accessLock);
+
+ args->scalarOutput[0] = sessionId;
+ args->scalarOutput[1] = connectionId;
+ args->scalarOutput[2] = error;
+ args->scalarOutputCount = 3;
+
+ targetIQN->release();
+ portalAddress->release();
+ portalPort->release();
+ hostInterface->release();
+
+ return kIOReturnSuccess;
+}
+
+/*! Dispatched function invoked from user-space to release session. */
+IOReturn iSCSIHBAUserClient::ReleaseSession(iSCSIHBAUserClient * target,
+ void * reference,
+ IOExternalMethodArguments * args)
+{
+ // Release the session with the specified ID
+ IOLockLock(target->accessLock);
+ target->provider->ReleaseSession(*args->scalarInput);
+ IOLockUnlock(target->accessLock);
+
+ return kIOReturnSuccess;
+}
+
+// TODO: Set session options only once, when session is still inactive...
+IOReturn iSCSIHBAUserClient::SetSessionParameter(iSCSIHBAUserClient * target,
+ void * reference,
+ IOExternalMethodArguments * args)
+{
+ iSCSIVirtualHBA * hba = OSDynamicCast(iSCSIVirtualHBA,target->provider);
+
+ if(args->scalarInputCount != 3)
+ return kIOReturnBadArgument;
+
+ SessionIdentifier sessionId = (SessionIdentifier)args->scalarInput[0];
+ enum iSCSIHBASessionParameters paramType = (enum iSCSIHBASessionParameters)args->scalarInput[1];
+ UInt64 paramVal = args->scalarInput[2];
+
+ // Range-check input
+ if(sessionId >= kiSCSIMaxSessions)
+ return kIOReturnBadArgument;
+
+ IOLockLock(target->accessLock);
+
+ // Do nothing if session doesn't exist
+ iSCSISession * session = hba->sessionList[sessionId];
+
+ IOReturn retVal = kIOReturnSuccess;
+
+ if(session)
+ {
+ switch(paramType)
+ {
+ case kiSCSIHBASODataPDUInOrder:
+ session->dataPDUInOrder = paramVal;
+ break;
+ case kiSCSIHBASODataSequenceInOrder:
+ session->dataSequenceInOrder = paramVal;
+ break;
+ case kiSCSIHBASODefaultTime2Retain:
+ session->defaultTime2Retain = paramVal;
+ break;
+ case kiSCSIHBASODefaultTime2Wait:
+ session->defaultTime2Wait = paramVal;
+ break;
+ case kiSCSIHBASOErrorRecoveryLevel:
+ session->errorRecoveryLevel = paramVal;
+ break;
+ case kiSCSIHBASOFirstBurstLength:
+ session->firstBurstLength = (UInt32)paramVal;
+ break;
+ case kiSCSIHBASOImmediateData:
+ session->immediateData = paramVal;
+ break;
+ case kiSCSIHBASOMaxConnections:
+ session->maxConnections = (ConnectionIdentifier)paramVal;
+ break;
+ case kiSCSIHBASOMaxOutstandingR2T:
+ session->maxOutStandingR2T = paramVal;
+ break;
+ case kiSCSIHBASOMaxBurstLength:
+ session->maxBurstLength = (UInt32)paramVal;
+ break;
+ case kiSCSIHBASOInitialR2T:
+ session->initialR2T = paramVal;
+ break;
+ case kiSCSIHBASOTargetPortalGroupTag:
+ session->targetPortalGroupTag = paramVal;
+ break;
+ case kiSCSIHBASOTargetSessionId:
+ session->targetSessionId = paramVal;
+ break;
+
+ default:
+ retVal = kIOReturnBadArgument;
+ };
+ }
+ else {
+ retVal = kIOReturnBadArgument;
+ }
+
+ IOLockUnlock(target->accessLock);
+ return retVal;
+}
+
+IOReturn iSCSIHBAUserClient::GetSessionParameter(iSCSIHBAUserClient * target,
+ void * reference,
+ IOExternalMethodArguments * args)
+{
+ iSCSIVirtualHBA * hba = OSDynamicCast(iSCSIVirtualHBA,target->provider);
+
+ if(args->scalarInputCount != 2)
+ return kIOReturnBadArgument;
+
+ SessionIdentifier sessionId = (SessionIdentifier)args->scalarInput[0];
+ enum iSCSIHBASessionParameters paramType = (enum iSCSIHBASessionParameters)args->scalarInput[1];
+
+ // Range-check input
+ if(sessionId >= kiSCSIMaxSessions)
+ return kIOReturnBadArgument;
+
+ IOLockLock(target->accessLock);
+
+ // Do nothing if session doesn't exist
+ iSCSISession * session = hba->sessionList[sessionId];
+
+ IOReturn retVal = kIOReturnSuccess;
+ UInt64 * paramVal = args->scalarOutput;
+
+ if(session)
+ {
+ switch(paramType)
+ {
+ case kiSCSIHBASODataPDUInOrder:
+ *paramVal = session->dataPDUInOrder;
+ break;
+ case kiSCSIHBASODataSequenceInOrder:
+ *paramVal = session->dataSequenceInOrder;
+ break;
+ case kiSCSIHBASODefaultTime2Retain:
+ *paramVal = session->defaultTime2Retain;
+ break;
+ case kiSCSIHBASODefaultTime2Wait:
+ *paramVal = session->defaultTime2Wait;
+ break;
+ case kiSCSIHBASOErrorRecoveryLevel:
+ *paramVal = session->errorRecoveryLevel;
+ break;
+ case kiSCSIHBASOFirstBurstLength:
+ *paramVal = session->firstBurstLength;
+ break;
+ case kiSCSIHBASOImmediateData:
+ *paramVal = session->immediateData;
+ break;
+ case kiSCSIHBASOMaxConnections:
+ *paramVal = session->maxConnections;
+ break;
+ case kiSCSIHBASOMaxOutstandingR2T:
+ *paramVal = session->maxOutStandingR2T;
+ break;
+ case kiSCSIHBASOMaxBurstLength:
+ *paramVal = session->maxBurstLength;
+ break;
+ case kiSCSIHBASOInitialR2T:
+ *paramVal = session->initialR2T;
+ break;
+ case kiSCSIHBASOTargetPortalGroupTag:
+ *paramVal = session->targetPortalGroupTag;
+ break;
+ case kiSCSIHBASOTargetSessionId:
+ *paramVal = session->targetSessionId;
+ break;
+ default:
+ retVal = kIOReturnBadArgument;
+ };
+ }
+ else {
+ retVal = kIOReturnNotFound;
+ }
+
+ IOLockUnlock(target->accessLock);
+ return retVal;
+}
+
+/*! Dispatched function invoked from user-space to create new connection. */
+IOReturn iSCSIHBAUserClient::CreateConnection(iSCSIHBAUserClient * target,
+ void * reference,
+ IOExternalMethodArguments * args)
+{
+ SessionIdentifier sessionId = (SessionIdentifier)args->scalarInput[0];
+ ConnectionIdentifier connectionId;
+
+ // Unpack the struct to get targetIQN, portalAddress, etc.
+ UInt64 kNumParams = args->scalarInput[1];
+
+ // We expect six input arguments to CreateSession...
+ if(kNumParams < 5)
+ return kIOReturnBadArgument;
+
+ void * params[kNumParams];
+ size_t paramSize[kNumParams];
+ size_t header = sizeof(UInt64*)*kNumParams;
+ UInt8 * inputPos = ((UInt8*)args->structureInput)+header;
+
+ for(int idx = 0; idx < kNumParams; idx++) {
+ paramSize[idx] = ((UInt64*)args->structureInput)[idx];
+ params[idx] = inputPos;
+ inputPos += paramSize[idx];
+ }
+
+ OSString * portalAddress = OSString::withCString((const char *)params[0]);
+ OSString * portalPort = OSString::withCString((const char *)params[1]);
+ OSString * hostInterface = OSString::withCString((const char *)params[2]);
+ const sockaddr_storage * remoteAddress = (struct sockaddr_storage*)params[3];
+ const sockaddr_storage * localAddress = (struct sockaddr_storage*)params[4];
+
+ IOLockLock(target->accessLock);
+
+ // Create a connection
+ errno_t error = target->provider->CreateConnection(
+ sessionId,portalAddress,portalPort,hostInterface,remoteAddress,
+ localAddress,&connectionId);
+
+ IOLockUnlock(target->accessLock);
+
+ args->scalarOutput[0] = connectionId;
+ args->scalarOutput[1] = error;
+ args->scalarOutputCount = 2;
+
+ return kIOReturnSuccess;
+}
+
+/*! Dispatched function invoked from user-space to release connection. */
+IOReturn iSCSIHBAUserClient::ReleaseConnection(iSCSIHBAUserClient * target,
+ void * reference,
+ IOExternalMethodArguments * args)
+{
+ iSCSIVirtualHBA * hba = OSDynamicCast(iSCSIVirtualHBA,target->provider);
+
+ SessionIdentifier sessionId = (SessionIdentifier)args->scalarInput[0];
+ ConnectionIdentifier connectionId = (ConnectionIdentifier)args->scalarInput[1];
+
+ // Range-check input
+ if(sessionId >= kiSCSIMaxSessions || connectionId >= kiSCSIMaxConnectionsPerSession)
+ return kIOReturnBadArgument;
+
+ IOLockLock(target->accessLock);
+
+ iSCSISession * session = hba->sessionList[sessionId];
+
+ // If this is the only connection, releasing the connection should
+ // release the session as well...
+ ConnectionIdentifier connectionCount = 0;
+
+ if(session) {
+ // Iterate over list of connections to see how many are valid
+ for(ConnectionIdentifier connectionId = 0; connectionId < kiSCSIMaxConnectionsPerSession; connectionId++)
+ if(session->connections[connectionId])
+ connectionCount++;
+ }
+
+ if(connectionCount == 1)
+ target->provider->ReleaseSession(sessionId);
+ else
+ target->provider->ReleaseConnection(sessionId,connectionId);
+
+ IOLockUnlock(target->accessLock);
+ return kIOReturnSuccess;
+}
+
+IOReturn iSCSIHBAUserClient::ActivateConnection(iSCSIHBAUserClient * target,
+ void * reference,
+ IOExternalMethodArguments * args)
+{
+ IOLockLock(target->accessLock);
+
+ *args->scalarOutput =
+ target->provider->ActivateConnection((SessionIdentifier)args->scalarInput[0],
+ (ConnectionIdentifier)args->scalarInput[1]);
+ IOLockUnlock(target->accessLock);
+ return kIOReturnSuccess;
+}
+
+IOReturn iSCSIHBAUserClient::ActivateAllConnections(iSCSIHBAUserClient * target,
+ void * reference,
+ IOExternalMethodArguments * args)
+{
+ IOLockLock(target->accessLock);
+
+ *args->scalarOutput =
+ target->provider->ActivateAllConnections((SessionIdentifier)args->scalarInput[0]);
+
+ IOLockUnlock(target->accessLock);
+ return kIOReturnSuccess;
+}
+
+IOReturn iSCSIHBAUserClient::DeactivateConnection(iSCSIHBAUserClient * target,
+ void * reference,
+ IOExternalMethodArguments * args)
+{
+ IOLockLock(target->accessLock);
+
+ *args->scalarOutput =
+ target->provider->DeactivateConnection((SessionIdentifier)args->scalarInput[0],
+ (ConnectionIdentifier)args->scalarInput[1]);
+
+ IOLockUnlock(target->accessLock);
+ return kIOReturnSuccess;
+}
+
+IOReturn iSCSIHBAUserClient::DeactivateAllConnections(iSCSIHBAUserClient * target,
+ void * reference,
+ IOExternalMethodArguments * args)
+{
+ IOLockLock(target->accessLock);
+
+ *args->scalarOutput =
+ target->provider->DeactivateAllConnections((SessionIdentifier)args->scalarInput[0]);
+
+ IOLockUnlock(target->accessLock);
+ return kIOReturnSuccess;
+}
+
+/*! Dispatched function invoked from user-space to send data
+ * over an existing, active connection. */
+IOReturn iSCSIHBAUserClient::SendBHS(iSCSIHBAUserClient * target,
+ void * reference,
+ IOExternalMethodArguments * args)
+{
+ // Validate input
+ if(args->structureInputSize != kiSCSIPDUBasicHeaderSegmentSize)
+ return kIOReturnNoSpace;
+
+ IOLockLock(target->accessLock);
+ memcpy(&target->bhsBuffer,args->structureInput,kiSCSIPDUBasicHeaderSegmentSize);
+ IOLockUnlock(target->accessLock);
+
+ return kIOReturnSuccess;
+}
+
+/*! Dispatched function invoked from user-space to send data
+ * over an existing, active connection. */
+IOReturn iSCSIHBAUserClient::SendData(iSCSIHBAUserClient * target,
+ void * reference,
+ IOExternalMethodArguments * args)
+{
+ iSCSIVirtualHBA * hba = OSDynamicCast(iSCSIVirtualHBA,target->provider);
+
+ SessionIdentifier sessionId = (SessionIdentifier)args->scalarInput[0];
+ ConnectionIdentifier connectionId = (ConnectionIdentifier)args->scalarInput[1];
+
+ // Range-check input
+ if(sessionId >= kiSCSIMaxSessions || connectionId >= kiSCSIMaxConnectionsPerSession)
+ return kIOReturnBadArgument;
+
+ IOLockLock(target->accessLock);
+
+ // Do nothing if session doesn't exist
+ iSCSISession * session = hba->sessionList[sessionId];
+ iSCSIConnection * connection = NULL;
+
+ if(session)
+ connection = session->connections[connectionId];
+
+ const void * data = args->structureInput;
+ size_t length = args->structureInputSize;
+
+ // Send data and return the result
+ IOReturn retVal = kIOReturnNotFound;
+
+ if(connection) {
+ if(hba->SendPDU(session,connection,&(target->bhsBuffer),nullptr,data,length))
+ retVal = kIOReturnError;
+ else
+ retVal = kIOReturnSuccess;
+ }
+
+ IOLockUnlock(target->accessLock);
+
+ return retVal;
+}
+
+/*! Dispatched function invoked from user-space to receive data
+ * over an existing, active connection, and to retrieve the size of
+ * a user-space buffer that is required to hold the data. */
+IOReturn iSCSIHBAUserClient::RecvBHS(iSCSIHBAUserClient * target,
+ void * reference,
+ IOExternalMethodArguments * args)
+{
+ // Verify user-supplied buffer is large enough to hold BHS
+ if(args->structureOutputSize != kiSCSIPDUBasicHeaderSegmentSize)
+ return kIOReturnNoSpace;
+
+ iSCSIVirtualHBA * hba = OSDynamicCast(iSCSIVirtualHBA,target->provider);
+
+ SessionIdentifier sessionId = (SessionIdentifier)args->scalarInput[0];
+ ConnectionIdentifier connectionId = (ConnectionIdentifier)args->scalarInput[1];
+
+ // Range-check input
+ if(sessionId >= kiSCSIMaxSessions || connectionId >= kiSCSIMaxConnectionsPerSession)
+ return kIOReturnBadArgument;
+
+ IOLockLock(target->accessLock);
+
+ // Do nothing if session doesn't exist
+ iSCSISession * session = hba->sessionList[sessionId];
+ iSCSIConnection * connection = NULL;
+
+ if(session)
+ connection = session->connections[connectionId];
+
+ // Receive data and return the result
+ IOReturn retVal = kIOReturnNotFound;
+
+ iSCSIPDUTargetBHS * bhs = (iSCSIPDUTargetBHS*)args->structureOutput;
+
+ if(connection) {
+ if(hba->RecvPDUHeader(session,connection,bhs,MSG_WAITALL))
+ retVal = kIOReturnIOError;
+ else
+ retVal = kIOReturnSuccess;
+ }
+
+ IOLockUnlock(target->accessLock);
+
+ return retVal;
+}
+
+/*! Dispatched function invoked from user-space to receive data
+ * over an existing, active connection, and to retrieve the size of
+ * a user-space buffer that is required to hold the data. */
+IOReturn iSCSIHBAUserClient::RecvData(iSCSIHBAUserClient * target,
+ void * reference,
+ IOExternalMethodArguments * args)
+{
+ iSCSIVirtualHBA * hba = OSDynamicCast(iSCSIVirtualHBA,target->provider);
+
+ SessionIdentifier sessionId = (SessionIdentifier)args->scalarInput[0];
+ ConnectionIdentifier connectionId = (ConnectionIdentifier)args->scalarInput[1];
+
+ // Range-check input
+ if(sessionId >= kiSCSIMaxSessions || connectionId >= kiSCSIMaxConnectionsPerSession)
+ return kIOReturnBadArgument;
+
+ IOLockLock(target->accessLock);
+
+ // Do nothing if session doesn't exist
+ iSCSISession * session = hba->sessionList[sessionId];
+ iSCSIConnection * connection = NULL;
+
+ if(session)
+ connection = session->connections[connectionId];
+
+ // Receive data and return the result
+ IOReturn retVal = kIOReturnNotFound;
+
+ void * data = (void *)args->structureOutput;
+ size_t length = args->structureOutputSize;
+
+ if(hba->RecvPDUData(session,connection,data,length,MSG_WAITALL))
+ retVal = kIOReturnIOError;
+ else
+ retVal = kIOReturnSuccess;
+
+ IOLockUnlock(target->accessLock);
+
+ return retVal;
+}
+
+// TODO: Only allow user to set options when connection is inactive
+// TODO: optimize socket parameters based on connection options
+IOReturn iSCSIHBAUserClient::SetConnectionParameter(iSCSIHBAUserClient * target,
+ void * reference,
+ IOExternalMethodArguments * args)
+{
+ iSCSIVirtualHBA * hba = OSDynamicCast(iSCSIVirtualHBA,target->provider);
+
+ if(args->scalarInputCount != 4)
+ return kIOReturnBadArgument;
+
+ SessionIdentifier sessionId = (SessionIdentifier)args->scalarInput[0];
+ ConnectionIdentifier connectionId = (ConnectionIdentifier)args->scalarInput[1];
+ enum iSCSIHBAConnectionParameters paramType = (enum iSCSIHBAConnectionParameters)args->scalarInput[2];
+ UInt64 paramVal = args->scalarInput[3];
+
+ // Range-check input
+ if(sessionId >= kiSCSIMaxSessions || connectionId >= kiSCSIMaxConnectionsPerSession)
+ return kIOReturnBadArgument;
+
+ IOLockLock(target->accessLock);
+
+ // Do nothing if session doesn't exist
+ iSCSISession * session = hba->sessionList[sessionId];
+ iSCSIConnection * connection = NULL;
+
+ if(session)
+ connection = session->connections[connectionId];
+
+ // Receive data and return the result
+ IOReturn retVal = kIOReturnNotFound;
+
+ if(connection)
+ {
+ retVal = kIOReturnSuccess;
+
+ switch(paramType)
+ {
+ case kiSCSIHBACOIFMarkInt:
+ connection->IFMarkInt = paramVal;
+ break;
+ case kiSCSIHBACOOFMarkInt:
+ connection->OFMarkInt = paramVal;
+ break;
+ case kiSCSIHBACOUseIFMarker:
+ connection->useIFMarker = paramVal;
+ break;
+ case kiSCSIHBACOUseOFMarker:
+ connection->useOFMarker = paramVal;
+ break;
+ case kiSCSIHBACOUseDataDigest:
+ connection->useDataDigest = paramVal;
+ break;
+ case kiSCSIHBACOUseHeaderDigest:
+ connection->useHeaderDigest = paramVal;
+ break;
+ case kiSCSIHBACOMaxRecvDataSegmentLength:
+ connection->maxRecvDataSegmentLength = (UInt32)paramVal;
+ break;
+ case kiSCSIHBACOMaxSendDataSegmentLength:
+ connection->maxSendDataSegmentLength = (UInt32)paramVal;
+ break;
+ case kiSCSIHBACOInitialExpStatSN:
+ connection->expStatSN = (UInt32)paramVal;
+ break;
+
+ default:
+ retVal = kIOReturnBadArgument;
+ };
+ }
+
+ IOLockUnlock(target->accessLock);
+
+ return retVal;
+}
+
+IOReturn iSCSIHBAUserClient::GetConnectionParameter(iSCSIHBAUserClient * target,
+ void * reference,
+ IOExternalMethodArguments * args)
+{
+ iSCSIVirtualHBA * hba = OSDynamicCast(iSCSIVirtualHBA,target->provider);
+
+ if(args->scalarInputCount != 3)
+ return kIOReturnBadArgument;
+
+ SessionIdentifier sessionId = (SessionIdentifier)args->scalarInput[0];
+ ConnectionIdentifier connectionId = (ConnectionIdentifier)args->scalarInput[1];
+ enum iSCSIHBAConnectionParameters paramType = (enum iSCSIHBAConnectionParameters)args->scalarInput[2];
+ UInt64 * paramVal = args->scalarOutput;
+
+ // Range-check input
+ if(sessionId >= kiSCSIMaxSessions || connectionId >= kiSCSIMaxConnectionsPerSession)
+ return kIOReturnBadArgument;
+
+ IOLockLock(target->accessLock);
+
+ // Do nothing if session doesn't exist
+ iSCSISession * session = hba->sessionList[sessionId];
+ iSCSIConnection * connection = NULL;
+
+ if(session)
+ connection = session->connections[connectionId];
+
+ // Receive data and return the result
+ IOReturn retVal = kIOReturnNotFound;
+
+ if(connection) {
+ retVal = kIOReturnSuccess;
+
+ switch(paramType)
+ {
+ case kiSCSIHBACOIFMarkInt:
+ *paramVal = connection->IFMarkInt;
+ break;
+ case kiSCSIHBACOOFMarkInt:
+ *paramVal = connection->OFMarkInt;
+ break;
+ case kiSCSIHBACOUseIFMarker:
+ *paramVal = connection->useIFMarker;
+ break;
+ case kiSCSIHBACOUseOFMarker:
+ *paramVal = connection->useOFMarker;
+ break;
+ case kiSCSIHBACOUseDataDigest:
+ *paramVal = connection->useDataDigest;
+ break;
+ case kiSCSIHBACOUseHeaderDigest:
+ *paramVal = connection->useHeaderDigest;
+ break;
+ case kiSCSIHBACOMaxRecvDataSegmentLength:
+ *paramVal = connection->maxRecvDataSegmentLength;
+ break;
+ case kiSCSIHBACOMaxSendDataSegmentLength:
+ *paramVal = connection->maxSendDataSegmentLength;
+ break;
+ case kiSCSIHBACOInitialExpStatSN:
+ *paramVal = connection->expStatSN;
+ break;
+
+ default:
+ return kIOReturnBadArgument;
+ };
+ }
+
+ IOLockUnlock(target->accessLock);
+
+ return retVal;
+}
+
+IOReturn iSCSIHBAUserClient::GetConnection(iSCSIHBAUserClient * target,
+ void * reference,
+ IOExternalMethodArguments * args)
+{
+ iSCSIVirtualHBA * hba = OSDynamicCast(iSCSIVirtualHBA,target->provider);
+
+ SessionIdentifier sessionId = (SessionIdentifier)args->scalarInput[0];
+
+ // Range-check input
+ if(sessionId >= kiSCSIMaxSessions)
+ return kIOReturnBadArgument;
+
+ IOLockLock(target->accessLock);
+
+ iSCSISession * session = hba->sessionList[sessionId];
+ IOReturn retVal = kIOReturnNotFound;
+
+ if(session) {
+
+ retVal = kIOReturnSuccess;
+
+ args->scalarOutputCount = 1;
+ ConnectionIdentifier * connectionId = (ConnectionIdentifier *)args->scalarOutput;
+
+ *connectionId = kiSCSIInvalidConnectionId;
+
+ for(ConnectionIdentifier connectionIdx = 0; connectionIdx < kiSCSIMaxConnectionsPerSession; connectionIdx++)
+ {
+ if(session->connections[connectionIdx])
+ {
+ *connectionId = connectionIdx;
+ break;
+ }
+ }
+ }
+
+ IOLockUnlock(target->accessLock);
+
+ return retVal;
+}
+
+IOReturn iSCSIHBAUserClient::GetNumConnections(iSCSIHBAUserClient * target,
+ void * reference,
+ IOExternalMethodArguments * args)
+{
+ iSCSIVirtualHBA * hba = OSDynamicCast(iSCSIVirtualHBA,target->provider);
+
+ SessionIdentifier sessionId = (SessionIdentifier)args->scalarInput[0];
+
+ // Range-check input
+ if(sessionId >= kiSCSIMaxSessions)
+ return kIOReturnBadArgument;
+
+ IOLockLock(target->accessLock);
+
+ iSCSISession * session = hba->sessionList[sessionId];
+ IOReturn retVal = kIOReturnNotFound;
+ ConnectionIdentifier connectionCount = 0;
+
+ if(session) {
+ // Iterate over list of connections to see how many are valid
+ for(ConnectionIdentifier connectionId = 0; connectionId < kiSCSIMaxConnectionsPerSession; connectionId++)
+ if(session->connections[connectionId])
+ connectionCount++;
+ }
+
+ *args->scalarOutput = connectionCount;
+ args->scalarOutputCount = 1;
+
+ IOLockUnlock(target->accessLock);
+
+ return retVal;
+}
+
+IOReturn iSCSIHBAUserClient::GetSessionIdForTargetIQN(iSCSIHBAUserClient * target,
+ void * reference,
+ IOExternalMethodArguments * args)
+{
+ iSCSIVirtualHBA * hba = OSDynamicCast(iSCSIVirtualHBA,target->provider);
+
+ const char * targetIQN = (const char *)args->structureInput;
+
+ IOLockLock(target->accessLock);
+ OSNumber * identifier = (OSNumber*)(hba->targetList->getObject(targetIQN));
+
+ IOReturn retVal = kIOReturnNotFound;
+
+ if(identifier) {
+ retVal = kIOReturnSuccess;
+ *args->scalarOutput = identifier->unsigned16BitValue();;
+ args->scalarOutputCount = 1;
+ }
+
+ IOLockUnlock(target->accessLock);
+
+ return retVal;
+}
+
+IOReturn iSCSIHBAUserClient::GetConnectionIdForPortalAddress(iSCSIHBAUserClient * target,
+ void * reference,
+ IOExternalMethodArguments * args)
+{
+ iSCSIVirtualHBA * hba = OSDynamicCast(iSCSIVirtualHBA,target->provider);
+
+ SessionIdentifier sessionId = (SessionIdentifier)args->scalarInput[0];
+
+ // Range-check input
+ if(sessionId == kiSCSIInvalidSessionId)
+ return kIOReturnBadArgument;
+
+ IOLockLock(target->accessLock);
+
+ iSCSISession * session = hba->sessionList[sessionId];
+ IOReturn retVal = kIOReturnNotFound;
+
+ if(session) {
+
+ retVal = kIOReturnBadArgument;
+
+ OSString * portalAddress = OSString::withCString((const char *)args->structureInput);
+
+ if(portalAddress)
+ {
+ retVal = kIOReturnNotFound;
+
+ iSCSIConnection * connection = NULL;
+
+ *args->scalarOutput = kiSCSIInvalidConnectionId;
+ args->scalarOutputCount = 1;
+
+ // Iterate over connections to find a matching address structure
+ for(ConnectionIdentifier connectionId = 0; connectionId < kiSCSIMaxConnectionsPerSession; connectionId++)
+ {
+ if(!(connection = session->connections[connectionId]))
+ continue;
+
+ if(!connection->portalAddress->isEqualTo(portalAddress))
+ continue;
+
+ *args->scalarOutput = connectionId;
+ args->scalarOutputCount = 1;
+
+ retVal = kIOReturnSuccess;
+ break;
+ }
+ }
+ }
+
+ IOLockUnlock(target->accessLock);
+
+ return retVal;
+}
+
+IOReturn iSCSIHBAUserClient::GetSessionIds(iSCSIHBAUserClient * target,
+ void * reference,
+ IOExternalMethodArguments * args)
+{
+ if(args->structureOutputSize < sizeof(SessionIdentifier)*kiSCSIMaxSessions)
+ return kIOReturnBadArgument;
+
+ iSCSIVirtualHBA * hba = OSDynamicCast(iSCSIVirtualHBA,target->provider);
+
+ SessionIdentifier sessionCount = 0;
+ SessionIdentifier * sessionIds = (SessionIdentifier *)args->structureOutput;
+
+ IOLockLock(target->accessLock);
+
+ for(SessionIdentifier sessionIdx = 0; sessionIdx < kiSCSIMaxSessions; sessionIdx++)
+ {
+ if(hba->sessionList[sessionIdx])
+ {
+ sessionIds[sessionCount] = sessionIdx;
+ sessionCount++;
+ }
+ }
+
+ args->scalarOutputCount = 1;
+ *args->scalarOutput = sessionCount;
+
+ IOLockUnlock(target->accessLock);
+
+ return kIOReturnSuccess;
+}
+
+IOReturn iSCSIHBAUserClient::GetConnectionIds(iSCSIHBAUserClient * target,
+ void * reference,
+ IOExternalMethodArguments * args)
+{
+ if(args->structureOutputSize < sizeof(ConnectionIdentifier)*kiSCSIMaxConnectionsPerSession)
+ return kIOReturnBadArgument;
+
+ iSCSIVirtualHBA * hba = OSDynamicCast(iSCSIVirtualHBA,target->provider);
+
+ SessionIdentifier sessionId = (SessionIdentifier)args->scalarInput[0];
+
+ // Range-check input
+ if(sessionId >= kiSCSIMaxSessions)
+ return kIOReturnBadArgument;
+
+ IOLockLock(target->accessLock);
+
+ iSCSISession * session = hba->sessionList[sessionId];
+ IOReturn retVal = kIOReturnNotFound;
+
+ if(session)
+ {
+ retVal = kIOReturnSuccess;
+
+ ConnectionIdentifier connectionCount = 0;
+ ConnectionIdentifier * connectionIds = (ConnectionIdentifier *)args->structureOutput;
+
+ // Find an empty connection slot to use for a new connection
+ for(ConnectionIdentifier index = 0; index < kiSCSIMaxConnectionsPerSession; index++)
+ {
+ if(session->connections[index])
+ {
+ connectionIds[connectionCount] = index;
+ connectionCount++;
+ }
+ }
+
+ args->scalarOutputCount = 1;
+ *args->scalarOutput = connectionCount;
+ }
+
+ IOLockUnlock(target->accessLock);
+
+ return retVal;
+}
+
+IOReturn iSCSIHBAUserClient::GetTargetIQNForSessionId(iSCSIHBAUserClient * target,
+ void * reference,
+ IOExternalMethodArguments * args)
+{
+ iSCSIVirtualHBA * hba = OSDynamicCast(iSCSIVirtualHBA,target->provider);
+
+ SessionIdentifier sessionId = (SessionIdentifier)args->scalarInput[0];
+
+ // Range-check input
+ if(sessionId >= kiSCSIMaxSessions)
+ return kIOReturnBadArgument;
+
+ IOLockLock(target->accessLock);
+
+ iSCSISession * session = hba->sessionList[sessionId];
+ IOReturn retVal = kIOReturnNotFound;
+
+ // Iterate over list of target name and find a matching session identifier
+ OSCollectionIterator * iterator = OSCollectionIterator::withCollection(hba->targetList);
+
+ if(session && iterator)
+ {
+ OSObject * object;
+
+ while((object = iterator->getNextObject()))
+ {
+ OSString * targetIQN = OSDynamicCast(OSString,object);
+ OSNumber * sessionIdNumber = OSDynamicCast(OSNumber,hba->targetList->getObject(targetIQN));
+
+ if(sessionIdNumber->unsigned16BitValue() == sessionId)
+ {
+ // Minimum length (either buffer size or size of
+ // target name, whichever is shorter)
+ size_t size = min(targetIQN->getLength(),args->structureOutputSize);
+ memcpy(args->structureOutput,targetIQN->getCStringNoCopy(),size);
+
+ retVal = kIOReturnSuccess;
+ break;
+ }
+ }
+ }
+
+ IOLockUnlock(target->accessLock);
+
+ OSSafeRelease(iterator);
+ return retVal;
+}
+
+IOReturn iSCSIHBAUserClient::GetPortalAddressForConnectionId(iSCSIHBAUserClient * target,
+ void * reference,
+ IOExternalMethodArguments * args)
+{
+ iSCSIVirtualHBA * hba = OSDynamicCast(iSCSIVirtualHBA,target->provider);
+
+ SessionIdentifier sessionId = (SessionIdentifier)args->scalarInput[0];
+ ConnectionIdentifier connectionId = (ConnectionIdentifier)args->scalarInput[1];
+
+ // Range-check input
+ if(sessionId >= kiSCSIMaxSessions || connectionId >= kiSCSIMaxConnectionsPerSession)
+ return kIOReturnBadArgument;
+
+ IOLockLock(target->accessLock);
+
+ // Do nothing if session doesn't exist
+ iSCSISession * session = hba->sessionList[sessionId];
+ iSCSIConnection * connection = NULL;
+
+ if(session)
+ connection = session->connections[connectionId];
+
+ // Receive data and return the result
+ IOReturn retVal = kIOReturnNotFound;
+
+ if(connection) {
+ retVal = kIOReturnSuccess;
+
+ const char * portalAddress = connection->portalAddress->getCStringNoCopy();
+ size_t portalAddressLength = connection->portalAddress->getLength();
+
+ memset(args->structureOutput,0,args->structureOutputSize);
+ memcpy(args->structureOutput,portalAddress,min(args->structureOutputSize,portalAddressLength));
+ }
+
+ IOLockUnlock(target->accessLock);
+ return retVal;
+}
+
+IOReturn iSCSIHBAUserClient::GetPortalPortForConnectionId(iSCSIHBAUserClient * target,
+ void * reference,
+ IOExternalMethodArguments * args)
+{
+ iSCSIVirtualHBA * hba = OSDynamicCast(iSCSIVirtualHBA,target->provider);
+
+ SessionIdentifier sessionId = (SessionIdentifier)args->scalarInput[0];
+ ConnectionIdentifier connectionId = (ConnectionIdentifier)args->scalarInput[1];
+
+ // Range-check input
+ if(sessionId >= kiSCSIMaxSessions || connectionId >= kiSCSIMaxConnectionsPerSession)
+ return kIOReturnBadArgument;
+
+ IOLockLock(target->accessLock);
+
+ // Do nothing if session doesn't exist
+ iSCSISession * session = hba->sessionList[sessionId];
+ iSCSIConnection * connection = NULL;
+
+ if(session)
+ connection = session->connections[connectionId];
+
+ // Receive data and return the result
+ IOReturn retVal = kIOReturnNotFound;
+
+ if(connection) {
+ retVal = kIOReturnSuccess;
+
+ const char * portalPort = connection->portalPort->getCStringNoCopy();
+ size_t portalPortLength = connection->portalPort->getLength();
+
+ memset(args->structureOutput,0,args->structureOutputSize);
+ memcpy(args->structureOutput,portalPort,min(args->structureOutputSize,portalPortLength));
+ }
+
+ IOLockUnlock(target->accessLock);
+ return retVal;
+}
+
+IOReturn iSCSIHBAUserClient::GetHostInterfaceForConnectionId(iSCSIHBAUserClient * target,
+ void * reference,
+ IOExternalMethodArguments * args)
+{
+ iSCSIVirtualHBA * hba = OSDynamicCast(iSCSIVirtualHBA,target->provider);
+
+ SessionIdentifier sessionId = (SessionIdentifier)args->scalarInput[0];
+ ConnectionIdentifier connectionId = (ConnectionIdentifier)args->scalarInput[1];
+
+ // Range-check input
+ if(sessionId >= kiSCSIMaxSessions || connectionId >= kiSCSIMaxConnectionsPerSession)
+ return kIOReturnBadArgument;
+
+ IOLockLock(target->accessLock);
+
+ // Do nothing if session doesn't exist
+ iSCSISession * session = hba->sessionList[sessionId];
+ iSCSIConnection * connection = NULL;
+
+ if(session)
+ connection = session->connections[connectionId];
+
+ // Receive data and return the result
+ IOReturn retVal = kIOReturnNotFound;
+
+ if(connection) {
+ retVal = kIOReturnSuccess;
+
+ const char * hostInterface = connection->hostInteface->getCStringNoCopy();
+ size_t hostInterfaceLength = connection->hostInteface->getLength();
+
+ memcpy(args->structureOutput,hostInterface,min(args->structureOutputSize,hostInterfaceLength+1));
+ }
+
+ IOLockUnlock(target->accessLock);
+
+ return retVal;
+}
+
+
+
diff --git a/Source/Kernel/iSCSIHBAUserClient.h b/Source/Kernel/iSCSIHBAUserClient.h
new file mode 100644
index 00000000..55dd5eaf
--- /dev/null
+++ b/Source/Kernel/iSCSIHBAUserClient.h
@@ -0,0 +1,288 @@
+/*
+ * Copyright (c) 2016, Nareg Sinenian
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.
+ */
+
+#ifndef __ISCSI_USER_CLIENT_H__
+#define __ISCSI_USER_CLIENT_H__
+
+#include
+
+#include "iSCSIKernelClasses.h"
+#include "iSCSIHBATypes.h"
+#include "iSCSIPDUShared.h"
+#include "iSCSIVirtualHBA.h"
+#include "iSCSITypesShared.h"
+
+class iSCSIHBAUserClient : public IOUserClient
+{
+ OSDeclareDefaultStructors(iSCSIHBAUserClient);
+
+public:
+
+ /*! Invoked after initWithTask() as a result of the user-space application
+ * calling IOServiceOpen(). */
+ virtual bool start(IOService * provider);
+
+ /*! Called to stop this service. */
+ virtual void stop(IOService * provider);
+
+ /*! Invoked as a result of the user-space application calling
+ * IOServiceOpen(). */
+ virtual bool initWithTask(task_t owningTask,
+ void * securityToken,
+ UInt32 type,
+ OSDictionary * properties);
+
+ /*! Dispatched function called from the device interface to this user
+ * client .*/
+ static IOReturn OpenInitiator(iSCSIHBAUserClient * target,
+ void * reference,
+ IOExternalMethodArguments * args);
+
+ /*! Dispatched function called from the device interface to this user
+ * client .*/
+ static IOReturn CloseInitiator(iSCSIHBAUserClient * target,
+ void * reference,
+ IOExternalMethodArguments * args);
+
+ /*! Dispatched function invoked from user-space to create new session. */
+ static IOReturn CreateSession(iSCSIHBAUserClient * target,
+ void * reference,
+ IOExternalMethodArguments * args);
+
+ /*! Dispatched function invoked from user-space to release session. */
+ static IOReturn ReleaseSession(iSCSIHBAUserClient * target,
+ void * reference,
+ IOExternalMethodArguments * args);
+
+ static IOReturn SetSessionParameter(iSCSIHBAUserClient * target,
+ void * reference,
+ IOExternalMethodArguments * args);
+
+ static IOReturn GetSessionParameter(iSCSIHBAUserClient * target,
+ void * reference,
+ IOExternalMethodArguments * args);
+
+ /*! Dispatched function invoked from user-space to create new connection. */
+ static IOReturn CreateConnection(iSCSIHBAUserClient * target,
+ void * reference,
+ IOExternalMethodArguments * args);
+
+ /*! Dispatched function invoked from user-space to release connection. */
+ static IOReturn ReleaseConnection(iSCSIHBAUserClient * target,
+ void * reference,
+ IOExternalMethodArguments * args);
+
+ static IOReturn ActivateConnection(iSCSIHBAUserClient * target,
+ void * reference,
+ IOExternalMethodArguments * args);
+
+ static IOReturn ActivateAllConnections(iSCSIHBAUserClient * target,
+ void * reference,
+ IOExternalMethodArguments * args);
+
+ static IOReturn DeactivateConnection(iSCSIHBAUserClient * target,
+ void * reference,
+ IOExternalMethodArguments * args);
+
+ static IOReturn DeactivateAllConnections(iSCSIHBAUserClient * target,
+ void * reference,
+ IOExternalMethodArguments * args);
+
+ static IOReturn GetConnection(iSCSIHBAUserClient * target,
+ void * reference,
+ IOExternalMethodArguments * args);
+
+ static IOReturn GetNumConnections(iSCSIHBAUserClient * target,
+ void * reference,
+ IOExternalMethodArguments * args);
+
+ static IOReturn GetSessionIdForTargetIQN(iSCSIHBAUserClient * target,
+ void * reference,
+ IOExternalMethodArguments * args);
+
+ static IOReturn GetConnectionIdForPortalAddress(iSCSIHBAUserClient * target,
+ void * reference,
+ IOExternalMethodArguments * args);
+
+ static IOReturn GetSessionIds(iSCSIHBAUserClient * target,
+ void * reference,
+ IOExternalMethodArguments * args);
+
+ static IOReturn GetConnectionIds(iSCSIHBAUserClient * target,
+ void * reference,
+ IOExternalMethodArguments * args);
+
+ static IOReturn GetTargetIQNForSessionId(iSCSIHBAUserClient * target,
+ void * reference,
+ IOExternalMethodArguments * args);
+
+
+ static IOReturn GetPortalAddressForConnectionId(iSCSIHBAUserClient * target,
+ void * reference,
+ IOExternalMethodArguments * args);
+
+
+ static IOReturn GetPortalPortForConnectionId(iSCSIHBAUserClient * target,
+ void * reference,
+ IOExternalMethodArguments * args);
+
+ static IOReturn GetHostInterfaceForConnectionId(iSCSIHBAUserClient * target,
+ void * reference,
+ IOExternalMethodArguments * args);
+
+ /*! Dispatched function invoked from user-space to send data
+ * over an existing, active connection. */
+ static IOReturn SendBHS(iSCSIHBAUserClient * target,
+ void * reference,
+ IOExternalMethodArguments * args);
+
+ /*! Dispatched function invoked from user-space to send data
+ * over an existing, active connection. */
+ static IOReturn SendData(iSCSIHBAUserClient * target,
+ void * reference,
+ IOExternalMethodArguments * args);
+
+ /*! Dispatched function invoked from user-space to receive data
+ * over an existing, active connection, and to retrieve the size of
+ * a user-space buffer that is required to hold the data. */
+ static IOReturn RecvBHS(iSCSIHBAUserClient * target,
+ void * reference,
+ IOExternalMethodArguments * args);
+
+ /*! Dispatched function invoked from user-space to receive data
+ * over an existing, active connection, and to retrieve the size of
+ * a user-space buffer that is required to hold the data. */
+ static IOReturn RecvData(iSCSIHBAUserClient * target,
+ void * reference,
+ IOExternalMethodArguments * args);
+
+ static IOReturn SetConnectionParameter(iSCSIHBAUserClient * target,
+ void * reference,
+ IOExternalMethodArguments * args);
+
+ static IOReturn GetConnectionParameter(iSCSIHBAUserClient * target,
+ void * reference,
+ IOExternalMethodArguments * args);
+
+ static IOReturn GetActiveConnection(iSCSIHBAUserClient * target,
+ void * reference,
+ IOExternalMethodArguments * args);
+
+ /*! Overrides IOUserClient's externalMethod to allow users to call
+ * dispatched functions defined by this subclass. */
+ virtual IOReturn externalMethod(uint32_t selector,
+ IOExternalMethodArguments * args,
+ IOExternalMethodDispatch * dispatch,
+ OSObject * target,
+ void * ref);
+
+ /*! Opens an exclusive connection to the iSCSI initiator device driver. The
+ * driver can handle multiple iSCSI targets with multiple LUNs. This
+ * function is remotely invoked by the user-space application. */
+ virtual IOReturn open();
+
+ /*! Closes the connection to the iSCSI initiator device driver. Leaves
+ * iSCSI target connections intact. This function is remotely invoked
+ * by the user-space application. */
+ virtual IOReturn close();
+
+ /*! Invoked when the user-space application calls IOServiceClose. */
+ virtual IOReturn clientClose();
+
+ /*! Invoked when the user-space application is terminated without calling
+ * IOServiceClose or remotely invoking close(). */
+ virtual IOReturn clientDied();
+
+ /*! Invoked when a user-space application registers a notification port
+ * with this user client.
+ * @param port the port associated with the client connection.
+ * @param type the type.
+ * @param refCon a user reference value.
+ * @return an error code indicating the result of the operation. */
+ virtual IOReturn registerNotificationPort(mach_port_t port,
+ UInt32 type,
+ io_user_reference_t refCon);
+
+ /*! Send a notification message to the user-space application.
+ * @param message details regarding the notification message.
+ * @return an error code indicating the result of the operation. */
+ IOReturn sendNotification(iSCSIHBANotificationMessage * message);
+
+ /*! Sends a notification message to the user indicating that an
+ * iSCSI asynchronous event has occured.
+ * @param sessionId the session identifier.
+ * @param connectionId the connection identifier.
+ * @param event the asynchronous event.
+ * @return an error code indicating the result of the operation. */
+ IOReturn sendAsyncMessageNotification(SessionIdentifier sessionId,
+ ConnectionIdentifier connectionId,
+ enum iSCSIPDUAsyncMsgEvent event);
+
+ /*! Notifies clients that a network connnectivity issue has
+ * caused the specified connection and session to be dropped.
+ * @param sessionId session identifier.
+ * @param connectionId conncetion identifier.
+ * @return an error code indicating the result of the operation. */
+ IOReturn sendTimeoutMessageNotification(SessionIdentifier sessionId,ConnectionIdentifier connectionId);
+
+ /*! Sends a notification message to the user indicating that the kernel
+ * extension will be terminating.
+ * @return an error code indicating the result of the operation. */
+ IOReturn sendTerminateMessageNotification();
+
+ /*! Array of methods that can be called by user-space. */
+ static const IOExternalMethodDispatch methods[kiSCSIInitiatorNumMethods];
+
+private:
+
+ /*! Points to the provider object (driver). The pointer is assigned
+ * when the start() function is called by the I/O Kit. */
+ iSCSIVirtualHBA * provider;
+
+ /*! Holds a basic header segment (buffer). Used when sending and
+ * receiving PDUs to and from the target. */
+ iSCSIPDUInitiatorBHS bhsBuffer;
+
+ /*! Identifies the Mach task (user-space) that opened a connection to this
+ * client. */
+ task_t owningTask;
+
+ /*! A security token that identifies user privileges. */
+ void * securityToken;
+
+ /*! A security type that identifies user privileges. */
+ UInt32 type;
+
+ /*! The notification port associated with a user-space connection. */
+ mach_port_t notificationPort;
+
+ /*! Access lock for kernel functions. */
+ IOLock * accessLock;
+};
+
+#endif /* defined(__ISCSI_USER_CLIENT_H__) */
diff --git a/Source/Kernel/iSCSIInitiator.cpp b/Source/Kernel/iSCSIInitiator.cpp
index 7fc120b5..7e683103 100644
--- a/Source/Kernel/iSCSIInitiator.cpp
+++ b/Source/Kernel/iSCSIInitiator.cpp
@@ -28,7 +28,7 @@
#include
#include "iSCSIInitiator.h"
-#include "iSCSIKernelInterfaceShared.h"
+#include "iSCSIHBATypes.h"
/*! Required IOKit macro that defines the constructors, destructors, etc. */
OSDefineMetaClassAndStructors(iSCSIInitiator,IOService);
diff --git a/Source/Kernel/iSCSIKernelClasses.h b/Source/Kernel/iSCSIKernelClasses.h
index 283f92eb..496ab791 100644
--- a/Source/Kernel/iSCSIKernelClasses.h
+++ b/Source/Kernel/iSCSIKernelClasses.h
@@ -39,7 +39,7 @@
#define iSCSIVirtualHBA ADD_PREFIX(iSCSIVirtualHBA)
#define iSCSITaskQueue ADD_PREFIX(iSCSITaskQueue)
#define iSCSIIOEventSource ADD_PREFIX(iSCSIIOEventSource)
-#define iSCSIInitiatorClient ADD_PREFIX(iSCSIInitiatorClient)
+#define iSCSIHBAUserClient ADD_PREFIX(iSCSIHBAUserClient)
#define iSCSIInitiator ADD_PREFIX(iSCSIInitiator)
#define kiSCSIVirtualHBA_IOClassName STRINGIFY_EVAL(iSCSIVirtualHBA)
diff --git a/Source/Kernel/iSCSITypesKernel.h b/Source/Kernel/iSCSITypesKernel.h
index 104824a1..edd9d162 100644
--- a/Source/Kernel/iSCSITypesKernel.h
+++ b/Source/Kernel/iSCSITypesKernel.h
@@ -46,7 +46,7 @@ typedef struct iSCSIConnection {
UInt32 expStatSN;
/*! Connection ID. */
- CID cid; // Might need this for ErrorRecovery (otherwise have to search through list for it)
+ ConnectionIdentifier cid;
/*! Portal address (IPv4/IPv6/DNS address). */
OSString * portalAddress;
@@ -146,7 +146,7 @@ typedef struct iSCSISession {
/*! The initiator session ID, which is also used as the target ID within
* this kernel extension since there is a 1-1 mapping. */
- SID sessionId;
+ SessionIdentifier sessionId;
/*! Command sequence number to be used for the next initiator command. */
UInt32 cmdSN;
@@ -203,10 +203,10 @@ typedef struct iSCSISession {
UInt32 firstBurstLength;
/*! Target session identifying handle. */
- TSIH targetSessionId;
+ TargetSessionIdentifier targetSessionId;
/*! Target portal group tag. */
- TPGT targetPortalGroupTag;
+ TargetPortalGroupTag targetPortalGroupTag;
} iSCSISession;
diff --git a/Source/Kernel/iSCSIVirtualHBA.cpp b/Source/Kernel/iSCSIVirtualHBA.cpp
index 3e1f0919..c21ef868 100644
--- a/Source/Kernel/iSCSIVirtualHBA.cpp
+++ b/Source/Kernel/iSCSIVirtualHBA.cpp
@@ -31,7 +31,7 @@
#include "iSCSITaskQueue.h"
#include "iSCSITypesKernel.h"
#include "iSCSIRFC3720Defaults.h"
-#include "iSCSIInitiatorClient.h"
+#include "iSCSIHBAUserClient.h"
#include "crc32c.h"
#include
@@ -78,7 +78,7 @@ const UInt32 iSCSIVirtualHBA::kMaxTaskCount = 10;
const UInt32 iSCSIVirtualHBA::kNumBytesPerAvgBW = 1048576;
/*! Default task timeout for new tasks (milliseconds). */
-const UInt32 iSCSIVirtualHBA::kiSCSITaskTimeoutMs = 60000;
+const UInt32 iSCSIVirtualHBA::kiSCSITaskTimeoutMs = 20000;
/*! Default TCP timeout for new connections (seconds). */
const UInt32 iSCSIVirtualHBA::kiSCSITCPTimeoutSec = 1;
@@ -397,8 +397,8 @@ void iSCSIVirtualHBA::HandleTimeout(SCSIParallelTaskIdentifier task)
{
// Determine the target identifier (session identifier) and connection
// associated with this task and remove the task from the task queue.
- SID sessionId = (UInt16)GetTargetIdentifier(task);
- CID connectionId = *((UInt32*)GetHBADataPointer(task));
+ SessionIdentifier sessionId = (UInt16)GetTargetIdentifier(task);
+ ConnectionIdentifier connectionId = *((UInt32*)GetHBADataPointer(task));
if(connectionId >= kMaxConnectionsPerSession)
return;
@@ -438,7 +438,7 @@ void iSCSIVirtualHBA::HandleTimeout(SCSIParallelTaskIdentifier task)
/*! Handles connection timeouts.
* @param sessionId the session associated with the timed-out connection.
* @param connectionId the connection that timed out. */
-void iSCSIVirtualHBA::HandleConnectionTimeout(SID sessionId,CID connectionId)
+void iSCSIVirtualHBA::HandleConnectionTimeout(SessionIdentifier sessionId,ConnectionIdentifier connectionId)
{
// If this is the last connection, release the session...
iSCSISession * session;
@@ -448,16 +448,29 @@ void iSCSIVirtualHBA::HandleConnectionTimeout(SID sessionId,CID connectionId)
DBLog("iscsi: Connection timeout (sid: %d, cid: %d)\n",sessionId,connectionId);
- CID connectionCount = 0;
- for(CID connectionId = 0; connectionId < kiSCSIMaxConnectionsPerSession; connectionId++)
+ ConnectionIdentifier connectionCount = 0;
+ for(ConnectionIdentifier connectionId = 0; connectionId < kiSCSIMaxConnectionsPerSession; connectionId++)
if(session->connections[connectionId])
connectionCount++;
+ iSCSIHBAUserClient * client = (iSCSIHBAUserClient*)getClient();
+
// In the future add recovery here...
if(connectionCount > 1)
- ReleaseConnection(sessionId,connectionId);
+ DeactivateConnection(sessionId,connectionId);
else
- ReleaseSession(sessionId);
+ DeactivateAllConnections(sessionId);
+
+ // Send a notification to the daemon; if the daemon does not respond then
+ // release the session or connection as appropriate
+ if(client->sendTimeoutMessageNotification(sessionId,connectionId) != kIOReturnSuccess)
+ {
+ if(connectionCount > 1)
+ ReleaseConnection(sessionId,connectionId);
+ else
+ ReleaseSession(sessionId);
+ }
+
}
SCSIServiceResponse iSCSIVirtualHBA::ProcessParallelTask(SCSIParallelTaskIdentifier parallelTask)
@@ -468,7 +481,7 @@ SCSIServiceResponse iSCSIVirtualHBA::ProcessParallelTask(SCSIParallelTaskIdentif
SCSILogicalUnitNumber LUN = GetLogicalUnitNumber(parallelTask);
SCSITaggedTaskIdentifier taskId = GetTaggedTaskIdentifier(parallelTask);
- iSCSISession * session = sessionList[(SID)targetId];
+ iSCSISession * session = sessionList[(SessionIdentifier)targetId];
if(!session)
return kSCSIServiceResponse_FUNCTION_REJECTED;
@@ -676,6 +689,7 @@ bool iSCSIVirtualHBA::ProcessTaskOnWorkloopThread(iSCSIVirtualHBA * owner,
// Grab incoming bhs (we are guaranteed to have a basic header at this
// point (iSCSIIOEventSource ensures that this is the case)
iSCSIPDUTargetBHS bhs;
+
if(owner->RecvPDUHeader(session,connection,&bhs,0))
{
DBLog("iscsi: Failed to get PDU header (sid: %d, cid: %d)\n",
@@ -1058,7 +1072,7 @@ void iSCSIVirtualHBA::ProcessAsyncMsg(iSCSISession * session,
DBLog("iscsi: Async Message (code %#x) received (sid: %d, cid: %d)\n",
asyncEvent,session->sessionId,connection->cid);
- iSCSIInitiatorClient * client = (iSCSIInitiatorClient*)getClient();
+ iSCSIHBAUserClient * client = (iSCSIHBAUserClient*)getClient();
if(!client) {
DBLog("iscsi: client is not available; async message may not be processed correctly\n");
}
@@ -1281,8 +1295,8 @@ errno_t iSCSIVirtualHBA::CreateSession(OSString * targetIQN,
OSString * hostInterface,
const struct sockaddr_storage * portalSockaddr,
const struct sockaddr_storage * hostSockaddr,
- SID * sessionId,
- CID * connectionId)
+ SessionIdentifier * sessionId,
+ ConnectionIdentifier * connectionId)
{
// Validate inputs
if(!portalSockaddr || !hostSockaddr || !sessionId || !connectionId)
@@ -1296,7 +1310,7 @@ errno_t iSCSIVirtualHBA::CreateSession(OSString * targetIQN,
errno_t error = EAGAIN;
// Find an open session slot
- SID sessionIdx;
+ SessionIdentifier sessionIdx;
for(sessionIdx = 0; sessionIdx < kMaxSessions; sessionIdx++)
if(!sessionList[sessionIdx])
break;
@@ -1381,7 +1395,7 @@ void iSCSIVirtualHBA::ReleaseAllSessions()
{
// Go through every connection for each session, and close sockets,
// remove event sources, etc
- for(SID index = 0; index < kMaxSessions; index++)
+ for(SessionIdentifier index = 0; index < kMaxSessions; index++)
{
if(!sessionList[index])
continue;
@@ -1393,7 +1407,7 @@ void iSCSIVirtualHBA::ReleaseAllSessions()
/*! Releases an iSCSI session, including all connections associated with that
* session.
* @param sessionId the session qualifier part of the ISID. */
-void iSCSIVirtualHBA::ReleaseSession(SID sessionId)
+void iSCSIVirtualHBA::ReleaseSession(SessionIdentifier sessionId)
{
// Range-check inputs
if(sessionId >= kMaxSessions)
@@ -1408,7 +1422,7 @@ void iSCSIVirtualHBA::ReleaseSession(SID sessionId)
DBLog("iscsi: Releasing session (sid %d)\n",sessionId);
// Disconnect all connections
- for(CID connectionId = 0; connectionId < kMaxConnectionsPerSession; connectionId++)
+ for(ConnectionIdentifier connectionId = 0; connectionId < kMaxConnectionsPerSession; connectionId++)
{
if(theSession->connections[connectionId])
ReleaseConnection(sessionId,connectionId);
@@ -1445,13 +1459,13 @@ void iSCSIVirtualHBA::ReleaseSession(SID sessionId)
* @param hostSockaddr the BSD socket structure used to identify the host adapter.
* @param connectionId identifier for the new connection.
* @return error code indicating result of operation. */
-errno_t iSCSIVirtualHBA::CreateConnection(SID sessionId,
+errno_t iSCSIVirtualHBA::CreateConnection(SessionIdentifier sessionId,
OSString * portalAddress,
OSString * portalPort,
OSString * hostInterface,
const struct sockaddr_storage * portalSockaddr,
const struct sockaddr_storage * hostSockaddr,
- CID * connectionId)
+ ConnectionIdentifier * connectionId)
{
// Range-check inputs
if(sessionId >= kMaxSessions || !portalSockaddr || !hostSockaddr || !connectionId)
@@ -1463,7 +1477,7 @@ errno_t iSCSIVirtualHBA::CreateConnection(SID sessionId,
return EINVAL;
// Find an empty connection slot to use for a new connection
- CID index;
+ ConnectionIdentifier index;
for(index = 0; index < kMaxConnectionsPerSession; index++)
if(!session->connections[index])
break;
@@ -1595,8 +1609,8 @@ errno_t iSCSIVirtualHBA::CreateConnection(SID sessionId,
/*! Frees a given iSCSI connection associated with a given session.
* The session should be logged out using the appropriate PDUs. */
-void iSCSIVirtualHBA::ReleaseConnection(SID sessionId,
- CID connectionId)
+void iSCSIVirtualHBA::ReleaseConnection(SessionIdentifier sessionId,
+ ConnectionIdentifier connectionId)
{
// Range-check inputs
if(sessionId >= kMaxSessions || connectionId >= kMaxConnectionsPerSession)
@@ -1642,7 +1656,7 @@ void iSCSIVirtualHBA::ReleaseConnection(SID sessionId,
* @param sessionId the session to deactivate.
* @param connectionId the connection to deactivate.
* @return error code indicating result of operation. */
-errno_t iSCSIVirtualHBA::ActivateConnection(SID sessionId,CID connectionId)
+errno_t iSCSIVirtualHBA::ActivateConnection(SessionIdentifier sessionId,ConnectionIdentifier connectionId)
{
if(sessionId == kiSCSIInvalidSessionId || connectionId == kiSCSIInvalidConnectionId)
return EINVAL;
@@ -1687,7 +1701,7 @@ errno_t iSCSIVirtualHBA::ActivateConnection(SID sessionId,CID connectionId)
* @param sessionId the session to deactivate.
* @param connectionId the connection to deactivate.
* @return error code indicating result of operation. */
-errno_t iSCSIVirtualHBA::ActivateAllConnections(SID sessionId)
+errno_t iSCSIVirtualHBA::ActivateAllConnections(SessionIdentifier sessionId)
{
if(sessionId == kiSCSIInvalidSessionId)
return EINVAL;
@@ -1699,7 +1713,7 @@ errno_t iSCSIVirtualHBA::ActivateAllConnections(SID sessionId)
return EINVAL;
errno_t error = 0;
- for(CID connectionId = 0; connectionId < kMaxConnectionsPerSession; connectionId++)
+ for(ConnectionIdentifier connectionId = 0; connectionId < kMaxConnectionsPerSession; connectionId++)
if((error = ActivateConnection(sessionId,connectionId)))
return error;
@@ -1711,7 +1725,7 @@ errno_t iSCSIVirtualHBA::ActivateAllConnections(SID sessionId)
* @param sessionId the session to deactivate.
* @param connectionId the connection to deactivate.
* @return error code indicating result of operation. */
-errno_t iSCSIVirtualHBA::DeactivateConnection(SID sessionId,CID connectionId)
+errno_t iSCSIVirtualHBA::DeactivateConnection(SessionIdentifier sessionId,ConnectionIdentifier connectionId)
{
if(sessionId >= kMaxSessions || connectionId >= kMaxConnectionsPerSession)
return EINVAL;
@@ -1766,7 +1780,7 @@ errno_t iSCSIVirtualHBA::DeactivateConnection(SID sessionId,CID connectionId)
* negotiated by the iSCSI daemon.
* @param sessionId the session to deactivate.
* @return error code indicating result of operation. */
-errno_t iSCSIVirtualHBA::DeactivateAllConnections(SID sessionId)
+errno_t iSCSIVirtualHBA::DeactivateAllConnections(SessionIdentifier sessionId)
{
if(sessionId >= kMaxSessions)
return EINVAL;
@@ -1778,7 +1792,7 @@ errno_t iSCSIVirtualHBA::DeactivateAllConnections(SID sessionId)
return EINVAL;
errno_t error = 0;
- for(CID connectionId = 0; connectionId < kMaxConnectionsPerSession; connectionId++)
+ for(ConnectionIdentifier connectionId = 0; connectionId < kMaxConnectionsPerSession; connectionId++)
{
if(session->connections[connectionId])
{
@@ -1897,9 +1911,16 @@ errno_t iSCSIVirtualHBA::SendPDU(iSCSISession * session,
// Update io vector count, send data
msg.msg_iovlen = iovecCnt;
size_t bytesSent = 0;
- int result = sock_send(connection->socket,&msg,0,&bytesSent);
+ errno_t error;
- return result;
+ if((error = sock_send(connection->socket,&msg,0,&bytesSent)))
+ {
+ DBLog("iscsi: sock_send error returned with code %d (sid: %d, cid: %d)\n",error,session->sessionId,connection->cid);
+ HandleConnectionTimeout(session->sessionId,connection->cid);
+ return error;
+ }
+
+ return error;
}
@@ -1959,13 +1980,22 @@ errno_t iSCSIVirtualHBA::RecvPDUHeader(iSCSISession * session,
// Bytes received from sock_receive call
size_t bytesRecv;
- errno_t result = sock_receive(connection->socket,&msg,MSG_WAITALL,&bytesRecv);
-
- if(result != 0)
- DBLog("iscsi: sock_receive error returned with code %d (sid: %d, cid: %d)\n",result,session->sessionId,connection->cid);
+ errno_t error;
+ // Handle connection problems
+ if((error = sock_receive(connection->socket,&msg,MSG_WAITALL,&bytesRecv)))
+ {
+ if(error != EWOULDBLOCK) {
+ DBLog("iscsi: sock_receive error returned with code %d (sid: %d, cid: %d)\n",error,session->sessionId,connection->cid);
+ HandleConnectionTimeout(session->sessionId,connection->cid);
+ return error;
+ }
+ else
+ error = 0;
+ }
+
// Verify length; incoming PDUS from a target should have no AHS, verify.
- if(bytesRecv < kiSCSIPDUBasicHeaderSegmentSize || bhs->totalAHSLength != 0)
+ if(bytesRecv < kiSCSIPDUBasicHeaderSegmentSize)// || bhs->totalAHSLength != 0)
{
DBLog("iscsi: Received incomplete PDU header: %zu bytes (sid: %d, cid: %d)\n",bytesRecv,session->sessionId,connection->cid);
@@ -1990,12 +2020,13 @@ errno_t iSCSIVirtualHBA::RecvPDUHeader(iSCSISession * session,
// Update command sequence numbers only if the PDU was not a data PDU
// (unless the data PDU contains a SCSI service response)
+
if(bhs->opCode == kiSCSIPDUOpCodeDataIn) {
iSCSIPDUDataInBHS * bhsDataIn = (iSCSIPDUDataInBHS *)bhs;
if((bhsDataIn->flags & kiSCSIPDUDataInStatusFlag) == 0)
- return result;
+ return error;
}
-
+
// Read and update the command sequence numbers
bhs->maxCmdSN = OSSwapBigToHostInt32(bhs->maxCmdSN);
bhs->expCmdSN = OSSwapBigToHostInt32(bhs->expCmdSN);
@@ -2009,7 +2040,7 @@ errno_t iSCSIVirtualHBA::RecvPDUHeader(iSCSISession * session,
if(bhs->opCode != kiSCSIPDUOpCodeR2T && bhs->statSN != 0xffffffff && bhs->initiatorTaskTag != 0xffffffff)
OSIncrementAtomic(&connection->expStatSN);
- return result;
+ return error;
}
/*! Receives a data segment over a kernel socket. If the specified length is
@@ -2066,7 +2097,19 @@ errno_t iSCSIVirtualHBA::RecvPDUData(iSCSISession * session,
msg.msg_iovlen = iovecCnt;
size_t bytesRecv;
- errno_t result = sock_receive(connection->socket,&msg,MSG_WAITALL,&bytesRecv);
+ errno_t error = 0;
+
+ // Handle connection problems
+ if((error = sock_receive(connection->socket,&msg,MSG_WAITALL,&bytesRecv)))
+ {
+ if(error != EWOULDBLOCK) {
+ DBLog("iscsi: sock_receive error returned with code %d (sid: %d, cid: %d)\n",error,session->sessionId,connection->cid);
+ HandleConnectionTimeout(session->sessionId,connection->cid);
+ return error;
+ }
+ else
+ error = 0;
+ }
// Verify digest if present
if(connection->useDataDigest)
@@ -2084,5 +2127,5 @@ errno_t iSCSIVirtualHBA::RecvPDUData(iSCSISession * session,
}
}
- return result;
+ return error;
}
diff --git a/Source/Kernel/iSCSIVirtualHBA.h b/Source/Kernel/iSCSIVirtualHBA.h
index 98fe6a04..223db542 100644
--- a/Source/Kernel/iSCSIVirtualHBA.h
+++ b/Source/Kernel/iSCSIVirtualHBA.h
@@ -41,7 +41,7 @@
#include "iSCSIKernelClasses.h"
#include "iSCSITypesKernel.h"
#include "iSCSITypesShared.h"
-#include "iSCSIKernelInterfaceShared.h"
+#include "iSCSIHBATypes.h"
#include "iSCSIPDUKernel.h"
// BSD socket includes
@@ -63,7 +63,7 @@
* and then returned to the OS. */
class iSCSIVirtualHBA : public IOSCSIParallelInterfaceController
{
- friend class iSCSIInitiatorClient;
+ friend class iSCSIHBAUserClient;
OSDeclareDefaultStructors(iSCSIVirtualHBA);
@@ -150,7 +150,7 @@ class iSCSIVirtualHBA : public IOSCSIParallelInterfaceController
/*! Handles connection timeouts.
* @param sessionId the session associated with the timed-out connection.
* @param connectionId the connection that timed out. */
- void HandleConnectionTimeout(SID sessionId,CID connectionId);
+ void HandleConnectionTimeout(SessionIdentifier sessionId,ConnectionIdentifier connectionId);
/*! Processes a task passed down by SCSI target devices in driver stack.
* @param parallelTask the task to process.
@@ -208,8 +208,8 @@ class iSCSIVirtualHBA : public IOSCSIParallelInterfaceController
OSString * hostInterface,
const struct sockaddr_storage * portalSockaddr,
const struct sockaddr_storage * hostSockaddr,
- SID * sessionId,
- CID * connectionId);
+ SessionIdentifier * sessionId,
+ ConnectionIdentifier * connectionId);
/*! Releases all iSCSI sessions. */
void ReleaseAllSessions();
@@ -218,7 +218,7 @@ class iSCSIVirtualHBA : public IOSCSIParallelInterfaceController
* session. Connections may be active or inactive when this function is
* called.
* @param sessionId the session qualifier part of the ISID. */
- void ReleaseSession(SID sessionId);
+ void ReleaseSession(SessionIdentifier sessionId);
/*! Allocates a new iSCSI connection associated with the particular session.
* @param sessionId the session to create a new connection for.
@@ -229,17 +229,17 @@ class iSCSIVirtualHBA : public IOSCSIParallelInterfaceController
* @param hostSockaddr the BSD socket structure used to identify the host adapter.
* @param connectionId identifier for the new connection.
* @return error code indicating result of operation. */
- errno_t CreateConnection(SID sessionId,
+ errno_t CreateConnection(SessionIdentifier sessionId,
OSString * portalAddress,
OSString * portalPort,
OSString * hostInterface,
const struct sockaddr_storage * portalSockaddr,
const struct sockaddr_storage * hostSockaddr,
- CID * connectionId);
+ ConnectionIdentifier * connectionId);
/*! Frees a given iSCSI connection associated with a given session.
* The session should be logged out using the appropriate PDUs. */
- void ReleaseConnection(SID sessionId,CID connectionId);
+ void ReleaseConnection(SessionIdentifier sessionId,ConnectionIdentifier connectionId);
/*! Activates an iSCSI connection, indicating to the kernel that the iSCSI
* daemon has negotiated security and operational parameters and that the
@@ -247,7 +247,7 @@ class iSCSIVirtualHBA : public IOSCSIParallelInterfaceController
* @param sessionId the session to deactivate.
* @param connectionId the connection to deactivate.
* @return error code indicating result of operation. */
- errno_t ActivateConnection(SID sessionId,CID connectionId);
+ errno_t ActivateConnection(SessionIdentifier sessionId,ConnectionIdentifier connectionId);
/*! Activates all iSCSI connections for the session, indicating to the
* kernel that the iSCSI daemon has negotiated security and operational
@@ -255,19 +255,19 @@ class iSCSIVirtualHBA : public IOSCSIParallelInterfaceController
* @param sessionId the session to deactivate.
* @param connectionId the connection to deactivate.
* @return error code indicating result of operation. */
- errno_t ActivateAllConnections(SID sessionId);
+ errno_t ActivateAllConnections(SessionIdentifier sessionId);
/*! Deactivates an iSCSI connection so that parameters can be adjusted or
* negotiated by the iSCSI daemon.
* @param sessionId the session to deactivate.
* @return error code indicating result of operation. */
- errno_t DeactivateConnection(SID sessionId,CID connectionId);
+ errno_t DeactivateConnection(SessionIdentifier sessionId,ConnectionIdentifier connectionId);
/*! Deactivates all iSCSI connections so that parameters can be adjusted or
* negotiated by the iSCSI daemon.
* @param sessionId the session to deactivate.
* @return error code indicating result of operation. */
- errno_t DeactivateAllConnections(SID sessionId);
+ errno_t DeactivateAllConnections(SessionIdentifier sessionId);
/*! Sends data over a kernel socket associated with iSCSI. If the specified
* data segment length is not a multiple of 4-bytes, padding bytes will be
diff --git a/Source/User/iSCSI Framework/iSCSIDA.c b/Source/User/iSCSI Framework/iSCSIDA.c
index be1f8873..d5e91dd8 100644
--- a/Source/User/iSCSI Framework/iSCSIDA.c
+++ b/Source/User/iSCSI Framework/iSCSIDA.c
@@ -93,11 +93,13 @@ void iSCSIDADiskMountComplete(DADiskRef disk,DADissenterRef dissenter,void * con
void iSCSIDAUnmountApplierFunc(io_object_t entry, void * context)
{
iSCSIDiskOperationContext * opContext = (iSCSIDiskOperationContext*)context;
- opContext->diskCount++;
-
DADiskRef disk = DADiskCreateFromIOMedia(kCFAllocatorDefault,opContext->session,entry);
- DADiskUnmount(disk,opContext->options,iSCSIDADiskUnmountComplete,context);
- CFRelease(disk);
+
+ if(disk) {
+ DADiskUnmount(disk,opContext->options,iSCSIDADiskUnmountComplete,context);
+ CFRelease(disk);
+ opContext->diskCount++;
+ }
}
@@ -134,11 +136,14 @@ void iSCSIDAUnmountForTarget(DASessionRef session,
void iSCSIDAMountApplierFunc(io_object_t entry, void * context)
{
iSCSIDiskOperationContext * opContext = (iSCSIDiskOperationContext*)context;
- opContext->diskCount++;
DADiskRef disk = DADiskCreateFromIOMedia(kCFAllocatorDefault,opContext->session,entry);
- DADiskMount(disk,NULL,opContext->options,iSCSIDADiskMountComplete,context);
- CFRelease(disk);
+
+ if(disk) {
+ DADiskMount(disk,NULL,opContext->options,iSCSIDADiskMountComplete,context);
+ CFRelease(disk);
+ opContext->diskCount++;
+ }
}
/*! Mounts all IOMedia associated with a particular iSCSI session, and
diff --git a/Source/User/iSCSI Framework/iSCSIDaemonInterface.c b/Source/User/iSCSI Framework/iSCSIDaemonInterface.c
index aeef8120..23aa0728 100644
--- a/Source/User/iSCSI Framework/iSCSIDaemonInterface.c
+++ b/Source/User/iSCSI Framework/iSCSIDaemonInterface.c
@@ -724,13 +724,13 @@ errno_t iSCSIDaemonSetSharedSecret(iSCSIDaemonHandle handle,
kAuthorizationExternalFormLength,
kCFAllocatorDefault);
- CFDataRef nodeIQNData = CFStringCreateExternalRepresentation(kCFAllocatorDefault,nodeIQN,kCFStringEncodingASCII,NULL);
- CFDataRef sharedSecretData = CFStringCreateExternalRepresentation(kCFAllocatorDefault,sharedSecret,kCFStringEncodingASCII,NULL);
+ CFDataRef nodeIQNData = CFStringCreateExternalRepresentation(kCFAllocatorDefault,nodeIQN,kCFStringEncodingASCII,0);
+ CFDataRef sharedSecretData = CFStringCreateExternalRepresentation(kCFAllocatorDefault,sharedSecret,kCFStringEncodingASCII,0);
iSCSIDMsgSetSharedSecretCmd cmd = iSCSIDMsgSetSharedSecretCmdInit;
cmd.authorizationLength = (UInt32)CFDataGetLength(authData);
- cmd.nodeIQNLength = CFDataGetLength(nodeIQNData);
- cmd.secretLength = CFDataGetLength(sharedSecretData);
+ cmd.nodeIQNLength = (UInt32)CFDataGetLength(nodeIQNData);
+ cmd.secretLength = (UInt32)CFDataGetLength(sharedSecretData);
errno_t error = iSCSIDaemonSendMsg(handle,(iSCSIDMsgGeneric *)&cmd,
authData,nodeIQNData,sharedSecretData,NULL);
@@ -780,7 +780,7 @@ errno_t iSCSIDaemonRemoveSharedSecret(iSCSIDaemonHandle handle,
iSCSIDMsgRemoveSharedSecretCmd cmd = iSCSIDMsgRemoveSharedSecretCmdInit;
cmd.authorizationLength = (UInt32)CFDataGetLength(authData);
- cmd.nodeIQNLength = CFDataGetLength(nodeIQNData);
+ cmd.nodeIQNLength = (UInt32)CFDataGetLength(nodeIQNData);
errno_t error = iSCSIDaemonSendMsg(handle,(iSCSIDMsgGeneric *)&cmd,
authData,nodeIQNData,NULL);
diff --git a/Source/User/iSCSI Framework/iSCSIIORegistry.c b/Source/User/iSCSI Framework/iSCSIIORegistry.c
index 6a9f5f0a..31cfb3b2 100644
--- a/Source/User/iSCSI Framework/iSCSIIORegistry.c
+++ b/Source/User/iSCSI Framework/iSCSIIORegistry.c
@@ -38,7 +38,7 @@
#include
#include
-#include "iSCSIKernelInterfaceShared.h"
+#include "iSCSIHBATypes.h"
/*! Gets the iSCSIVirtualHBA object in the IO registry.*/
diff --git a/Source/User/iSCSI Framework/iSCSIPreferences.c b/Source/User/iSCSI Framework/iSCSIPreferences.c
index c681309b..021c1463 100644
--- a/Source/User/iSCSI Framework/iSCSIPreferences.c
+++ b/Source/User/iSCSI Framework/iSCSIPreferences.c
@@ -60,6 +60,9 @@ CFStringRef kiSCSIPVTargetConfigTypeDiscovery = CFSTR("SendTargets");
/*! Preference key name for auto-login of target. */
CFStringRef kiSCSIPKAutoLogin = CFSTR("Automatic Login");
+/*! Preference key name for target persistence. */
+CFStringRef kiSCSIPKPersistent = CFSTR("Persistent");
+
/*! Preference key name for error recovery level. */
CFStringRef kiSCSIPKErrorRecoveryLevel = CFSTR("Error Recovery Level");
@@ -213,6 +216,7 @@ CFMutableDictionaryRef iSCSIPreferencesCreateTargetDict()
CFDictionaryAddValue(targetDict,kiSCSIPKAuthCHAPName,(void *)CFSTR(""));
CFDictionaryAddValue(targetDict,kiSCSIPKAuth,kiSCSIPVAuthNone);
CFDictionaryAddValue(targetDict,kiSCSIPKAutoLogin,kCFBooleanFalse);
+ CFDictionaryAddValue(targetDict,kiSCSIPKPersistent,kCFBooleanTrue);
CFDictionaryAddValue(targetDict,kiSCSIPKMaxConnections,maxConnections);
CFDictionaryAddValue(targetDict,kiSCSIPKErrorRecoveryLevel,errorRecoveryLevel);
CFDictionaryAddValue(targetDict,kiSCSIPKHeaderDigest,kiSCSIPVDigestNone);
@@ -410,8 +414,8 @@ enum iSCSIErrorRecoveryLevels iSCSIPreferencesGetErrorRecoveryLevelForTarget(iSC
}
iSCSIPortalRef iSCSIPreferencesCopyPortalForTarget(iSCSIPreferencesRef preferences,
- CFStringRef targetIQN,
- CFStringRef portalAddress)
+ CFStringRef targetIQN,
+ CFStringRef portalAddress)
{
// Get list of portals for this target
CFMutableDictionaryRef portalsList = iSCSIPreferencesGetPortalsList(preferences,targetIQN,false);
@@ -672,6 +676,43 @@ Boolean iSCSIPreferencesGetAutoLoginForTarget(iSCSIPreferencesRef preferences,
return autoLogin;
}
+/*! Sets whether the a connection to the target should be re-established
+ * in the event of an interruption.
+ * @param preferences an iSCSI preferences object.
+ * @param targetIQN the target iSCSI qualified name (IQN).
+ * @param persistent true to make target persistent, false otherwise. */
+void iSCSIPreferencesSetPersistenceForTarget(iSCSIPreferencesRef preferences,
+ CFStringRef targetIQN,
+ Boolean persistent)
+{
+ CFMutableDictionaryRef targetDict = iSCSIPreferencesGetTargetDict(preferences,targetIQN,true);
+
+ if(targetDict) {
+ if(persistent)
+ CFDictionarySetValue(targetDict,kiSCSIPKPersistent,kCFBooleanTrue);
+ else
+ CFDictionarySetValue(targetDict,kiSCSIPKPersistent,kCFBooleanFalse);
+ }
+}
+
+/*! Gets whether the a connection to the target should be re-established
+ * in the event of an interruption.
+ * @param preferences an iSCSI preferences object.
+ * @param targetIQN the target iSCSI qualified name (IQN). */
+Boolean iSCSIPreferencesGetPersistenceForTarget(iSCSIPreferencesRef preferences,
+ CFStringRef targetIQN)
+{
+ CFMutableDictionaryRef targetDict = iSCSIPreferencesGetTargetDict(preferences,targetIQN,true);
+ Boolean persistent = false;
+
+ if(targetDict) {
+ if(CFDictionaryGetValue(targetDict,kiSCSIPKPersistent) == kCFBooleanTrue)
+ persistent = true;
+ }
+
+ return persistent;
+}
+
/*! Adds a target object with a specified portal.
* @param targetIQN the target iSCSI qualified name (IQN).
* @param portal the portal object to set. */
@@ -935,6 +976,10 @@ void iSCSIPreferencesSetTargetIQN(iSCSIPreferencesRef preferences,
CFStringRef existingIQN,
CFStringRef newIQN)
{
+ // Do not allow a change in IQN for dynamically configured targets
+ if(iSCSIPreferencesGetTargetConfigType(preferences,existingIQN) != kiSCSITargetConfigStatic)
+ return;
+
CFMutableDictionaryRef targetNodes = iSCSIPreferencesGetTargets(preferences,false);
CFMutableDictionaryRef target = iSCSIPreferencesGetTargetDict(preferences,existingIQN,false);
diff --git a/Source/User/iSCSI Framework/iSCSIPreferences.h b/Source/User/iSCSI Framework/iSCSIPreferences.h
index 6ffaa26e..5fa41796 100644
--- a/Source/User/iSCSI Framework/iSCSIPreferences.h
+++ b/Source/User/iSCSI Framework/iSCSIPreferences.h
@@ -152,6 +152,22 @@ void iSCSIPreferencesSetAutoLoginForTarget(iSCSIPreferencesRef preferences,
Boolean iSCSIPreferencesGetAutoLoginForTarget(iSCSIPreferencesRef preferences,
CFStringRef targetIQN);
+/*! Sets whether the a connection to the target should be re-established
+ * in the event of an interruption.
+ * @param preferences an iSCSI preferences object.
+ * @param targetIQN the target iSCSI qualified name (IQN).
+ * @param persistent true to make target persistent, false otherwise. */
+void iSCSIPreferencesSetPersistenceForTarget(iSCSIPreferencesRef preferences,
+ CFStringRef targetIQN,
+ Boolean persistent);
+
+/*! Gets whether the a connection to the target should be re-established
+ * in the event of an interruption.
+ * @param preferences an iSCSI preferences object.
+ * @param targetIQN the target iSCSI qualified name (IQN). */
+Boolean iSCSIPreferencesGetPersistenceForTarget(iSCSIPreferencesRef preferences,
+ CFStringRef targetIQN);
+
/*! Sets the maximum number of connections for the specified target.
* @param preferences an iSCSI preferences object.
* @param targetIQN the target iSCSI qualified name (IQN).
diff --git a/Source/User/iSCSI Framework/iSCSIRFC3720Keys.h b/Source/User/iSCSI Framework/iSCSIRFC3720Keys.h
index 203db8ed..583ba461 100644
--- a/Source/User/iSCSI Framework/iSCSIRFC3720Keys.h
+++ b/Source/User/iSCSI Framework/iSCSIRFC3720Keys.h
@@ -103,6 +103,10 @@ static CFStringRef kRFC3720_Value_SendTargetsAll = CFSTR("All");
static CFStringRef kRFC3720_Value_Yes = CFSTR("Yes");
static CFStringRef kRFC3720_Value_No = CFSTR("No");
+static CFStringRef kRFC3720_Value_Reject = CFSTR("Reject");
+static CFStringRef kRFC3720_Value_NotUnderstood = CFSTR("NotUnderstood");
+static CFStringRef kRFC3720_Value_Irrelevant = CFSTR("Irrelevant");
+
// Other keys associated with sessions
static CFStringRef kRFC3720_Key_TargetSessionId = CFSTR("TSIH");
diff --git a/Source/User/iSCSI Framework/iSCSITypes.c b/Source/User/iSCSI Framework/iSCSITypes.c
index c8ec5b03..d3640cb3 100644
--- a/Source/User/iSCSI Framework/iSCSITypes.c
+++ b/Source/User/iSCSI Framework/iSCSITypes.c
@@ -625,17 +625,17 @@ void iSCSISessionConfigSetErrorRecoveryLevel(iSCSIMutableSessionConfigRef target
}
/*! Gets the target portal group tag. */
-TPGT iSCSISessionConfigGetTargetPortalGroupTag(iSCSISessionConfigRef target)
+TargetPortalGroupTag iSCSISessionConfigGetTargetPortalGroupTag(iSCSISessionConfigRef target)
{
- TPGT targetPortalGroupTag = 0;
+ TargetPortalGroupTag targetPortalGroupTag = 0;
CFNumberRef targetPortalGroupTagNum = CFDictionaryGetValue(target,kiSCSISessionConfigPortalGroupTagKey);
CFNumberGetValue(targetPortalGroupTagNum,kCFNumberIntType,&targetPortalGroupTag);
- return (TPGT)targetPortalGroupTag;
+ return (TargetPortalGroupTag)targetPortalGroupTag;
}
/*! Sets the target portal group tag. */
void iSCSISessionConfigSetTargetPortalGroupTag(iSCSIMutableSessionConfigRef target,
- TPGT targetPortalGroupTag)
+ TargetPortalGroupTag targetPortalGroupTag)
{
CFNumberRef targetPortalGroupTagNum = CFNumberCreate(kCFAllocatorDefault,kCFNumberIntType,&targetPortalGroupTag);
CFDictionarySetValue(target,kiSCSISessionConfigPortalGroupTagKey,targetPortalGroupTagNum);
diff --git a/Source/User/iSCSI Framework/iSCSITypes.h b/Source/User/iSCSI Framework/iSCSITypes.h
index 8daa0168..45e1123b 100644
--- a/Source/User/iSCSI Framework/iSCSITypes.h
+++ b/Source/User/iSCSI Framework/iSCSITypes.h
@@ -84,6 +84,8 @@ typedef CFMutableDictionaryRef iSCSIMutableConnectionConfigRef;
#define kiSCSITypeDictionaryKeyCallbacks kCFTypeDictionaryKeyCallBacks
#define kiSCSITypeDictionaryValueCallbacks kCFTypeDictionaryValueCallBacks
+typedef CFTypeRef iSCSITypeRef;
+
/*! Error recovery levels. */
enum iSCSIErrorRecoveryLevels {
@@ -497,11 +499,11 @@ void iSCSISessionConfigSetErrorRecoveryLevel(iSCSIMutableSessionConfigRef config
enum iSCSIErrorRecoveryLevels errorRecoveryLevel);
/*! Gets the target portal group tag for the session. */
-TPGT iSCSISessionConfigGetTargetPortalGroupTag(iSCSISessionConfigRef config);
+TargetPortalGroupTag iSCSISessionConfigGetTargetPortalGroupTag(iSCSISessionConfigRef config);
/*! Sets the target portal group tag for the session. */
void iSCSISessionConfigSetTargetPortalGroupTag(iSCSIMutableSessionConfigRef config,
- TPGT targetPortalGroupTag);
+ TargetPortalGroupTag targetPortalGroupTag);
/*! Gets the maximum number of connections. */
UInt32 iSCSISessionConfigGetMaxConnections(iSCSISessionConfigRef config);
diff --git a/Source/User/iSCSI Framework/iSCSITypesShared.h b/Source/User/iSCSI Framework/iSCSITypesShared.h
index dc1ebb5a..8eacdb18 100644
--- a/Source/User/iSCSI Framework/iSCSITypesShared.h
+++ b/Source/User/iSCSI Framework/iSCSITypesShared.h
@@ -34,16 +34,16 @@ typedef int errno_t;
#endif
/*! Session identifier. */
-typedef UInt16 SID;
+typedef UInt16 SessionIdentifier;
/*! Connection identifier. */
-typedef UInt32 CID;
+typedef UInt32 ConnectionIdentifier;
/*! Target portal group tag. */
-typedef UInt16 TPGT;
+typedef UInt16 TargetPortalGroupTag;
/*! Target session identifier. */
-typedef UInt16 TSIH;
+typedef UInt16 TargetSessionIdentifier;
/*! Session qualifier value for an invalid session. */
static const UInt16 kiSCSIInvalidSessionId = 0xFFFF;
@@ -58,79 +58,79 @@ static const UInt16 kiSCSIMaxSessions = 16;
static const UInt32 kiSCSIMaxConnectionsPerSession = 2;
/*! An enumeration of configurable session parameters. */
-enum iSCSIKernelSessionOptTypes {
+enum iSCSIHBASessionParameters {
/*! Time to retain (UInt16). */
- kiSCSIKernelSODefaultTime2Retain,
+ kiSCSIHBASODefaultTime2Retain,
/*! Time to wait (UInt16). */
- kiSCSIKernelSODefaultTime2Wait,
+ kiSCSIHBASODefaultTime2Wait,
/*! Error recovery level (UInt8). */
- kiSCSIKernelSOErrorRecoveryLevel,
+ kiSCSIHBASOErrorRecoveryLevel,
/*! Max connections supported by target (UInt32). */
- kiSCSIKernelSOMaxConnections,
+ kiSCSIHBASOMaxConnections,
/*! Send data immediately (bool). */
- kiSCSIKernelSOImmediateData,
+ kiSCSIHBASOImmediateData,
/*! Expect an initial R2T from target (bool). */
- kiSCSIKernelSOInitialR2T,
+ kiSCSIHBASOInitialR2T,
/*! Data PDUs in order (bool). */
- kiSCSIKernelSODataPDUInOrder,
+ kiSCSIHBASODataPDUInOrder,
/*! Data sequence in order (bool). */
- kiSCSIKernelSODataSequenceInOrder,
+ kiSCSIHBASODataSequenceInOrder,
/*! Number of outstanding R2Ts allowed (UInt16). */
- kiSCSIKernelSOMaxOutstandingR2T,
+ kiSCSIHBASOMaxOutstandingR2T,
/*! Maximum data burst length in bytes (UInt32). */
- kiSCSIKernelSOMaxBurstLength,
+ kiSCSIHBASOMaxBurstLength,
/*! First data burst length in bytes (UInt32). */
- kiSCSIKernelSOFirstBurstLength,
+ kiSCSIHBASOFirstBurstLength,
/*! Target session identifying handle (TSIH). */
- kiSCSIKernelSOTargetSessionId,
+ kiSCSIHBASOTargetSessionId,
/*! Target portal group tag (TPGT). */
- kiSCSIKernelSOTargetPortalGroupTag,
+ kiSCSIHBASOTargetPortalGroupTag,
};
/*! An enumeration of configurable connection parameters. */
-enum iSCSIKernelConnectionOptTypes {
+enum iSCSIHBAConnectionParameters {
/*! Flag that indicates if this connection uses header digests (bool). */
- kiSCSIKernelCOUseHeaderDigest,
+ kiSCSIHBACOUseHeaderDigest,
/*! Flag that indicates if this connection uses data digests (bool). */
- kiSCSIKernelCOUseDataDigest,
+ kiSCSIHBACOUseDataDigest,
/*! Flag that indicates if this connection uses IF markers (bool). */
- kiSCSIKernelCOUseIFMarker,
+ kiSCSIHBACOUseIFMarker,
/*! Flag that indicates if this connection uses OF markers (bool). */
- kiSCSIKernelCOUseOFMarker,
+ kiSCSIHBACOUseOFMarker,
/*! Interval for OF marker (UInt16). */
- kiSCSIKernelCOOFMarkInt,
+ kiSCSIHBACOOFMarkInt,
/*! Interval for IF marker (UInt16). */
- kiSCSIKernelCOIFMarkInt,
+ kiSCSIHBACOIFMarkInt,
/*! Maximum data segment length allowed by the target (UInt32). */
- kiSCSIKernelCOMaxSendDataSegmentLength,
+ kiSCSIHBACOMaxSendDataSegmentLength,
/*! Maximum data segment length initiator can receive (UInt32). */
- kiSCSIKernelCOMaxRecvDataSegmentLength,
+ kiSCSIHBACOMaxRecvDataSegmentLength,
/*! Initial expStatSN. */
- kiSCSIKernelCOInitialExpStatSN
+ kiSCSIHBACOInitialExpStatSN
};
diff --git a/Source/User/iSCSI Framework/iSCSIUtils.c b/Source/User/iSCSI Framework/iSCSIUtils.c
index 5e2bc868..d548e6de 100644
--- a/Source/User/iSCSI Framework/iSCSIUtils.c
+++ b/Source/User/iSCSI Framework/iSCSIUtils.c
@@ -50,7 +50,11 @@ Boolean iSCSIUtilsValidateIQN(CFStringRef IQN)
regex_t preg;
regcomp(&preg,pattern,REG_EXTENDED | REG_NOSUB);
- if(regexec(&preg,CFStringGetCStringPtr(IQN,kCFStringEncodingASCII),0,NULL,0) == 0)
+ CFIndex IQNLength = CFStringGetMaximumSizeForEncoding(CFStringGetLength(IQN),kCFStringEncodingASCII) + sizeof('\0');
+ char IQNBuffer[IQNLength];
+ CFStringGetCString(IQN,IQNBuffer,IQNLength,kCFStringEncodingASCII);
+
+ if(regexec(&preg,IQNBuffer,0,NULL,0) == 0)
validName = true;
regfree(&preg);
@@ -101,9 +105,13 @@ CFArrayRef iSCSIUtilsCreateArrayByParsingPortalParts(CFStringRef portal)
regmatch_t matches[maxMatches[index]];
memset(matches,0,sizeof(regmatch_t)*maxMatches[index]);
-
+
+ CFIndex portalLength = CFStringGetMaximumSizeForEncoding(CFStringGetLength(portal),kCFStringEncodingASCII) + sizeof('\0');
+ char portalBuffer[portalLength];
+ CFStringGetCString(portal,portalBuffer,portalLength,kCFStringEncodingASCII);
+
// Match against pattern[index]
- if(regexec(&preg,CFStringGetCStringPtr(portal,kCFStringEncodingASCII),maxMatches[index],matches,0))
+ if(regexec(&preg,portalBuffer,maxMatches[index],matches,0))
{
regfree(&preg);
index++;
@@ -263,4 +271,106 @@ CFStringRef iSCSIUtilsGetStringForLogoutStatus(enum iSCSILogoutStatusCode status
return CFSTR("");
};
return CFSTR("");
+}
+
+/*! Creates address structures for an iSCSI target and the host (initiator)
+ * given an iSCSI portal reference. This function may be helpful when
+ * interfacing to low-level C networking APIs or other foundation libraries.
+ * @param portal an iSCSI portal.
+ * @param the target address structure (returned by this function).
+ * @param the host address structure (returned by this function). */
+errno_t iSCSIUtilsGetAddressForPortal(iSCSIPortalRef portal,
+ struct sockaddr_storage * remoteAddress,
+ struct sockaddr_storage * localAddress)
+{
+ if (!portal || !remoteAddress || !localAddress)
+ return EINVAL;
+
+ errno_t error = 0;
+
+ // Resolve the target node first and get a sockaddr info for it
+ const char * targetAddr, * targetPort;
+
+ targetAddr = CFStringGetCStringPtr(iSCSIPortalGetAddress(portal),kCFStringEncodingUTF8);
+ targetPort = CFStringGetCStringPtr(iSCSIPortalGetPort(portal),kCFStringEncodingUTF8);
+
+ struct addrinfo hints = {
+ .ai_family = AF_UNSPEC,
+ .ai_socktype = SOCK_STREAM,
+ .ai_protocol = IPPROTO_TCP,
+ };
+
+ struct addrinfo * aiTarget = NULL;
+ if((error = getaddrinfo(targetAddr,targetPort,&hints,&aiTarget)))
+ return error;
+
+ // Copy the sock_addr structure into a sockaddr_storage structure (this
+ // may be either an IPv4 or IPv6 sockaddr structure)
+ memcpy(remoteAddress,aiTarget->ai_addr,aiTarget->ai_addrlen);
+
+ freeaddrinfo(aiTarget);
+
+ // If the default interface is to be used, prepare a structure for it
+ CFStringRef hostIface = iSCSIPortalGetHostInterface(portal);
+
+ if(CFStringCompare(hostIface,kiSCSIDefaultHostInterface,0) == kCFCompareEqualTo)
+ {
+ localAddress->ss_family = remoteAddress->ss_family;
+
+ // For completeness, setup the sockaddr_in structure
+ if(localAddress->ss_family == AF_INET)
+ {
+ struct sockaddr_in * sa = (struct sockaddr_in *)localAddress;
+ sa->sin_port = 0;
+ sa->sin_addr.s_addr = htonl(INADDR_ANY);
+ sa->sin_len = sizeof(struct sockaddr_in);
+ }
+
+ // TODO: test IPv6 functionality
+ else if(localAddress->ss_family == AF_INET6)
+ {
+ struct sockaddr_in6 * sa = (struct sockaddr_in6 *)localAddress;
+ sa->sin6_addr = in6addr_any;
+ }
+
+ return error;
+ }
+
+ // Otherwise we have to search the list of all interfaces for the specified
+ // interface and copy the corresponding address structure
+ struct ifaddrs * interfaceList;
+
+ if((error = getifaddrs(&interfaceList)))
+ return error;
+
+ error = EAFNOSUPPORT;
+ struct ifaddrs * interface = interfaceList;
+
+ while(interface)
+ {
+ // Check if interface supports the targets address family (e.g., IPv4)
+ if(interface->ifa_addr->sa_family == remoteAddress->ss_family)
+ {
+ CFStringRef currIface = CFStringCreateWithCStringNoCopy(
+ kCFAllocatorDefault,
+ interface->ifa_name,
+ kCFStringEncodingUTF8,
+ kCFAllocatorNull);
+
+ Boolean ifaceNameMatch =
+ CFStringCompare(currIface,hostIface,kCFCompareCaseInsensitive) == kCFCompareEqualTo;
+ CFRelease(currIface);
+ // Check if interface names match...
+ if(ifaceNameMatch)
+ {
+ memcpy(localAddress,interface->ifa_addr,interface->ifa_addr->sa_len);
+ error = 0;
+ break;
+ }
+ }
+ interface = interface->ifa_next;
+ }
+
+ freeifaddrs(interfaceList);
+ return error;
}
\ No newline at end of file
diff --git a/Source/User/iSCSI Framework/iSCSIUtils.h b/Source/User/iSCSI Framework/iSCSIUtils.h
index 013a0c96..c66adcce 100644
--- a/Source/User/iSCSI Framework/iSCSIUtils.h
+++ b/Source/User/iSCSI Framework/iSCSIUtils.h
@@ -30,9 +30,12 @@
#define __ISCSI_UTILS_H__
#include
-#include
#include
+#include
+#include
+#include
+
#include "iSCSITypes.h"
/*! Verifies whether specified iSCSI qualified name (IQN) is valid per RFC3720.
@@ -73,4 +76,14 @@ CFStringRef iSCSIUtilsGetStringForLoginStatus(enum iSCSILoginStatusCode statusCo
* @return a string describing the login status (guaranteed to be a valid string). */
CFStringRef iSCSIUtilsGetStringForLogoutStatus(enum iSCSILogoutStatusCode statusCode);
+/*! Creates address structures for an iSCSI target and the host (initiator)
+ * given an iSCSI portal reference. This function may be helpful when
+ * interfacing to low-level C networking APIs or other foundation libraries.
+ * @param portal an iSCSI portal.
+ * @param the target address structure (returned by this function).
+ * @param the host address structure (returned by this function). */
+errno_t iSCSIUtilsGetAddressForPortal(iSCSIPortalRef portal,
+ struct sockaddr_storage * remoteAddress,
+ struct sockaddr_storage * localAddress);
+
#endif /* defined(__ISCSI_UTILS_H__) */
diff --git a/Source/User/iscsictl/iSCSICtl.m b/Source/User/iscsictl/iSCSICtl.m
index 23734940..58428e2d 100644
--- a/Source/User/iscsictl/iSCSICtl.m
+++ b/Source/User/iscsictl/iSCSICtl.m
@@ -113,12 +113,21 @@
/*! Auto login command-line option. */
CFStringRef kOptKeyAutoLogin = CFSTR("auto-login");
+/*! Persistent command-line option. */
+CFStringRef kOptKeyPersistent = CFSTR("persistent");
+
/*! Auto-login enable/disable command-line value. */
CFStringRef kOptValueAutoLoginEnable = CFSTR("enable");
/*! Auto login enable/disable command-line value. */
CFStringRef kOptValueAutoLoginDisable = CFSTR("disable");
+/*! Persistent enable/disable command-line value. */
+CFStringRef kOptValuePersistentEnable = CFSTR("enable");
+
+/*! Persistent enable/disable command-line value. */
+CFStringRef kOptValuePersistentDisable = CFSTR("disable");
+
/*! Digest command-line options. */
CFStringRef kOptKeyDigest = CFSTR("digest");
@@ -314,14 +323,8 @@ void iSCSICtlDisplayString(CFStringRef string)
CFIndex usedBufLen = 0;
UInt8 buffer[maxBufLen];
- CFStringGetBytes(string,
- CFRangeMake(0,CFStringGetLength(string)),
- kCFStringEncodingASCII,
- 0,
- false,
- buffer,
- maxBufLen,
- &usedBufLen);
+ CFStringGetBytes(string,CFRangeMake(0,CFStringGetLength(string)),kCFStringEncodingASCII,
+ 0,false,buffer,maxBufLen,&usedBufLen);
CFWriteStreamWrite(stdoutStream,buffer,usedBufLen);
}
@@ -375,7 +378,7 @@ CFStringRef iSCSICtlCreateSecretFromInput(CFIndex retries)
{
CFStringRef secret = NULL;
- const int MAX_SECRET_LENGTH = 128; //256
+ const int MAX_SECRET_LENGTH = 128;
char buffer[MAX_SECRET_LENGTH];
char verify[MAX_SECRET_LENGTH];
@@ -1001,11 +1004,25 @@ errno_t iSCSICtlModifyInitiator(AuthorizationRef authorization,CFDictionaryRef o
bool lockAndSync = false;
iSCSIPreferencesRef preferences = NULL;
errno_t error = 0;
+ bool validOption = false; // Was there at least one valid option?
- // Check for CHAP shared secret
+ // Get CHAP shared secret if present, otherwise get from input
CFStringRef secret = NULL;
- if(CFDictionaryContainsKey(options,kOptKeyCHAPSecret))
- secret = iSCSICtlCreateSecretFromInput(MAX_SECRET_RETRY_ATTEMPTS);
+ if (CFDictionaryGetValueIfPresent(options, kOptKeyCHAPSecret, (const void **)&secret))
+ {
+ if (CFStringCompare(secret, kOptValueEmpty, 0) == kCFCompareEqualTo)
+ {
+ if (CFDictionaryContainsKey(options,kOptKeyCHAPSecret))
+ {
+ secret = iSCSICtlCreateSecretFromInput(MAX_SECRET_RETRY_ATTEMPTS);
+ validOption = true;
+ }
+ }
+ else
+ {
+ validOption = true;
+ }
+ }
error = iSCSICtlConnectToDaemon(&handle);
@@ -1024,6 +1041,8 @@ errno_t iSCSICtlModifyInitiator(AuthorizationRef authorization,CFDictionaryRef o
}
else
error = EINVAL;
+
+ validOption = true;
}
if(!error) {
@@ -1040,6 +1059,12 @@ errno_t iSCSICtlModifyInitiator(AuthorizationRef authorization,CFDictionaryRef o
{
if(CFStringCompare(value,kOptValueEmpty,0) != kCFCompareEqualTo)
iSCSIPreferencesSetInitiatorCHAPName(preferences,value);
+ else {
+ iSCSICtlDisplayError(CFSTR("A CHAP name was not specified"));
+ error = EINVAL;
+ }
+
+ validOption = true;
}
// Check for authentication method
@@ -1049,31 +1074,55 @@ errno_t iSCSICtlModifyInitiator(AuthorizationRef authorization,CFDictionaryRef o
iSCSIPreferencesSetInitiatorAuthenticationMethod(preferences,kiSCSIAuthMethodNone);
else if(CFStringCompare(value,kOptValueAuthMethodCHAP,kCFCompareCaseInsensitive) == kCFCompareEqualTo)
iSCSIPreferencesSetInitiatorAuthenticationMethod(preferences,kiSCSIAuthMethodCHAP);
+ else if(CFStringCompare(value,kOptValueEmpty,0) == kCFCompareEqualTo) {
+ iSCSICtlDisplayError(CFSTR("Authentication method not specified"));
+ error = EINVAL;
+ }
else {
iSCSICtlDisplayError(CFSTR("The specified authentication method is invalid"));
error = EINVAL;
}
+
+ validOption = true;
}
// Check for initiator alias
if(!error && CFDictionaryGetValueIfPresent(options,kOptKeyNodeAlias,(const void**)&value))
- iSCSIPreferencesSetInitiatorAlias(preferences,value);
+ {
+ if(CFStringCompare(value,kOptValueEmpty,0) == kCFCompareEqualTo) {
+ iSCSICtlDisplayError(CFSTR("An alias was not specified"));
+ error = EINVAL;
+ }
+ else
+ iSCSIPreferencesSetInitiatorAlias(preferences,value);
+
+ validOption = true;
+ }
// Check for initiator IQN
if(!error && CFDictionaryGetValueIfPresent(options,kOptKeyNodeName,(const void **)&value))
{
- // Validate the chosen initiator IQN
- if(iSCSIUtilsValidateIQN(value))
+ if(CFStringCompare(value,kOptValueEmpty,0) == kCFCompareEqualTo) {
+ iSCSICtlDisplayError(CFSTR("An iSCSI Qualified Name (IQN) was not specified"));
+ error = EINVAL;
+ }
+ else if(iSCSIUtilsValidateIQN(value))
iSCSIPreferencesSetInitiatorIQN(preferences,value);
else {
iSCSICtlDisplayError(CFSTR("The specified name is not a valid IQN or EUI-64 identifier"));
error = EINVAL;
}
+
+ validOption = true;
}
if(!error) {
iSCSIDaemonPreferencesIOUnlockAndSync(handle,preferences);
- iSCSICtlDisplayString(CFSTR("Initiator settings have been updated\n"));
+
+ if(validOption)
+ iSCSICtlDisplayString(CFSTR("Initiator settings have been updated\n"));
+ else
+ iSCSICtlDisplayError(CFSTR("No valid options have been specified."));
}
else if(lockAndSync)
iSCSIDaemonPreferencesIOUnlockAndSync(handle,NULL);
@@ -1089,7 +1138,8 @@ errno_t iSCSICtlModifyTargetFromOptions(AuthorizationRef authorization,
iSCSIPreferencesRef preferences,
CFDictionaryRef options,
iSCSITargetRef target,
- iSCSIPortalRef portal)
+ iSCSIPortalRef portal,
+ bool validOption)
{
CFStringRef targetIQN = iSCSITargetGetIQN(target);
CFStringRef value = NULL;
@@ -1100,38 +1150,54 @@ errno_t iSCSICtlModifyTargetFromOptions(AuthorizationRef authorization,
{
if(CFStringCompare(value,kOptValueEmpty,0) != kCFCompareEqualTo)
iSCSIPreferencesSetTargetCHAPName(preferences,targetIQN,value);
+ else {
+ iSCSICtlDisplayError(CFSTR("A CHAP name was not specified"));
+ error = EINVAL;
+ }
+
+ validOption = true;
}
-
+
// Check for authentication method
- enum iSCSIAuthMethods authMethod = kiSCSIAuthMethodInvalid;
-
if(!error && CFDictionaryGetValueIfPresent(options,kOptKeyAutMethod,(const void**)&value))
{
- if(CFStringCompare(value,kOptValueAuthMethodNone,kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
- authMethod = kiSCSIAuthMethodNone;
- iSCSIPreferencesSetTargetAuthenticationMethod(preferences,targetIQN,authMethod);
- }
+ if(CFStringCompare(value,kOptValueAuthMethodNone,kCFCompareCaseInsensitive) == kCFCompareEqualTo)
+ iSCSIPreferencesSetTargetAuthenticationMethod(preferences,targetIQN,kiSCSIAuthMethodNone);
else if(CFStringCompare(value,kOptValueAuthMethodCHAP,kCFCompareCaseInsensitive) == kCFCompareEqualTo)
- {
- authMethod = kiSCSIAuthMethodCHAP;
- iSCSIPreferencesSetTargetAuthenticationMethod(preferences,targetIQN,authMethod);
+ iSCSIPreferencesSetTargetAuthenticationMethod(preferences,targetIQN,kiSCSIAuthMethodCHAP);
+ else if(CFStringCompare(value,kOptValueEmpty,0) == kCFCompareEqualTo) {
+ iSCSICtlDisplayError(CFSTR("Authentication method not specified"));
+ error = EINVAL;
}
else {
iSCSICtlDisplayError(CFSTR("The specified authentication method is invalid"));
error = EINVAL;
}
+
+ validOption = true;
}
- // Check for target IQN
+ // Check for target IQN changes (preferences will not allow a change to the IQN for
+ // static targets, we must therefore catch and display an appropriate error message)
if(!error && CFDictionaryGetValueIfPresent(options,kOptKeyNodeName,(const void **)&value))
{
- // Validate the chosen target IQN
- if(iSCSIUtilsValidateIQN(value))
+ if(iSCSIPreferencesGetTargetConfigType(preferences,targetIQN) != kiSCSITargetConfigStatic)
+ {
+ iSCSICtlDisplayError(CFSTR("The specified target is dynamically managed using discovery and cannot be renamed"));
+ error = EINVAL;
+ }
+ else if(CFStringCompare(value,kOptValueEmpty,0) == kCFCompareEqualTo) {
+ iSCSICtlDisplayError(CFSTR("An iSCSI Qualified Name (IQN) was not specified"));
+ error = EINVAL;
+ }
+ else if(iSCSIUtilsValidateIQN(value))
iSCSIPreferencesSetTargetIQN(preferences,targetIQN,value);
else {
iSCSICtlDisplayError(CFSTR("The specified name is not a valid IQN or EUI-64 identifier"));
error = EINVAL;
}
+
+ validOption = true;
}
// Check for auto-login
@@ -1149,6 +1215,27 @@ errno_t iSCSICtlModifyTargetFromOptions(AuthorizationRef authorization,
CFRelease(errorString);
error = EINVAL;
}
+
+ validOption = true;
+ }
+
+ // Check for persistent
+ if(!error && CFDictionaryGetValueIfPresent(options,kOptKeyPersistent,(const void **)&value))
+ {
+
+ if(CFStringCompare(value,kOptValuePersistentEnable,kCFCompareCaseInsensitive) == kCFCompareEqualTo)
+ iSCSIPreferencesSetPersistenceForTarget(preferences,targetIQN,true);
+ else if(CFStringCompare(value,kOptValuePersistentDisable,kCFCompareCaseInsensitive) == kCFCompareEqualTo)
+ iSCSIPreferencesSetPersistenceForTarget(preferences,targetIQN,false);
+ else {
+ CFStringRef errorString = CFStringCreateWithFormat(
+ kCFAllocatorDefault,0,CFSTR("Invalid argument for %@"),kOptKeyPersistent);
+ iSCSICtlDisplayError(errorString);
+ CFRelease(errorString);
+ error = EINVAL;
+ }
+
+ validOption = true;
}
// Check for maximum connections
@@ -1161,10 +1248,12 @@ errno_t iSCSICtlModifyTargetFromOptions(AuthorizationRef authorization,
}
else if(maxConnections > kRFC3720_MaxConnections_Max) {
iSCSICtlDisplayError(CFSTR("Specified maximum number of connections is not sufficient"));
- error = EINVAL;
+ error = EINVAL;
}
else
iSCSIPreferencesSetMaxConnectionsForTarget(preferences,targetIQN,maxConnections);
+
+ validOption = true;
}
// Check for error recovery level
@@ -1179,6 +1268,8 @@ errno_t iSCSICtlModifyTargetFromOptions(AuthorizationRef authorization,
else {
iSCSIPreferencesSetErrorRecoveryLevelForTarget(preferences,targetIQN,level);
}
+
+ validOption = true;
}
// Check for header digest
@@ -1188,10 +1279,16 @@ errno_t iSCSICtlModifyTargetFromOptions(AuthorizationRef authorization,
iSCSIPreferencesSetHeaderDigestForTarget(preferences,targetIQN,kiSCSIDigestNone);
else if(CFStringCompare(value,kOptValueDigestCRC32C,kCFCompareCaseInsensitive) == kCFCompareEqualTo)
iSCSIPreferencesSetHeaderDigestForTarget(preferences,targetIQN,kiSCSIDigestCRC32C);
+ if(CFStringCompare(value,kOptValueEmpty,0) == kCFCompareEqualTo) {
+ iSCSICtlDisplayError(CFSTR("A digest type was not specified"));
+ error = EINVAL;
+ }
else {
iSCSICtlDisplayError(CFSTR("The specified digest type is invalid"));
error = EINVAL;
}
+
+ validOption = true;
}
// Check for data digest
@@ -1201,12 +1298,23 @@ errno_t iSCSICtlModifyTargetFromOptions(AuthorizationRef authorization,
iSCSIPreferencesSetDataDigestForTarget(preferences,targetIQN,kiSCSIDigestNone);
else if(CFStringCompare(value,kOptValueDigestCRC32C,kCFCompareCaseInsensitive) == kCFCompareEqualTo)
iSCSIPreferencesSetDataDigestForTarget(preferences,targetIQN,kiSCSIDigestCRC32C);
+ if(CFStringCompare(value,kOptValueEmpty,0) == kCFCompareEqualTo) {
+ iSCSICtlDisplayError(CFSTR("A digest type was not specified"));
+ error = EINVAL;
+ }
else {
iSCSICtlDisplayError(CFSTR("The specified digest type is invalid"));
error = EINVAL;
}
+
+ validOption = true;
}
-
+
+ if(!error && !validOption) {
+ iSCSICtlDisplayError(CFSTR("No valid options have been specified."));
+ error = EINVAL;
+ }
+
return error;
}
@@ -1227,6 +1335,7 @@ errno_t iSCSICtlModifyTarget(AuthorizationRef authorization,CFDictionaryRef opti
iSCSIPreferencesRef preferences = NULL;
CFStringRef targetIQN = NULL;
errno_t error = 0;
+ bool validOption = false; // Was there at least one valid option?
if(!error && !(target = iSCSICtlCreateTargetFromOptions(options)))
error = EINVAL;
@@ -1237,10 +1346,23 @@ errno_t iSCSICtlModifyTarget(AuthorizationRef authorization,CFDictionaryRef opti
if(!(portal = iSCSICtlCreatePortalFromOptions(options)))
error = EINVAL;
- // Check for CHAP shared secret
+ // Get CHAP shared secret if present, otherwise get from input
CFStringRef secret = NULL;
- if(CFDictionaryContainsKey(options,kOptKeyCHAPSecret))
- secret = iSCSICtlCreateSecretFromInput(MAX_SECRET_RETRY_ATTEMPTS);
+ if (CFDictionaryGetValueIfPresent(options, kOptKeyCHAPSecret, (const void **)&secret))
+ {
+ if (CFStringCompare(secret, kOptValueEmpty, 0) == kCFCompareEqualTo)
+ {
+ if (CFDictionaryContainsKey(options,kOptKeyCHAPSecret))
+ {
+ secret = iSCSICtlCreateSecretFromInput(MAX_SECRET_RETRY_ATTEMPTS);
+ validOption = true;
+ }
+ }
+ else
+ {
+ validOption = true;
+ }
+ }
if(!error)
error = iSCSICtlConnectToDaemon(&handle);
@@ -1248,16 +1370,18 @@ errno_t iSCSICtlModifyTarget(AuthorizationRef authorization,CFDictionaryRef opti
if(!error)
preferences = iSCSIPreferencesCreateFromAppValues();
- if(!error && CFDictionaryContainsKey(options,kOptKeyCHAPSecret)) {
- if(secret != NULL) {
+ if(CFDictionaryContainsKey(options,kOptKeyCHAPSecret)) {
+ if(!error && secret != NULL) {
if(iSCSIDaemonSetSharedSecret(handle,authorization,targetIQN,secret)) {
iSCSICtlDisplayError(kPermissionsErrorString);
error = EAUTH;
}
- CFRelease(secret);
}
else
error = EINVAL;
+
+ if(secret)
+ CFRelease(secret);
}
if(!error) {
@@ -1299,8 +1423,10 @@ errno_t iSCSICtlModifyTarget(AuthorizationRef authorization,CFDictionaryRef opti
if(iSCSIDaemonIsTargetActive(handle,target))
iSCSICtlDisplayString(CFSTR("The specified target has an active session and cannot be modified\n"));
else {
- iSCSICtlModifyTargetFromOptions(authorization,preferences,options,target,portal);
- iSCSICtlDisplayString(CFSTR("Target settings have been updated\n"));
+ error = iSCSICtlModifyTargetFromOptions(authorization,preferences,options,target,portal,validOption);
+
+ if(!error)
+ iSCSICtlDisplayString(CFSTR("Target settings have been updated\n"));
}
}
}
@@ -1323,8 +1449,7 @@ errno_t iSCSICtlModifyTarget(AuthorizationRef authorization,CFDictionaryRef opti
}
/*! Helper function. Displays information about a target/session. */
-void displayTargetInfo(iSCSITargetRef target,
- CFDictionaryRef properties)
+void displayTargetInfo(iSCSITargetRef target,CFDictionaryRef properties)
{
CFStringRef targetState = NULL;
CFStringRef targetConfig = NULL;
@@ -1360,7 +1485,7 @@ void displayTargetInfo(iSCSITargetRef target,
CFNumberRef targetSessionId = CFDictionaryGetValue(properties,kRFC3720_Key_TargetSessionId);
CFNumberRef sessionId = CFDictionaryGetValue(properties,kRFC3720_Key_SessionId);
- TSIH tsih = 0;
+ TargetSessionIdentifier tsih = 0;
CFNumberGetValue(targetSessionId,kCFNumberSInt16Type,&tsih);
status = CFStringCreateWithFormat(kCFAllocatorDefault,0,
@@ -1521,15 +1646,34 @@ errno_t iSCSICtlListTarget(CFDictionaryRef options)
displayTargetInfo(target,properties);
+ // Retrieve last known target alias (if available) and display it
+ CFStringRef targetAlias = iSCSIPreferencesGetTargetAlias(preferences,targetIQN);
+ if(!targetAlias)
+ targetAlias = CFSTR("");
+
+ CFStringRef aliasString = CFStringCreateWithFormat(kCFAllocatorDefault,0,CFSTR("\tnode-alias: %@\n"),targetAlias);
+ iSCSICtlDisplayString(aliasString);
+ CFRelease(aliasString);
+
// Get information about automatic login
CFStringRef autoLogin = CFSTR("disabled");
if(iSCSIPreferencesGetAutoLoginForTarget(preferences,targetIQN))
autoLogin = CFSTR("enabled");
- CFStringRef targetConfig = CFStringCreateWithFormat(kCFAllocatorDefault,0,CFSTR("\t%@: %@\n"),kOptKeyAutoLogin,autoLogin);
- iSCSICtlDisplayString(targetConfig);
- CFRelease(targetConfig);
+ CFStringRef autoLoginString = CFStringCreateWithFormat(kCFAllocatorDefault,0,CFSTR("\t%@: %@\n"),kOptKeyAutoLogin,autoLogin);
+ iSCSICtlDisplayString(autoLoginString);
+ CFRelease(autoLoginString);
+
+ // Get information about persistence
+ CFStringRef persistent = CFSTR("no");
+
+ if(iSCSIPreferencesGetPersistenceForTarget(preferences,targetIQN))
+ persistent = CFSTR("yes");
+
+ CFStringRef persistentString = CFStringCreateWithFormat(kCFAllocatorDefault,0,CFSTR("\t%@: %@\n"),kOptKeyPersistent,persistent);
+ iSCSICtlDisplayString(persistentString);
+ CFRelease(persistentString);
if(iSCSIPreferencesGetTargetConfigType(preferences,targetIQN) == kiSCSITargetConfigDynamicSendTargets)
{
@@ -1843,6 +1987,7 @@ errno_t iSCSICtlModifyDiscovery(AuthorizationRef authorization,CFDictionaryRef o
iSCSIPreferencesRef preferences = NULL;
bool lockAndSync = false;
errno_t error = 0;
+ bool validOption = false; // Was there at least one valid option?
if(!error)
error = iSCSICtlConnectToDaemon(&handle);
@@ -1873,6 +2018,8 @@ errno_t iSCSICtlModifyDiscovery(AuthorizationRef authorization,CFDictionaryRef o
CFRelease(errorString);
error = EINVAL;
}
+
+ validOption = true;
}
// Check if user modified the discovery interval
if(!error && CFDictionaryGetValueIfPresent(optDictionary,kOptKeyDiscoveryInterval,(const void **)&value))
@@ -1888,11 +2035,17 @@ errno_t iSCSICtlModifyDiscovery(AuthorizationRef authorization,CFDictionaryRef o
}
else
iSCSIPreferencesSetSendTargetsDiscoveryInterval(preferences,interval);
+
+ validOption = true;
}
if(!error) {
iSCSIDaemonPreferencesIOUnlockAndSync(handle,preferences);
- iSCSICtlDisplayString(CFSTR("Discovery settings have been updated\n"));
+
+ if(validOption)
+ iSCSICtlDisplayString(CFSTR("Discovery settings have been updated\n"));
+ else
+ iSCSICtlDisplayError(CFSTR("No valid options have been specified."));
}
else if(lockAndSync)
iSCSIDaemonPreferencesIOUnlockAndSync(handle,NULL);
@@ -2277,4 +2430,4 @@ int main(int argc, char * argv[])
AuthorizationFree(authorization,kAuthorizationFlagDefaults);
}
return error;
-}
\ No newline at end of file
+}
diff --git a/Source/User/iscsictl/iscsictl.8 b/Source/User/iscsictl/iscsictl.8
index 86661466..08ec28bc 100644
--- a/Source/User/iscsictl/iscsictl.8
+++ b/Source/User/iscsictl/iscsictl.8
@@ -1,6 +1,6 @@
.\" (c) 2013-2015 Nareg Sinenian. All rights reserved.
.\" This file is the UNIX man page for the iscsictl command-line utility."
-.Dd November 1, 2015
+.Dd July 23, 2016
.Dt ISCSICTL 8
.Os "Mac OS X"
.Sh NAME
@@ -113,6 +113,10 @@ The following options can be used to modify target-config:
Specifies whether the iSCSI daemon should login to the target upon startup. Possible values for
.Ar enable
are enable or disable.
+.It Fl persistent Ar enable
+Specifies whether the iSCSI daemon should reconnect to the target in the event of a network interruption or connection timeout. Possible values for
+.Ar enable
+are enable or disable.
.It Fl MaxConnections Ar max_connections
The maximum number of simultaneous connections allowed for this target.
.It Fl ErrorRecoveryLevel Ar error_level
diff --git a/Source/User/iscsid/iSCSIAuth.c b/Source/User/iscsid/iSCSIAuth.c
index ff06de77..cd492acc 100644
--- a/Source/User/iscsid/iSCSIAuth.c
+++ b/Source/User/iscsid/iSCSIAuth.c
@@ -29,7 +29,7 @@
#include "iSCSIAuth.h"
#include "iSCSIPDUUser.h"
#include "iSCSISession.h"
-#include "iSCSIKernelInterface.h"
+#include "iSCSIHBAInterface.h"
#include "iSCSIQueryTarget.h"
@@ -42,29 +42,30 @@ extern CFStringRef kiSCSIInitiatorAlias;
/*! Helper function. Create a byte array (CFDataRef object) that holds the
* value represented by the hexidecimal string. Handles strings with or
* without a 0x prefix. */
-CFDataRef CFDataCreateWithHexString(CFStringRef hexStr)
+CFDataRef CFDataCreateWithHexString(CFStringRef hexString)
{
- if(!hexStr)
+ if(!hexString)
return NULL;
// Get length and pointer to hex string
- CFIndex hexStrLen = CFStringGetLength(hexStr);
- const char * hexStrPtr = CFStringGetCStringPtr(hexStr,kCFStringEncodingASCII);
+ CFIndex hexStringLength = CFStringGetMaximumSizeForEncoding(CFStringGetLength(hexString),kCFStringEncodingASCII) + sizeof('\0');
+ char hexStringBuffer[hexStringLength];
+ CFStringGetCString(hexString,hexStringBuffer,hexStringLength,kCFStringEncodingASCII);
// Byte length stars off as the number of hex characters, and is adjusted
// to reflect the number of bytes depending on the format of the hex string
- // (e.g., if the hex string
- CFIndex byteLength = hexStrLen;
+ // (does not include null terminator)
+ CFIndex byteLength = CFStringGetLength(hexString);
// The index we'll start processing the hex string
unsigned int startIndex = 0;
- // Check for the "0x" prefix, ignore it if present...
- if(hexStrLen >= 2 && hexStrPtr[0] == '0' && hexStrPtr[1] == 'x') {
+ // Check for the "0x" or "x" prefix, ignore it if present...
+ if(hexStringLength >= 2 && hexStringBuffer[0] == '0' && hexStringBuffer[1] == 'x') {
startIndex+=2;
byteLength-=2;
}
- else if(hexStrLen >= 1 && hexStrPtr[0] == 'x') {
+ else if(hexStringLength >= 1 && hexStringBuffer[0] == 'x') {
startIndex++;
byteLength--;
}
@@ -82,21 +83,21 @@ CFDataRef CFDataCreateWithHexString(CFStringRef hexStr)
int buffer = 0;
// If an odd number of hex characters, process first one differently...
- if(hexStrLen % 2 != 0) {
+ if(hexStringLength % 2 != 0) {
// Pick off the first character and convert differently
- sscanf(&hexStrPtr[startIndex],"%01x",&buffer);
+ sscanf(&hexStringBuffer[startIndex],"%01x",&buffer);
bytes[byteIdx] = buffer;
startIndex++;
byteIdx++;
}
// Process remaining characters in pairs (2 hex characters = 1 byte)
- for(unsigned int idx = startIndex; idx < hexStrLen; idx+=2) {
- sscanf(&hexStrPtr[idx],"%02x",&buffer);
+ for(unsigned int idx = startIndex; idx < hexStringLength; idx+=2) {
+ sscanf(&hexStringBuffer[idx],"%02x",&buffer);
bytes[byteIdx] = buffer;
byteIdx++;
}
-
+
return data;
}
@@ -107,9 +108,9 @@ CFDataRef CFDataCreateWithHexString(CFStringRef hexStr)
CFStringRef CreateHexStringWithBytes(const UInt8 * bytes, size_t length)
{
// Pad string by 3 bytes to leave room for "0x" prefix and null terminator
- const long hexStrLen = length * 2 + 3;
+ const long hexStrLength = length * 2 + 3;
- char hexStr[hexStrLen];
+ char hexStr[hexStrLength];
hexStr[0] = '0';
hexStr[1] = 'x';
@@ -118,7 +119,7 @@ CFStringRef CreateHexStringWithBytes(const UInt8 * bytes, size_t length)
sprintf(&hexStr[i*2+2], "%02x", bytes[i]);
// Null terminate
- hexStr[hexStrLen-1] = 0;
+ hexStr[hexStrLength-1] = 0;
// This copies our buffer into a CFString object
return CFStringCreateWithCString(kCFAllocatorDefault,hexStr,kCFStringEncodingASCII);
@@ -143,8 +144,11 @@ CFStringRef iSCSIAuthNegotiateCHAPCreateResponse(CFStringRef identifier,
CC_MD5_Update(&md5,&id,(CC_LONG)sizeof(id));
// Hash in the secret
- const UInt8 * byteSecret = (const UInt8*)CFStringGetCStringPtr(secret,kCFStringEncodingASCII);
- CC_MD5_Update(&md5,byteSecret,(CC_LONG)CFStringGetLength(secret));
+ CFIndex secretLength = CFStringGetMaximumSizeForEncoding(CFStringGetLength(secret),kCFStringEncodingASCII) + sizeof('\0');
+ char secretBuffer[secretLength];
+ CFStringGetCString(secret,secretBuffer,secretLength,kCFStringEncodingASCII);
+
+ CC_MD5_Update(&md5,secretBuffer,(CC_LONG)CFStringGetLength(secret));
// Hash in the challenge
CFDataRef challengeData = CFDataCreateWithHexString(challenge);
@@ -155,7 +159,7 @@ CFStringRef iSCSIAuthNegotiateCHAPCreateResponse(CFStringRef identifier,
CC_MD5_Final(md5Hash,&md5);
CFRelease(challengeData);
-
+
return CreateHexStringWithBytes(md5Hash,CC_MD5_DIGEST_LENGTH);
}
@@ -188,18 +192,15 @@ CFStringRef iSCSIAuthNegotiateCHAPCreateId()
/*! Helper function for iSCSIConnectionSecurityNegotiate. Once it has been
* determined that a CHAP session is to be used, this function will perform
* the CHAP authentication. */
-errno_t iSCSIAuthNegotiateCHAP(iSCSIMutableTargetRef target,
+errno_t iSCSIAuthNegotiateCHAP(iSCSISessionManagerRef managerRef,
+ iSCSIMutableTargetRef target,
iSCSIAuthRef initiatorAuth,
iSCSIAuthRef targetAuth,
- SID sessionId,
- CID connectionId,
- TSIH targetSessionId,
+ SessionIdentifier sessionId,
+ ConnectionIdentifier connectionId,
+ TargetSessionIdentifier targetSessionId,
enum iSCSILoginStatusCode * statusCode)
{
- if(!target || !initiatorAuth || !targetAuth ||
- sessionId == kiSCSIInvalidConnectionId || connectionId == kiSCSIInvalidConnectionId)
- return EINVAL;
-
// Setup dictionary CHAP authentication information
CFMutableDictionaryRef authCmd = CFDictionaryCreateMutable(
kCFAllocatorDefault,kiSCSISessionMaxTextKeyValuePairs,
@@ -223,6 +224,7 @@ errno_t iSCSIAuthNegotiateCHAP(iSCSIMutableTargetRef target,
CFDictionaryAddValue(authCmd,kRFC3720_Key_AuthCHAPDigest,kRFC3720_Value_AuthCHAPDigestMD5);
struct iSCSILoginQueryContext context;
+ context.interface = iSCSISessionManagerGetHBAInterface(managerRef);
context.sessionId = sessionId;
context.connectionId = connectionId;
context.targetSessionId = targetSessionId;
@@ -387,17 +389,16 @@ void iSCSIAuthNegotiateBuildDict(iSCSITargetRef target,
* begin authentication between the initiator and a selected target. If the
* target name is set to blank (e.g., by a call to iSCSITargetSetIQN()) or
* never set at all, a discovery session is assumed for authentication. */
-errno_t iSCSIAuthNegotiate(iSCSIMutableTargetRef target,
+errno_t iSCSIAuthNegotiate(iSCSISessionManagerRef managerRef,
+ iSCSIMutableTargetRef target,
iSCSIAuthRef initiatorAuth,
iSCSIAuthRef targetAuth,
- SID sessionId,
- CID connectionId,
+ SessionIdentifier sessionId,
+ ConnectionIdentifier connectionId,
enum iSCSILoginStatusCode * statusCode)
{
- if(!target || !initiatorAuth || !targetAuth ||
- sessionId == kiSCSIInvalidConnectionId || connectionId == kiSCSIInvalidConnectionId)
- return EINVAL;
-
+ iSCSIHBAInterfaceRef hbaInterface = iSCSISessionManagerGetHBAInterface(managerRef);
+
// Setup dictionary with target and initiator info for authentication
CFMutableDictionaryRef authCmd = CFDictionaryCreateMutable(
kCFAllocatorDefault,kiSCSISessionMaxTextKeyValuePairs,
@@ -411,14 +412,16 @@ errno_t iSCSIAuthNegotiate(iSCSIMutableTargetRef target,
iSCSIAuthNegotiateBuildDict(target,initiatorAuth,targetAuth,authCmd);
struct iSCSILoginQueryContext context;
+ context.interface = hbaInterface;
context.sessionId = sessionId;
context.connectionId = connectionId;
context.currentStage = kiSCSIPDUSecurityNegotiation;
context.nextStage = kiSCSIPDUSecurityNegotiation;
// Retrieve the TSIH from the kernel
- TSIH targetSessionId = 0;
- iSCSIKernelGetSessionOpt(sessionId,kiSCSIKernelSOTargetSessionId,&targetSessionId,sizeof(TSIH));
+ TargetSessionIdentifier targetSessionId = 0;
+ iSCSIHBAInterfaceGetSessionParameter(hbaInterface,sessionId,kiSCSIHBASOTargetSessionId,
+ &targetSessionId,sizeof(TargetSessionIdentifier));
context.targetSessionId = targetSessionId;
enum iSCSIPDURejectCode rejectCode;
@@ -440,11 +443,11 @@ errno_t iSCSIAuthNegotiate(iSCSIMutableTargetRef target,
// This was the first query of the connection; record the status
// sequence number provided by the target
UInt32 expStatSN = context.statSN + 1;
- iSCSIKernelSetConnectionOpt(sessionId,connectionId,kiSCSIKernelCOInitialExpStatSN,
- &expStatSN,sizeof(expStatSN));
+ iSCSIHBAInterfaceSetConnectionParameter(hbaInterface,sessionId,connectionId,kiSCSIHBACOInitialExpStatSN,
+ &expStatSN,sizeof(expStatSN));
- // If this is not a discovery session, we expect to receive a target
- // portal group tag (TPGT) and validate it
+ // If this is not a discovery session (the target is not specified for discovery),
+ // we expect to receive a target portal group tag (TPGT) and validate it
if(CFStringCompare(iSCSITargetGetIQN(target),kiSCSIUnspecifiedTargetIQN,0) != kCFCompareEqualTo)
{
// Ensure that the target returned a portal group tag (TPGT)...
@@ -459,16 +462,16 @@ errno_t iSCSIAuthNegotiate(iSCSIMutableTargetRef target,
// If this is leading login (TSIH = 0 for leading login), store TPGT,
// else compare it to the TPGT that we have stored for this session...
if(targetSessionId == 0) {
- TPGT targetPortalGroupTag = CFStringGetIntValue(targetPortalGroupRsp);
+ TargetPortalGroupTag targetPortalGroupTag = CFStringGetIntValue(targetPortalGroupRsp);
- iSCSIKernelSetSessionOpt(sessionId,kiSCSIKernelSOTargetPortalGroupTag,
- &targetPortalGroupTag,sizeof(TPGT));
+ iSCSIHBAInterfaceSetSessionParameter(hbaInterface,sessionId,kiSCSIHBASOTargetPortalGroupTag,
+ &targetPortalGroupTag,sizeof(TargetPortalGroupTag));
}
else {
// Retrieve from kernel
- TPGT targetPortalGroupTag = 0;
- iSCSIKernelGetSessionOpt(sessionId,kiSCSIKernelSOTargetPortalGroupTag,
- &targetPortalGroupTag,sizeof(TPGT));
+ TargetPortalGroupTag targetPortalGroupTag = 0;
+ iSCSIHBAInterfaceGetSessionParameter(hbaInterface,sessionId,kiSCSIHBASOTargetPortalGroupTag,
+ &targetPortalGroupTag,sizeof(TargetPortalGroupTag));
// Validate existing group against TPGT for this connection
if(targetPortalGroupTag != CFStringGetIntValue(targetPortalGroupRsp))
@@ -476,12 +479,14 @@ errno_t iSCSIAuthNegotiate(iSCSIMutableTargetRef target,
}
}
- // Determine if target supports desired authentication method
+ // Determine if target supports desired authentication method. Desired method could
+ // be a comma-separated list in authCmd, so we check the target's desired method
+ // as specified in the response (authRsp) against our list
CFRange result = CFStringFind(CFDictionaryGetValue(authCmd,kRFC3720_Key_AuthMethod),
CFDictionaryGetValue(authRsp,kRFC3720_Key_AuthMethod),
kCFCompareCaseInsensitive);
- // If we wanted to use a particular method and the target doesn't support it
+ // Check if target supported our desired authentication method
if(result.location == kCFNotFound) {
error = EAUTH;
goto ERROR_AUTHENTICATION;
@@ -513,7 +518,8 @@ errno_t iSCSIAuthNegotiate(iSCSIMutableTargetRef target,
}
if(authMethod == kiSCSIAuthMethodCHAP) {
- error = iSCSIAuthNegotiateCHAP(target,
+ error = iSCSIAuthNegotiateCHAP(managerRef,
+ target,
initiatorAuth,
targetAuth,
sessionId,
@@ -552,9 +558,10 @@ errno_t iSCSIAuthNegotiate(iSCSIMutableTargetRef target,
/*! Helper function. Called by session or connection creation functions to
* determine available authentication options for a given target. */
-errno_t iSCSIAuthInterrogate(iSCSITargetRef target,
- SID sessionId,
- CID connectionId,
+errno_t iSCSIAuthInterrogate(iSCSISessionManagerRef managerRef,
+ iSCSITargetRef target,
+ SessionIdentifier sessionId,
+ ConnectionIdentifier connectionId,
enum iSCSIAuthMethods * authMethod,
enum iSCSILoginStatusCode * statusCode)
{
@@ -581,6 +588,7 @@ errno_t iSCSIAuthInterrogate(iSCSITargetRef target,
&kCFTypeDictionaryKeyCallBacks,&kCFTypeDictionaryValueCallBacks);
struct iSCSILoginQueryContext context;
+ context.interface = iSCSISessionManagerGetHBAInterface(managerRef);
context.sessionId = sessionId;
context.connectionId = connectionId;
context.currentStage = kiSCSIPDUSecurityNegotiation;
diff --git a/Source/User/iscsid/iSCSIAuth.h b/Source/User/iscsid/iSCSIAuth.h
index 58257e4f..49c56dc6 100644
--- a/Source/User/iscsid/iSCSIAuth.h
+++ b/Source/User/iscsid/iSCSIAuth.h
@@ -32,23 +32,26 @@
#include
#include
+#include "iSCSISessionManager.h"
#include "iSCSITypes.h"
-#include "iSCSIKernelInterfaceShared.h"
+#include "iSCSIHBATypes.h"
/*! Authentication function defined in the authentication module
* (in the file iSCSIAuth.h). */
-errno_t iSCSIAuthNegotiate(iSCSIMutableTargetRef target,
+errno_t iSCSIAuthNegotiate(iSCSISessionManagerRef manager,
+ iSCSIMutableTargetRef target,
iSCSIAuthRef initiatorAuth,
iSCSIAuthRef targetAuth,
- SID sessionId,
- CID connectionId,
+ SessionIdentifier sessionId,
+ ConnectionIdentifier connectionId,
enum iSCSILoginStatusCode * statusCode);
/*! Authentication function defined in the authentication module
* (in the file iSCSIAuth.h). */
-errno_t iSCSIAuthInterrogate(iSCSITargetRef target,
- SID sessionId,
- CID connectionId,
+errno_t iSCSIAuthInterrogate(iSCSISessionManagerRef manager,
+ iSCSITargetRef target,
+ SessionIdentifier sessionId,
+ ConnectionIdentifier connectionId,
enum iSCSIAuthMethods * authMethod,
enum iSCSILoginStatusCode * statusCode);
diff --git a/Source/User/iscsid/iSCSIDaemon.c b/Source/User/iscsid/iSCSIDaemon.c
index 6e2351f6..678de72e 100644
--- a/Source/User/iscsid/iSCSIDaemon.c
+++ b/Source/User/iscsid/iSCSIDaemon.c
@@ -48,6 +48,7 @@
// Foundation includes
#include
#include
+#include
// Mach kernel includes
#include
@@ -60,7 +61,6 @@
// iSCSI includes
#include "iSCSISession.h"
-#include "iSCSIDiscovery.h"
#include "iSCSIDaemonInterfaceShared.h"
#include "iSCSIPreferences.h"
#include "iSCSIDA.h"
@@ -94,6 +94,8 @@ iSCSIPreferencesRef preferences = NULL;
/*! Incoming request information struct. */
struct iSCSIDIncomingRequestInfo * reqInfo = NULL;
+/*! Used to manage iSCSI sessions. */
+iSCSISessionManagerRef sessionManager = NULL;
struct iSCSIDIncomingRequestInfo {
CFSocketRef socket;
@@ -101,6 +103,10 @@ struct iSCSIDIncomingRequestInfo {
int fd;
};
+struct iSCSIDQueueLoginForTargetPortal {
+ iSCSITargetRef target;
+ iSCSIPortalRef portal;
+};
const iSCSIDMsgLoginRsp iSCSIDMsgLoginRspInit = {
.funcCode = kiSCSIDLogin,
@@ -259,7 +265,6 @@ iSCSIAuthRef iSCSIDCreateAuthenticationForTarget(CFStringRef targetIQN)
CFRelease(name);
if(sharedSecret)
CFRelease(sharedSecret);
-
}
else
auth = iSCSIAuthCreateNone();
@@ -302,7 +307,7 @@ iSCSIAuthRef iSCSIDCreateAuthenticationForInitiator()
return auth;
}
-errno_t iSCSIDLoginCommon(SID sessionId,
+errno_t iSCSIDLoginCommon(SessionIdentifier sessionId,
iSCSIMutableTargetRef target,
iSCSIPortalRef portal,
enum iSCSILoginStatusCode * statusCode)
@@ -312,7 +317,7 @@ errno_t iSCSIDLoginCommon(SID sessionId,
iSCSIConnectionConfigRef connCfg = NULL;
iSCSIAuthRef initiatorAuth = NULL, targetAuth = NULL;
- CID connectionId = kiSCSIInvalidConnectionId;
+ ConnectionIdentifier connectionId = kiSCSIInvalidConnectionId;
*statusCode = kiSCSILoginInvalidStatusCode;
@@ -336,9 +341,9 @@ errno_t iSCSIDLoginCommon(SID sessionId,
// Do either session or connection login
if(sessionId == kiSCSIInvalidSessionId)
- error = iSCSILoginSession(target,portal,initiatorAuth,targetAuth,sessCfg,connCfg,&sessionId,&connectionId,statusCode);
+ error = iSCSISessionLogin(sessionManager,target,portal,initiatorAuth,targetAuth,sessCfg,connCfg,&sessionId,&connectionId,statusCode);
else
- error = iSCSILoginConnection(sessionId,portal,initiatorAuth,targetAuth,connCfg,&connectionId,statusCode);
+ error = iSCSISessionAddConnection(sessionManager,sessionId,portal,initiatorAuth,targetAuth,connCfg,&connectionId,statusCode);
// Log error message
if(error) {
@@ -350,7 +355,12 @@ errno_t iSCSIDLoginCommon(SID sessionId,
iSCSIPortalGetPort(portal),
strerror(error));
- asl_log(NULL,NULL,ASL_LEVEL_ERR,"%s",CFStringGetCStringPtr(errorString,kCFStringEncodingASCII));
+ CFIndex errorStringLength = CFStringGetMaximumSizeForEncoding(CFStringGetLength(errorString),kCFStringEncodingASCII) + sizeof('\0');
+ char errorStringBuffer[errorStringLength];
+ CFStringGetCString(errorString,errorStringBuffer,errorStringLength,kCFStringEncodingASCII);
+
+ asl_log(NULL, NULL, ASL_LEVEL_ERR, "%s", errorStringBuffer);
+
CFRelease(errorString);
}
// Update target alias in preferences (if one was furnished)
@@ -389,7 +399,7 @@ errno_t iSCSIDLoginAllPortals(iSCSIMutableTargetRef target,
*statusCode = kiSCSILoginInvalidStatusCode;
CFStringRef targetIQN = iSCSITargetGetIQN(target);
- SID sessionId = iSCSIGetSessionIdForTarget(targetIQN);
+ SessionIdentifier sessionId = iSCSISessionGetSessionIdForTarget(sessionManager,targetIQN);
// Set initial values for maxConnections and activeConnections
if(sessionId == kiSCSIInvalidSessionId)
@@ -398,7 +408,7 @@ errno_t iSCSIDLoginAllPortals(iSCSIMutableTargetRef target,
else {
// If session exists, get the max connections and active connections
- CFDictionaryRef properties = iSCSICreateCFPropertiesForSession(target);
+ CFDictionaryRef properties = iSCSISessionCopyCFPropertiesForTarget(sessionManager,target);
if(properties) {
// Get max connections from property list
@@ -406,7 +416,7 @@ errno_t iSCSIDLoginAllPortals(iSCSIMutableTargetRef target,
CFNumberGetValue(number,kCFNumberSInt32Type,&maxConnections);
CFRelease(properties);
- CFArrayRef connections = iSCSICreateArrayOfConnectionsIds(sessionId);
+ CFArrayRef connections = iSCSISessionCopyArrayOfConnectionIds(sessionManager,sessionId);
if(connections) {
activeConnections = CFArrayGetCount(connections);
@@ -439,12 +449,12 @@ errno_t iSCSIDLoginAllPortals(iSCSIMutableTargetRef target,
portalIdx++;
// Determine how many connections this session supports
- sessionId = iSCSIGetSessionIdForTarget(iSCSITargetGetIQN(target));
+ sessionId = iSCSISessionGetSessionIdForTarget(sessionManager,iSCSITargetGetIQN(target));
// If this was the first connection of the session, get the number of
// allowed maximum connections
if(activeConnections == 1) {
- CFDictionaryRef properties = iSCSICreateCFPropertiesForSession(target);
+ CFDictionaryRef properties = iSCSISessionCopyCFPropertiesForTarget(sessionManager,target);
if(properties) {
// Get max connections from property list
CFNumberRef number = CFDictionaryGetValue(properties,kRFC3720_Key_MaxConnections);
@@ -466,25 +476,25 @@ errno_t iSCSIDLoginWithPortal(iSCSIMutableTargetRef target,
enum iSCSILoginStatusCode * statusCode)
{
// Check for active sessions before attempting loginb
- SID sessionId = kiSCSIInvalidSessionId;
- CID connectionId = kiSCSIInvalidConnectionId;
+ SessionIdentifier sessionId = kiSCSIInvalidSessionId;
+ ConnectionIdentifier connectionId = kiSCSIInvalidConnectionId;
*statusCode = kiSCSILoginInvalidStatusCode;
errno_t errorCode = 0;
CFStringRef targetIQN = iSCSITargetGetIQN(target);
- sessionId = iSCSIGetSessionIdForTarget(targetIQN);
+ sessionId = iSCSISessionGetSessionIdForTarget(sessionManager,targetIQN);
// Existing session, add a connection
if(sessionId != kiSCSIInvalidSessionId) {
- connectionId = iSCSIGetConnectionIdForPortal(sessionId,portal);
+ connectionId = iSCSISessionGetConnectionIdForPortal(sessionManager,sessionId,portal);
// If there's an active session display error otherwise login
if(connectionId != kiSCSIInvalidConnectionId)
{} //iSCSICtlDisplayError("The specified target has an active session over the specified portal.");
else {
// See if the session can support an additional connection
- CFDictionaryRef properties = iSCSICreateCFPropertiesForSession(target);
+ CFDictionaryRef properties = iSCSISessionCopyCFPropertiesForTarget(sessionManager,target);
if(properties) {
// Get max connections from property list
UInt32 maxConnections;
@@ -492,7 +502,7 @@ errno_t iSCSIDLoginWithPortal(iSCSIMutableTargetRef target,
CFNumberGetValue(number,kCFNumberSInt32Type,&maxConnections);
CFRelease(properties);
- CFArrayRef connections = iSCSICreateArrayOfConnectionsIds(sessionId);
+ CFArrayRef connections = iSCSISessionCopyArrayOfConnectionIds(sessionManager,sessionId);
if(connections)
{
CFIndex activeConnections = CFArrayGetCount(connections);
@@ -610,19 +620,19 @@ void iSCSIDLogoutComplete(iSCSITargetRef target,enum iSCSIDAOperationResult resu
if(!errorCode)
{
- SID sessionId = iSCSIGetSessionIdForTarget(iSCSITargetGetIQN(target));
+ SessionIdentifier sessionId = iSCSISessionGetSessionIdForTarget(sessionManager,iSCSITargetGetIQN(target));
// For session logout, ensure that disk unmount was successful...
if(!portal) {
if(result == kiSCSIDAOperationSuccess)
- errorCode = iSCSILogoutSession(sessionId,&statusCode);
+ errorCode = iSCSISessionLogout(sessionManager,sessionId,&statusCode);
else
errorCode = EBUSY;
}
else {
- CID connectionId = iSCSIGetConnectionIdForPortal(sessionId,portal);
- errorCode = iSCSILogoutConnection(sessionId,connectionId,&statusCode);
+ ConnectionIdentifier connectionId = iSCSISessionGetConnectionIdForPortal(sessionManager,sessionId,portal);
+ errorCode = iSCSISessionRemoveConnection(sessionManager,sessionId,connectionId,&statusCode);
}
}
@@ -647,7 +657,12 @@ void iSCSIDLogoutComplete(iSCSITargetRef target,enum iSCSIDAOperationResult resu
strerror(errorCode));
}
- asl_log(NULL,NULL,ASL_LEVEL_ERR,"%s",CFStringGetCStringPtr(errorString,kCFStringEncodingASCII));
+ CFIndex errorStringLength = CFStringGetMaximumSizeForEncoding(CFStringGetLength(errorString),kCFStringEncodingASCII) + sizeof('\0');
+ char errorStringBuffer[errorStringLength];
+ CFStringGetCString(errorString,errorStringBuffer,errorStringLength,kCFStringEncodingASCII);
+
+ asl_log(NULL, NULL, ASL_LEVEL_ERR, "%s", errorStringBuffer);
+
CFRelease(errorString);
}
@@ -707,9 +722,8 @@ errno_t iSCSIDLogout(int fd,iSCSIDMsgLogoutCmd * cmd)
else
errorCode = EINVAL;
-
// See if there exists an active session for this target
- SID sessionId = iSCSIGetSessionIdForTarget(iSCSITargetGetIQN(target));
+ SessionIdentifier sessionId = iSCSISessionGetSessionIdForTarget(sessionManager,iSCSITargetGetIQN(target));
if(!errorCode && sessionId == kiSCSIInvalidSessionId)
{
@@ -718,17 +732,22 @@ errno_t iSCSIDLogout(int fd,iSCSIDMsgLogoutCmd * cmd)
CFSTR("logout of %@ failed: the target has no active sessions"),
iSCSITargetGetIQN(target));
- asl_log(0,0,ASL_LEVEL_CRIT,"%s",CFStringGetCStringPtr(errorString,kCFStringEncodingASCII));
+ CFIndex errorStringLength = CFStringGetMaximumSizeForEncoding(CFStringGetLength(errorString),kCFStringEncodingASCII) + sizeof('\0');
+ char errorStringBuffer[errorStringLength];
+ CFStringGetCString(errorString,errorStringBuffer,errorStringLength,kCFStringEncodingASCII);
+
+ asl_log(NULL, NULL, ASL_LEVEL_CRIT, "%s", errorStringBuffer);
+
CFRelease(errorString);
errorCode = EINVAL;
}
// See if there exists an active connection for this portal
- CID connectionId = kiSCSIInvalidConnectionId;
+ ConnectionIdentifier connectionId = kiSCSIInvalidConnectionId;
CFIndex connectionCount = 0;
if(!errorCode && portal) {
- connectionId = iSCSIGetConnectionIdForPortal(sessionId,portal);
+ connectionId = iSCSISessionGetConnectionIdForPortal(sessionManager,sessionId,portal);
if(connectionId == kiSCSIInvalidConnectionId) {
@@ -737,13 +756,18 @@ errno_t iSCSIDLogout(int fd,iSCSIDMsgLogoutCmd * cmd)
CFSTR("logout of %@,%@:%@ failed: the portal has no active connections"),
iSCSITargetGetIQN(target),iSCSIPortalGetAddress(portal),iSCSIPortalGetPort(portal));
- asl_log(0,0,ASL_LEVEL_CRIT,"%s",CFStringGetCStringPtr(errorString,kCFStringEncodingASCII));
+ CFIndex errorStringLength = CFStringGetMaximumSizeForEncoding(CFStringGetLength(errorString),kCFStringEncodingASCII) + sizeof('\0');
+ char errorStringBuffer[errorStringLength];
+ CFStringGetCString(errorString,errorStringBuffer,errorStringLength,kCFStringEncodingASCII);
+
+ asl_log(NULL, NULL, ASL_LEVEL_CRIT, "%s", errorStringBuffer);
+
CFRelease(errorString);
errorCode = EINVAL;
}
else {
// Determine the number of connections
- CFArrayRef connectionIds = iSCSICreateArrayOfConnectionsIds(sessionId);
+ CFArrayRef connectionIds = iSCSISessionCopyArrayOfConnectionIds(sessionManager,sessionId);
connectionCount = CFArrayGetCount(connectionIds);
CFRelease(connectionIds);
}
@@ -775,7 +799,7 @@ errno_t iSCSIDLogout(int fd,iSCSIDMsgLogoutCmd * cmd)
errno_t iSCSIDCreateArrayOfActiveTargets(int fd,iSCSIDMsgCreateArrayOfActiveTargetsCmd * cmd)
{
- CFArrayRef sessionIds = iSCSICreateArrayOfSessionIds();
+ CFArrayRef sessionIds = iSCSISessionCopyArrayOfSessionIds(sessionManager);
CFIndex sessionCount = CFArrayGetCount(sessionIds);
// Prepare an array to hold our targets
@@ -786,7 +810,7 @@ errno_t iSCSIDCreateArrayOfActiveTargets(int fd,iSCSIDMsgCreateArrayOfActiveTarg
// Get target object for each active session and add to array
for(CFIndex idx = 0; idx < sessionCount; idx++)
{
- iSCSITargetRef target = iSCSICreateTargetForSessionId((SID)CFArrayGetValueAtIndex(sessionIds,idx));
+ iSCSITargetRef target = iSCSISessionCopyTargetForId(sessionManager,(SessionIdentifier)CFArrayGetValueAtIndex(sessionIds,idx));
CFArrayAppendValue(activeTargets,target);
iSCSITargetRelease(target);
}
@@ -816,7 +840,7 @@ errno_t iSCSIDCreateArrayofActivePortalsForTarget(int fd,
iSCSIDMsgCreateArrayOfActivePortalsForTargetCmd * cmd)
{
// TODO: null check
- CFArrayRef sessionIds = iSCSICreateArrayOfSessionIds();
+ CFArrayRef sessionIds = iSCSISessionCopyArrayOfSessionIds(sessionManager);
CFIndex sessionCount = CFArrayGetCount(sessionIds);
// Prepare an array to hold our targets
@@ -827,7 +851,7 @@ errno_t iSCSIDCreateArrayofActivePortalsForTarget(int fd,
// Get target object for each active session and add to array
for(CFIndex idx = 0; idx < sessionCount; idx++)
{
- iSCSITargetRef target = iSCSICreateTargetForSessionId((SID)CFArrayGetValueAtIndex(sessionIds,idx));
+ iSCSITargetRef target = iSCSISessionCopyTargetForId(sessionManager,(SessionIdentifier)CFArrayGetValueAtIndex(sessionIds,idx));
CFArrayAppendValue(activeTargets,target);
iSCSITargetRelease(target);
}
@@ -870,7 +894,7 @@ errno_t iSCSIDIsTargetActive(int fd,iSCSIDMsgIsTargetActiveCmd *cmd)
if(target) {
iSCSIDMsgIsTargetActiveRsp rsp = iSCSIDMsgIsTargetActiveRspInit;
- rsp.active = (iSCSIGetSessionIdForTarget(iSCSITargetGetIQN(target)) != kiSCSIInvalidSessionId);
+ rsp.active = (iSCSISessionGetSessionIdForTarget(sessionManager,iSCSITargetGetIQN(target)) != kiSCSIInvalidSessionId);
iSCSITargetRelease(target);
@@ -900,12 +924,12 @@ errno_t iSCSIDIsPortalActive(int fd,iSCSIDMsgIsPortalActiveCmd *cmd)
}
iSCSIDMsgIsPortalActiveRsp rsp = iSCSIDMsgIsPortalActiveRspInit;
- SID sessionId = (iSCSIGetSessionIdForTarget(iSCSITargetGetIQN(target)));
+ SessionIdentifier sessionId = (iSCSISessionGetSessionIdForTarget(sessionManager,iSCSITargetGetIQN(target)));
if(sessionId == kiSCSIInvalidSessionId)
rsp.active = false;
else
- rsp.active = (iSCSIGetConnectionIdForPortal(sessionId,portal) != kiSCSIInvalidConnectionId);
+ rsp.active = (iSCSISessionGetConnectionIdForPortal(sessionManager,sessionId,portal) != kiSCSIInvalidConnectionId);
if(target)
iSCSITargetRelease(target);
@@ -941,7 +965,7 @@ errno_t iSCSIDQueryTargetForAuthMethod(int fd,iSCSIDMsgQueryTargetForAuthMethodC
enum iSCSIAuthMethods authMethod = kiSCSIAuthMethodInvalid;
enum iSCSILoginStatusCode statusCode = kiSCSILoginInvalidStatusCode;
- errno_t error = iSCSIQueryTargetForAuthMethod(portal,iSCSITargetGetIQN(target),&authMethod,&statusCode);
+ errno_t error = iSCSIQueryTargetForAuthMethod(sessionManager,portal,iSCSITargetGetIQN(target),&authMethod,&statusCode);
// Compose a response to send back to the client
iSCSIDMsgQueryTargetForAuthMethodRsp rsp = iSCSIDMsgQueryTargetForAuthMethodRspInit;
@@ -975,7 +999,7 @@ errno_t iSCSIDCreateCFPropertiesForSession(int fd,
}
if(!error) {
- CFDictionaryRef properties = iSCSICreateCFPropertiesForSession(target);
+ CFDictionaryRef properties = iSCSISessionCopyCFPropertiesForTarget(sessionManager,target);
// Send back response
iSCSIDMsgCreateCFPropertiesForSessionRsp rsp = iSCSIDMsgCreateCFPropertiesForSessionRspInit;
@@ -1032,7 +1056,7 @@ errno_t iSCSIDCreateCFPropertiesForConnection(int fd,
if(!error) {
- CFDictionaryRef properties = iSCSICreateCFPropertiesForConnection(target,portal);
+ CFDictionaryRef properties = iSCSISessionCopyCFPropertiesForPortal(sessionManager,target,portal);
// Send back response
iSCSIDMsgCreateCFPropertiesForConnectionRsp rsp = iSCSIDMsgCreateCFPropertiesForConnectionRspInit;
@@ -1064,9 +1088,219 @@ errno_t iSCSIDCreateCFPropertiesForConnection(int fd,
return error;
}
+
+errno_t iSCSIDAddTargetForSendTargets(iSCSIPreferencesRef preferences,
+ CFStringRef targetIQN,
+ iSCSIDiscoveryRecRef discoveryRec,
+ CFStringRef discoveryPortal)
+{
+ CFArrayRef portalGroups = iSCSIDiscoveryRecCreateArrayOfPortalGroupTags(discoveryRec,targetIQN);
+ CFIndex portalGroupCount = CFArrayGetCount(portalGroups);
+
+ // Iterate over portal groups for this target
+ for(CFIndex portalGroupIdx = 0; portalGroupIdx < portalGroupCount; portalGroupIdx++)
+ {
+ CFStringRef portalGroupTag = CFArrayGetValueAtIndex(portalGroups,portalGroupIdx);
+ CFArrayRef portals = iSCSIDiscoveryRecGetPortals(discoveryRec,targetIQN,portalGroupTag);
+ CFIndex portalsCount = CFArrayGetCount(portals);
+
+ iSCSIPortalRef portal = NULL;
+
+ // Iterate over portals within this group
+ for(CFIndex portalIdx = 0; portalIdx < portalsCount; portalIdx++)
+ {
+ if(!(portal = CFArrayGetValueAtIndex(portals,portalIdx)))
+ continue;
+
+ // Add portal to target, or add target as necessary
+ if(iSCSIPreferencesContainsTarget(preferences,targetIQN))
+ iSCSIPreferencesSetPortalForTarget(preferences,targetIQN,portal);
+ else
+ iSCSIPreferencesAddDynamicTargetForSendTargets(preferences,targetIQN,portal,discoveryPortal);
+ }
+ }
+
+ CFRelease(portalGroups);
+
+ return 0;
+}
+
+/*! Updates an iSCSI preference sobject with information about targets as
+ * contained in the provided discovery record.
+ * @param preferences an iSCSI preferences object.
+ * @param discoveryPortal the portal (address) that was used to perform discovery.
+ * @param discoveryRec the discovery record resulting from the discovery operation.
+ * @return an error code indicating the result of the operation. */
+errno_t iSCSIDUpdatePreferencesWithDiscoveredTargets(iSCSISessionManagerRef managerRef,
+ iSCSIPreferencesRef preferences,
+ CFStringRef discoveryPortal,
+ iSCSIDiscoveryRecRef discoveryRec)
+{
+ CFArrayRef targets = iSCSIDiscoveryRecCreateArrayOfTargets(discoveryRec);
+
+ if(!targets)
+ return EINVAL;
+
+ CFIndex targetCount = CFArrayGetCount(targets);
+
+ CFMutableDictionaryRef discTargets = CFDictionaryCreateMutable(
+ kCFAllocatorDefault,0,&kCFTypeDictionaryKeyCallBacks,0);
+
+ for(CFIndex targetIdx = 0; targetIdx < targetCount; targetIdx++)
+ {
+ CFStringRef targetIQN = CFArrayGetValueAtIndex(targets,targetIdx);
+
+ // Target exists with static (or other configuration). In
+ // this case we do nothing, log a message and move on.
+ if(iSCSIPreferencesContainsTarget(preferences,targetIQN) &&
+ iSCSIPreferencesGetTargetConfigType(preferences,targetIQN) != kiSCSITargetConfigDynamicSendTargets)
+ {
+ CFStringRef statusString = CFStringCreateWithFormat(
+ kCFAllocatorDefault,0,
+ CFSTR("discovered target %@ already exists with static configuration."),
+ targetIQN);
+
+ asl_log(NULL,NULL,ASL_LEVEL_INFO,"%s",CFStringGetCStringPtr(statusString,kCFStringEncodingASCII));
+
+ CFRelease(statusString);
+ }
+ // Target doesn't exist, or target exists with SendTargets
+ // configuration (add or update as necessary)
+ else {
+ iSCSIDAddTargetForSendTargets(preferences,targetIQN,discoveryRec,discoveryPortal);
+ CFStringRef statusString = CFStringCreateWithFormat(
+ kCFAllocatorDefault,0,
+ CFSTR("discovered target %@ over discovery portal %@."),
+ targetIQN,discoveryPortal);
+
+ asl_log(NULL,NULL,ASL_LEVEL_INFO,"%s",CFStringGetCStringPtr(statusString,kCFStringEncodingASCII));
+
+ CFRelease(statusString);
+ }
+
+ // As we process each target we'll add it to a temporary dictionary
+ // for cross-checking against targets that exist in our database
+ // which have been removed.
+ CFDictionaryAddValue(discTargets,targetIQN,0);
+ }
+
+ // Are there any targets that must be removed? Cross-check existing
+ // list against the list we just built...
+ CFArrayRef existingTargets = iSCSIPreferencesCreateArrayOfDynamicTargetsForSendTargets(preferences,discoveryPortal);
+ targetCount = CFArrayGetCount(existingTargets);
+
+ for(CFIndex targetIdx = 0; targetIdx < targetCount; targetIdx++)
+ {
+ CFStringRef targetIQN = CFArrayGetValueAtIndex(existingTargets,targetIdx);
+
+ // If we have a target that was not discovered, then we need to remove
+ // it from our property list...
+ if(!CFDictionaryContainsKey(discTargets,targetIQN)) {
+
+ // If the target is logged in, logout of the target and remove it
+ SessionIdentifier sessionId = iSCSISessionGetSessionIdForTarget(managerRef,targetIQN);
+ enum iSCSILogoutStatusCode statusCode;
+ if(sessionId != kiSCSIInvalidSessionId)
+ iSCSISessionLogout(managerRef,sessionId,&statusCode);
+
+ iSCSIPreferencesRemoveTarget(preferences,targetIQN);
+ }
+ }
+
+ CFRelease(targets);
+ CFRelease(discTargets);
+ CFRelease(existingTargets);
+
+ return 0;
+}
+
+/*! Scans all iSCSI discovery portals found in iSCSI preferences
+ * for targets (SendTargets). Returns a dictionary of key-value pairs
+ * with discovery record objects as values and discovery portal names
+ * as keys.
+ * @param preferences an iSCSI preferences object.
+ * @return a dictionary key-value pairs of dicovery portal names (addresses)
+ * and the discovery records associated with the result of SendTargets
+ * discovery of those portals. */
+CFDictionaryRef iSCSIDCreateRecordsWithSendTargets(iSCSISessionManagerRef managerRef,
+ iSCSIPreferencesRef preferences)
+{
+ if(!preferences)
+ return NULL;
+
+ CFArrayRef portals = iSCSIPreferencesCreateArrayOfPortalsForSendTargetsDiscovery(preferences);
+
+ // Quit if no discovery portals are defined
+ if(!portals)
+ return NULL;
+
+ CFIndex portalCount = CFArrayGetCount(portals);
+
+ CFStringRef discoveryPortal = NULL;
+ iSCSIPortalRef portal = NULL;
+
+ CFMutableDictionaryRef discoveryRecords = CFDictionaryCreateMutable(kCFAllocatorDefault,0,
+ &kiSCSITypeDictionaryKeyCallbacks,
+ &kiSCSITypeDictionaryValueCallbacks);
+
+ for(CFIndex idx = 0; idx < portalCount; idx++)
+ {
+ discoveryPortal = CFArrayGetValueAtIndex(portals,idx);
+
+ if(!discoveryPortal)
+ continue;
+
+ portal = iSCSIPreferencesCopySendTargetsDiscoveryPortal(preferences,discoveryPortal);
+
+ if(!portal)
+ continue;
+
+ enum iSCSILoginStatusCode statusCode;
+ iSCSIMutableDiscoveryRecRef discoveryRec;
+
+ // If there was an error, log it and move on to the next portal
+ errno_t error = 0;
+ iSCSIAuthRef auth = iSCSIAuthCreateNone();
+ if((error = iSCSIQueryPortalForTargets(managerRef,portal,auth,&discoveryRec,&statusCode)))
+ {
+ CFStringRef errorString = CFStringCreateWithFormat(
+ kCFAllocatorDefault,0,
+ CFSTR("system error (code %d) occurred during SendTargets discovery of %@."),
+ error,discoveryPortal);
+
+ asl_log(NULL,NULL,ASL_LEVEL_ERR,"%s",CFStringGetCStringPtr(errorString,kCFStringEncodingASCII));
+ CFRelease(errorString);
+ }
+ else if(statusCode != kiSCSILoginSuccess) {
+ CFStringRef errorString = CFStringCreateWithFormat(
+ kCFAllocatorDefault,0,
+ CFSTR("login failed with (code %d) during SendTargets discovery of %@."),
+ statusCode,discoveryPortal);
+
+ asl_log(NULL,NULL,ASL_LEVEL_ERR,"%s",CFStringGetCStringPtr(errorString,kCFStringEncodingASCII));
+ CFRelease(errorString);
+ }
+ else {
+ // Queue discovery record so that it can be processes later
+ if(discoveryRec) {
+ CFDictionarySetValue(discoveryRecords,discoveryPortal,discoveryRec);
+ iSCSIDiscoveryRecRelease(discoveryRec);
+ }
+ }
+
+ iSCSIAuthRelease(auth);
+ iSCSIPortalRelease(portal);
+ }
+
+ // Release the array of discovery portals
+ CFRelease(portals);
+
+ return discoveryRecords;
+}
+
void * iSCSIDRunDiscovery(void * context)
{
- CFDictionaryRef discoveryRecords = iSCSIDiscoveryCreateRecordsWithSendTargets(preferences);
+ CFDictionaryRef discoveryRecords = iSCSIDCreateRecordsWithSendTargets(sessionManager,preferences);
// Process discovery results if any
if(discoveryRecords) {
@@ -1080,7 +1314,7 @@ void * iSCSIDRunDiscovery(void * context)
CFDictionaryGetKeysAndValues(discoveryRecords,keys,values);
for(CFIndex i = 0; i < count; i++)
- iSCSIDiscoveryUpdatePreferencesWithDiscoveredTargets(preferences,keys[i],values[i]);
+ iSCSIDUpdatePreferencesWithDiscoveredTargets(sessionManager,preferences,keys[i],values[i]);
iSCSIPreferencesSynchronzeAppValues(preferences);
pthread_mutex_unlock(&preferencesMutex);
@@ -1367,6 +1601,86 @@ errno_t iSCSIDRemoveSharedSecret(int fd,iSCSIDMsgRemoveSharedSecretCmd *cmd)
return 0;
}
+/*! Callback function used to process a queued login once
+ * the network becomes available. */
+void iSCSIDProcessQueuedLogin(SCNetworkReachabilityRef reachabilityTarget,
+ SCNetworkReachabilityFlags flags,
+ void * info)
+{
+ struct iSCSIDQueueLoginForTargetPortal * loginRef = info;
+
+ iSCSIMutableTargetRef target = iSCSITargetCreateMutableCopy(loginRef->target);
+ iSCSIPortalRef portal = loginRef->portal;
+
+ enum iSCSILoginStatusCode statusCode;
+ iSCSIDLoginWithPortal(target,portal,&statusCode);
+
+ iSCSITargetRelease(target);
+ iSCSITargetRelease(loginRef->target);
+ iSCSIPortalRelease(portal);
+
+ free(loginRef);
+}
+
+/*! Helper function used by auto-login, sleep-mode and persistent
+ * functions to login to the specified target using the specified
+ * portal when the network becomes available. */
+void iSCSIDQueueLogin(iSCSITargetRef target,iSCSIPortalRef portal)
+{
+ SCNetworkReachabilityRef reachabilityTarget;
+ SCNetworkReachabilityContext reachabilityContext;
+
+ struct iSCSIDQueueLoginForTargetPortal * loginRef = malloc(sizeof(struct iSCSIDQueueLoginForTargetPortal));
+ loginRef->target = target;
+ loginRef->portal = portal;
+
+ reachabilityContext.info = loginRef;
+ reachabilityContext.copyDescription = 0;
+ reachabilityContext.retain = 0;
+ reachabilityContext.release = 0;
+
+ char portalAddressBuffer[NI_MAXHOST];
+
+ if(!CFStringGetCString(iSCSIPortalGetAddress(portal),portalAddressBuffer,NI_MAXHOST,kCFStringEncodingASCII))
+ return;
+
+ // If a specific host interface was specified, create with pair...
+ if(CFStringCompare(iSCSIPortalGetHostInterface(portal),kiSCSIDefaultHostInterface,0) == kCFCompareEqualTo)
+ reachabilityTarget = SCNetworkReachabilityCreateWithName(kCFAllocatorDefault,portalAddressBuffer);
+ else {
+
+ struct sockaddr_storage remoteAddress, localAddress;
+ iSCSIUtilsGetAddressForPortal(portal,&remoteAddress,&localAddress);
+
+ reachabilityTarget = SCNetworkReachabilityCreateWithAddressPair(kCFAllocatorDefault,
+ (const struct sockaddr *)&localAddress,
+ (const struct sockaddr *)&remoteAddress);
+ }
+
+ SCNetworkReachabilitySetCallback(reachabilityTarget,iSCSIDProcessQueuedLogin,&reachabilityContext);
+ SCNetworkReachabilityScheduleWithRunLoop(reachabilityTarget,CFRunLoopGetMain(),kCFRunLoopDefaultMode);
+}
+
+void iSCSIDSessionTimeoutHandler(iSCSITargetRef target,iSCSIPortalRef portal)
+{
+ if(!target || !portal)
+ return;
+
+ // Post message to system log
+ asl_log(NULL,NULL,ASL_LEVEL_ERR,"TCP timeout for %s over portal %s.",
+ CFStringGetCStringPtr(iSCSITargetGetIQN(target),kCFStringEncodingASCII),
+ CFStringGetCStringPtr(iSCSIPortalGetAddress(portal),kCFStringEncodingASCII));
+
+ // If this was a persistance target, queue another login when the network is
+ // available
+ if(iSCSIPreferencesGetPersistenceForTarget(preferences,iSCSITargetGetIQN(target)))
+ iSCSIDQueueLogin(target,portal);
+ else {
+ iSCSITargetRelease(target);
+ iSCSIPortalRelease(portal);
+ }
+}
+
/*! Automatically logs in to targets that were specified for auto-login.
* Used during startup of the daemon to log in to either static
* dynamic targets for which the auto-login option is enabled. */
@@ -1385,14 +1699,27 @@ void iSCSIDAutoLogin()
for(CFIndex idx = 0; idx < targetsCount; idx++)
{
CFStringRef targetIQN = CFArrayGetValueAtIndex(targets,idx);
+ iSCSITargetRef target = iSCSIPreferencesCopyTarget(preferences,targetIQN);
+ // See if this target requires auto-login and process it
if(iSCSIPreferencesGetAutoLoginForTarget(preferences,targetIQN)) {
- iSCSITargetRef targetTemp = iSCSIPreferencesCopyTarget(preferences,targetIQN);
- iSCSIMutableTargetRef target = iSCSITargetCreateMutableCopy(targetTemp);
- iSCSITargetRelease(targetTemp);
- enum iSCSILoginStatusCode statusCode;
- iSCSIDLoginAllPortals(target,&statusCode);
+
+ CFArrayRef portals = iSCSIPreferencesCreateArrayOfPortalsForTarget(preferences,targetIQN);
+ if(!portals)
+ continue;
+
+ CFIndex portalsCount = CFArrayGetCount(portals);
+
+ // Queue a login operation for a each portal; mind the interface is one is required
+ for(CFIndex portalIdx = 0; portalIdx < portalsCount; portalIdx++)
+ {
+ CFStringRef portalAddress = CFArrayGetValueAtIndex(portals,portalIdx);
+ iSCSIPortalRef portal = iSCSIPreferencesCopyPortalForTarget(preferences,targetIQN,portalAddress);
+ iSCSIDQueueLogin(target,portal);
+ }
+
iSCSITargetRelease(target);
+ CFRelease(portals);
}
}
CFRelease(targets);
@@ -1439,16 +1766,16 @@ void iSCSIDPrepareForSystemSleepComplete(iSCSITargetRef target,
enum iSCSIDAOperationResult result,
void * context)
{
- SID sessionId = (SID)context;
+ SessionIdentifier sessionId = (SessionIdentifier)context;
enum iSCSILogoutStatusCode statusCode;
- iSCSILogoutSession(sessionId,&statusCode);
+ iSCSISessionLogout(sessionManager,sessionId,&statusCode);
}
/*! Saves a dictionary of active targets and portals that
* is used to restore active sessions upon wakeup. */
void iSCSIDPrepareForSystemSleep()
{
- CFArrayRef sessionIds = iSCSICreateArrayOfSessionIds();
+ CFArrayRef sessionIds = iSCSISessionCopyArrayOfSessionIds(sessionManager);
if(!sessionIds)
return;
@@ -1469,22 +1796,22 @@ void iSCSIDPrepareForSystemSleep()
for(CFIndex idx = 0; idx < sessionCount; idx++)
{
- SID sessionId = (SID)CFArrayGetValueAtIndex(sessionIds,idx);
- iSCSITargetRef target = iSCSICreateTargetForSessionId(sessionId);
+ SessionIdentifier sessionId = (SessionIdentifier)CFArrayGetValueAtIndex(sessionIds,idx);
+ iSCSITargetRef target = iSCSISessionCopyTargetForId(sessionManager,sessionId);
if(!target)
continue;
CFStringRef targetIQN = iSCSITargetGetIQN(target);
- CFArrayRef connectionIds = iSCSICreateArrayOfConnectionsIds(sessionId);
+ CFArrayRef connectionIds = iSCSISessionCopyArrayOfConnectionIds(sessionManager,sessionId);
CFIndex connectionCount = CFArrayGetCount(connectionIds);
CFMutableArrayRef portals = CFArrayCreateMutable(kCFAllocatorDefault,0,&kCFTypeArrayCallBacks);
for(CFIndex connIdx = 0; connIdx < connectionCount; connIdx++)
{
- CID connectionId = (CID)CFArrayGetValueAtIndex(connectionIds,connIdx);
- iSCSIPortalRef portal = iSCSICreatePortalForConnectionId(sessionId,connectionId);
+ ConnectionIdentifier connectionId = (ConnectionIdentifier)CFArrayGetValueAtIndex(connectionIds,connIdx);
+ iSCSIPortalRef portal = iSCSISessionCopyPortalForConnectionId(sessionManager,sessionId,connectionId);
CFArrayAppendValue(portals,portal);
CFRelease(portal);
}
@@ -1610,7 +1937,7 @@ void iSCSIDProcessIncomingRequest(void * info)
}
}
-/*! Handle an incoming connection from iscsictl. Once a connection is
+/*! Handle an incoming connection from a client. Once a connection is
* established, main runloop calls this function. This function processes
* all incoming commands until a shutdown request is received, at which point
* this function terminates and returns control to the run loop. For this
@@ -1660,15 +1987,26 @@ int main(void)
{
// Initialize logging
aslclient log = asl_open(NULL,NULL,ASL_OPT_STDERR);
+
+ // Start the iSCSI session manager (which creates a connection to the HBA)
+ iSCSISessionManagerCallBacks callbacks;
+ callbacks.timeoutCallback = iSCSIDSessionTimeoutHandler;
+ sessionManager = iSCSISessionManagerCreate(kCFAllocatorDefault,callbacks);
+
+ // Let launchd call us again once the HBA kext is loaded
+ if(!sessionManager)
+ return EAGAIN;
+
+ iSCSISessionManagerScheduleWithRunLoop(sessionManager,CFRunLoopGetMain(),kCFRunLoopDefaultMode);
// Read configuration parameters from the iSCSI property list
iSCSIDUpdatePreferencesFromAppValues();
// Update initiator name and alias internally
CFStringRef initiatorIQN = iSCSIPreferencesCopyInitiatorIQN(preferences);
-
+
if(initiatorIQN) {
- iSCSISetInitiatorName(initiatorIQN);
+ iSCSISessionManagerSetInitiatorName(sessionManager,initiatorIQN);
CFRelease(initiatorIQN);
}
else {
@@ -1678,7 +2016,7 @@ int main(void)
CFStringRef initiatorAlias = iSCSIPreferencesCopyInitiatorAlias(preferences);
if(initiatorAlias) {
- iSCSISetInitiatorAlias(initiatorAlias);
+ iSCSISessionManagerSetInitiatorName(sessionManager,initiatorAlias);
CFRelease(initiatorAlias);
}
else {
@@ -1761,10 +2099,6 @@ int main(void)
// Ignore SIGPIPE (generated when the client closes the connection)
signal(SIGPIPE,sig_pipe_handler);
- // Initialize iSCSI connection to kernel (ability to call iSCSI kernel
- // functions and receive notifications from the kernel).
- iSCSIInitialize(CFRunLoopGetMain());
-
// Setup authorization rights if none exist
AuthorizationRef authorization;
AuthorizationCreate(NULL,NULL,0,&authorization);
@@ -1778,7 +2112,10 @@ int main(void)
iSCSIDAutoLogin();
CFRunLoopRun();
- iSCSICleanup();
+
+ iSCSISessionManagerUnscheduleWithRunloop(sessionManager,CFRunLoopGetMain(),kCFRunLoopDefaultMode);
+ iSCSISessionManagerRelease(sessionManager);
+ sessionManager = NULL;
// Deregister for power
iSCSIDDeregisterForPowerEvents();
diff --git a/Source/User/iscsid/iSCSIDiscovery.c b/Source/User/iscsid/iSCSIDiscovery.c
index 35aabe49..df2352d0 100644
--- a/Source/User/iscsid/iSCSIDiscovery.c
+++ b/Source/User/iscsid/iSCSIDiscovery.c
@@ -70,7 +70,8 @@ errno_t iSCSIDiscoveryAddTargetForSendTargets(iSCSIPreferencesRef preferences,
* @param discoveryPortal the portal (address) that was used to perform discovery.
* @param discoveryRec the discovery record resulting from the discovery operation.
* @return an error code indicating the result of the operation. */
-errno_t iSCSIDiscoveryUpdatePreferencesWithDiscoveredTargets(iSCSIPreferencesRef preferences,
+errno_t iSCSIDiscoveryUpdatePreferencesWithDiscoveredTargets(iSCSISessionManagerRef managerRef,
+ iSCSIPreferencesRef preferences,
CFStringRef discoveryPortal,
iSCSIDiscoveryRecRef discoveryRec)
{
@@ -98,8 +99,12 @@ errno_t iSCSIDiscoveryUpdatePreferencesWithDiscoveredTargets(iSCSIPreferencesRef
CFSTR("discovered target %@ already exists with static configuration."),
targetIQN);
- asl_log(NULL,NULL,ASL_LEVEL_INFO,"%s",CFStringGetCStringPtr(statusString,kCFStringEncodingASCII));
+ CFIndex statusStringLength = CFStringGetMaximumSizeForEncoding(CFStringGetLength(statusString),kCFStringEncodingASCII) + sizeof('\0');
+ char statusStringBuffer[statusStringLength];
+ CFStringGetCString(statusString,statusStringBuffer,statusStringLength,kCFStringEncodingASCII);
+ asl_log(NULL, NULL, ASL_LEVEL_INFO, "%s", statusStringBuffer);
+
CFRelease(statusString);
}
// Target doesn't exist, or target exists with SendTargets
@@ -111,8 +116,12 @@ errno_t iSCSIDiscoveryUpdatePreferencesWithDiscoveredTargets(iSCSIPreferencesRef
CFSTR("discovered target %@ over discovery portal %@."),
targetIQN,discoveryPortal);
- asl_log(NULL,NULL,ASL_LEVEL_INFO,"%s",CFStringGetCStringPtr(statusString,kCFStringEncodingASCII));
-
+ CFIndex statusStringLength = CFStringGetMaximumSizeForEncoding(CFStringGetLength(statusString),kCFStringEncodingASCII) + sizeof('\0');
+ char statusStringBuffer[statusStringLength];
+ CFStringGetCString(statusString,statusStringBuffer,statusStringLength,kCFStringEncodingASCII);
+
+ asl_log(NULL, NULL, ASL_LEVEL_INFO, "%s", statusStringBuffer);
+
CFRelease(statusString);
}
@@ -136,10 +145,10 @@ errno_t iSCSIDiscoveryUpdatePreferencesWithDiscoveredTargets(iSCSIPreferencesRef
if(!CFDictionaryContainsKey(discTargets,targetIQN)) {
// If the target is logged in, logout of the target and remove it
- SID sessionId = iSCSIGetSessionIdForTarget(targetIQN);
+ SessionIdentifier sessionId = iSCSISessionGetSessionIdForTarget(managerRef,targetIQN);
enum iSCSILogoutStatusCode statusCode;
if(sessionId != kiSCSIInvalidSessionId)
- iSCSILogoutSession(sessionId,&statusCode);
+ iSCSISessionLogout(managerRef,sessionId,&statusCode);
iSCSIPreferencesRemoveTarget(preferences,targetIQN);
}
@@ -160,7 +169,8 @@ errno_t iSCSIDiscoveryUpdatePreferencesWithDiscoveredTargets(iSCSIPreferencesRef
* @return a dictionary key-value pairs of dicovery portal names (addresses)
* and the discovery records associated with the result of SendTargets
* discovery of those portals. */
-CFDictionaryRef iSCSIDiscoveryCreateRecordsWithSendTargets(iSCSIPreferencesRef preferences)
+CFDictionaryRef iSCSIDiscoveryCreateRecordsWithSendTargets(iSCSISessionManagerRef managerRef,
+ iSCSIPreferencesRef preferences)
{
if(!preferences)
return NULL;
@@ -198,14 +208,19 @@ CFDictionaryRef iSCSIDiscoveryCreateRecordsWithSendTargets(iSCSIPreferencesRef p
// If there was an error, log it and move on to the next portal
errno_t error = 0;
iSCSIAuthRef auth = iSCSIAuthCreateNone();
- if((error = iSCSIQueryPortalForTargets(portal,auth,&discoveryRec,&statusCode)))
+ if((error = iSCSIQueryPortalForTargets(managerRef,portal,auth,&discoveryRec,&statusCode)))
{
CFStringRef errorString = CFStringCreateWithFormat(
kCFAllocatorDefault,0,
CFSTR("system error (code %d) occurred during SendTargets discovery of %@."),
error,discoveryPortal);
- asl_log(NULL,NULL,ASL_LEVEL_ERR,"%s",CFStringGetCStringPtr(errorString,kCFStringEncodingASCII));
+ CFIndex errorStringLength = CFStringGetMaximumSizeForEncoding(CFStringGetLength(errorString),kCFStringEncodingASCII) + sizeof('\0');
+ char errorStringBuffer[errorStringLength];
+ CFStringGetCString(errorString,errorStringBuffer,errorStringLength,kCFStringEncodingASCII);
+
+ asl_log(NULL, NULL, ASL_LEVEL_ERR, "%s", errorStringBuffer);
+
CFRelease(errorString);
}
else if(statusCode != kiSCSILoginSuccess) {
@@ -214,7 +229,12 @@ CFDictionaryRef iSCSIDiscoveryCreateRecordsWithSendTargets(iSCSIPreferencesRef p
CFSTR("login failed with (code %d) during SendTargets discovery of %@."),
statusCode,discoveryPortal);
- asl_log(NULL,NULL,ASL_LEVEL_ERR,"%s",CFStringGetCStringPtr(errorString,kCFStringEncodingASCII));
+ CFIndex errorStringLength = CFStringGetMaximumSizeForEncoding(CFStringGetLength(errorString),kCFStringEncodingASCII) + sizeof('\0');
+ char errorStringBuffer[errorStringLength];
+ CFStringGetCString(errorString,errorStringBuffer,errorStringLength,kCFStringEncodingASCII);
+
+ asl_log(NULL, NULL, ASL_LEVEL_ERR, "%s", errorStringBuffer);
+
CFRelease(errorString);
}
else {
diff --git a/Source/User/iscsid/iSCSIDiscovery.h b/Source/User/iscsid/iSCSIDiscovery.h
index 3af95fe8..c959e35c 100644
--- a/Source/User/iscsid/iSCSIDiscovery.h
+++ b/Source/User/iscsid/iSCSIDiscovery.h
@@ -45,7 +45,8 @@
* @return a dictionary key-value pairs of dicovery portal names (addresses)
* and the discovery records associated with the result of SendTargets
* discovery of those portals. */
-CFDictionaryRef iSCSIDiscoveryCreateRecordsWithSendTargets(iSCSIPreferencesRef preferences);
+CFDictionaryRef iSCSIDiscoveryCreateRecordsWithSendTargets(iSCSISessionManagerRef managerRef,
+ iSCSIPreferencesRef preferences);
/*! Updates an iSCSI preference sobject with information about targets as
* contained in the provided discovery record.
@@ -53,7 +54,8 @@ CFDictionaryRef iSCSIDiscoveryCreateRecordsWithSendTargets(iSCSIPreferencesRef p
* @param discoveryPortal the portal (address) that was used to perform discovery.
* @param discoveryRec the discovery record resulting from the discovery operation.
* @return an error code indicating the result of the operation. */
-errno_t iSCSIDiscoveryUpdatePreferencesWithDiscoveredTargets(iSCSIPreferencesRef preferences,
+errno_t iSCSIDiscoveryUpdatePreferencesWithDiscoveredTargets(iSCSISessionManagerRef managerRef,
+ iSCSIPreferencesRef preferences,
CFStringRef discoveryPortal,
iSCSIDiscoveryRecRef discoveryRec);
diff --git a/Source/User/iscsid/iSCSIHBAInterface.c b/Source/User/iscsid/iSCSIHBAInterface.c
new file mode 100644
index 00000000..fe8c83ae
--- /dev/null
+++ b/Source/User/iscsid/iSCSIHBAInterface.c
@@ -0,0 +1,1068 @@
+/*
+ * Copyright (c) 2016, Nareg Sinenian
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INConnectionIdentifierENTAL, 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.
+ */
+
+#include "iSCSIHBAInterface.h"
+#include "iSCSIHBATypes.h"
+#include "iSCSIPDUUser.h"
+
+#include
+#include
+
+struct __iSCSIHBAInterface {
+
+ /*! Allocator used to create this instance. */
+ CFAllocatorRef allocator;
+
+ /*! The iSCSI HBA service. */
+ io_service_t service;
+
+ /*! Connection to kernel user client. */
+ io_connect_t connect;
+
+ /*! Runloop source associated with this instance. */
+ CFRunLoopSourceRef source;
+
+ /*! Mach port used to receive notifications. */
+ CFMachPortRef notificationPort;
+
+ /*! Callback that will handle kernel notifications. */
+ iSCSIHBANotificationCallBack callback;
+
+ /*! Notification data used when invoking the callback. */
+ struct __iSCSIHBANotificationContext notifyContext;
+};
+
+/*! Handles messages sent from the HBA. This is an internal handler that is called first
+ * to adhere to the required Mach callback prototype. The info parameter contains
+ * information about an iSCSIHBAInterface instance (which includes user-defined data). */
+static void iSCSIHBANotificationHandler(CFMachPortRef port,void * msg,CFIndex size,void * info)
+{
+ // The parameter is a notification message
+ iSCSIHBANotificationMessage * notificationMsg;
+ if(!(notificationMsg = msg))
+ return;
+
+ // Process notification type and return if invalid
+ enum iSCSIHBANotificationTypes type = (enum iSCSIHBANotificationTypes)notificationMsg->notificationType;
+
+ if(type == kiSCSIHBANotificationInvalid)
+ return;
+
+ // Call the callback function with the message type and body
+ iSCSIHBAInterfaceRef interface = (iSCSIHBAInterfaceRef)info;
+ if(interface->callback)
+ interface->callback(interface,type,msg,interface->notifyContext.info);
+}
+
+/*! Schedules execution of various tasks, including handling of kernel notifications
+ * on for the specified interface instance over the designated runloop.
+ * @param interface an instance of an iSCSIHBAInterface.
+ * @param runLoop the runloop to schedule
+ * @param runLoopMode the execution mode for the runLoop. */
+void iSCSIHBAInterfaceScheduleWithRunloop(iSCSIHBAInterfaceRef interface,
+ CFRunLoopRef runLoop,
+ CFStringRef runLoopMode)
+{
+ if(interface->notificationPort && interface->source == NULL) {
+ CFRunLoopSourceRef source = CFMachPortCreateRunLoopSource(kCFAllocatorDefault,interface->notificationPort,0);
+ CFRunLoopAddSource(runLoop,source,runLoopMode);
+ interface->source = source;
+ }
+}
+
+/*! Unschedules execution of various tasks, including handling of kernel notifications
+ * on for the specified interface instance over the designated runloop.
+ * @param interface an instance of an iSCSIHBAInterface.
+ * @param runLoop the runloop to schedule
+ * @param runLoopMode the execution mode for the runLoop. */
+void iSCSIHBAInterfaceUnscheduleWithRunloop(iSCSIHBAInterfaceRef interface,
+ CFRunLoopRef runLoop,
+ CFStringRef runLoopMode)
+{
+ if(interface->notificationPort) {
+ CFRunLoopSourceRef source = CFMachPortCreateRunLoopSource(kCFAllocatorDefault,interface->notificationPort,0);
+ CFRunLoopRemoveSource(runLoop,source,runLoopMode);
+ }
+}
+
+/*! Opens a connection to the iSCSI initiator. A connection must be
+ * successfully opened before any of the supporting functions below can be
+ * called. */
+iSCSIHBAInterfaceRef iSCSIHBAInterfaceCreate(CFAllocatorRef allocator,iSCSIHBANotificationCallBack callback,iSCSIHBANotificationContext * context)
+{
+ io_service_t service = IO_OBJECT_NULL;
+ io_connect_t connect = IO_OBJECT_NULL;
+ kern_return_t result = kIOReturnSuccess;
+ CFMachPortRef notificationPort = NULL;
+
+ iSCSIHBAInterfaceRef interface = CFAllocatorAllocate(allocator,sizeof(struct __iSCSIHBAInterface),0);
+
+ // Create a dictionary to match iSCSIkext
+ CFMutableDictionaryRef matchingDict = NULL;
+ matchingDict = IOServiceMatching(kiSCSIVirtualHBA_IOClassName);
+
+ service = IOServiceGetMatchingService(kIOMasterPortDefault,matchingDict);
+
+ // Check to see if the driver was found in the I/O registry
+ // and open a connection to it.
+ if(service != IO_OBJECT_NULL) {
+ result = IOServiceOpen(service,mach_task_self(),0,&connect);
+ }
+
+ if(result == kIOReturnSuccess)
+ result = IOConnectCallScalarMethod(connect,kiSCSIOpenInitiator,0,0,0,0);
+
+ if(result == kIOReturnSuccess) {
+
+ CFMachPortContext notificationContext;
+ notificationContext.version = 0;
+ notificationContext.info = (void *)interface;
+ notificationContext.release = 0;
+ notificationContext.retain = 0;
+ notificationContext.copyDescription = NULL;
+
+ // Create a mach port to receive notifications from the kernel
+ notificationPort = CFMachPortCreate(allocator,iSCSIHBANotificationHandler,¬ificationContext,NULL);
+ result = IOConnectSetNotificationPort(connect,0,CFMachPortGetPort(notificationPort),0);
+ }
+
+ if(result == kIOReturnSuccess) {
+ interface->allocator = allocator;
+ interface->service = service;
+ interface->connect = connect;
+ interface->notificationPort = notificationPort;
+ interface->callback = callback;
+ interface->source = NULL;
+ memcpy(&interface->notifyContext,context,sizeof(struct __iSCSIHBANotificationContext));
+
+ // Retain user-defined data if a callback was provided
+ // (this may be NULL in which case we are not responsible)
+ if(interface->notifyContext.retain)
+ interface->notifyContext.retain(interface->notifyContext.info);
+
+ }
+ // Cleanup
+ else {
+ if(notificationPort)
+ CFRelease(notificationPort);
+ if(connect != IO_OBJECT_NULL)
+ IOObjectRelease(connect);
+ if(service != IO_OBJECT_NULL)
+ IOObjectRelease(service);
+
+ CFAllocatorDeallocate(allocator,interface);
+ }
+ return interface;
+}
+
+/*! Closes a connection to the iSCSI initiator. */
+void iSCSIHBAInterfaceRelease(iSCSIHBAInterfaceRef interface)
+{
+ if(!interface)
+ return;
+
+ // Release runloop source is one exists
+ if(interface->source)
+ CFRelease(interface->source);
+
+ // Close connection to the driver
+ IOConnectCallScalarMethod(interface->connect,kiSCSICloseInitiator,0,0,0,0);
+
+ // Clean up (now that we have a connection we no longer need the object)
+ IOServiceClose(interface->connect);
+
+ // Stop receiving HBA notifications
+ if(interface->notificationPort) {
+ CFRelease(interface->notificationPort);
+ }
+
+ // Release user-defined data if a callback was provided
+ // (this may be NULL in which case we are not responsible)
+ if(interface->notifyContext.release)
+ interface->notifyContext.release(interface->notifyContext.info);
+
+ CFAllocatorDeallocate(interface->allocator,interface);
+}
+
+/*! Allocates a new iSCSI session in the kernel and creates an associated
+ * connection to the target portal. Additional connections may be added to the
+ * session by calling iSCSIHBAInterfaceCreateConnection().
+ * @param interface an instance of an iSCSIHBAInterface.
+ * @param targetIQN the name of the target.
+ * @param portalAddress the portal address (IPv4/IPv6, or DNS name).
+ * @param portalPort the TCP port used to connect to the portal.
+ * @param hostInterface the name of the host interface adapter to use.
+ * @param portalSockaddr the BSD socket structure used to identify the target.
+ * @param hostSockaddr the BSD socket structure used to identify the host. This
+ * specifies the interface that the connection will be bound to.
+ * @param sessionId the session identifier for the new session (returned).
+ * @param connectionId the identifier of the new connection (returned).
+ * @return An error code if a valid session could not be created. */
+IOReturn iSCSIHBAInterfaceCreateSession(iSCSIHBAInterfaceRef interface,
+ CFStringRef targetIQN,
+ CFStringRef portalAddress,
+ CFStringRef portalPort,
+ CFStringRef hostInterface,
+ const struct sockaddr_storage * remoteAddress,
+ const struct sockaddr_storage * localAddress,
+ SessionIdentifier * sessionId,
+ ConnectionIdentifier * connectionId)
+{
+ // Check parameters
+ if(!interface || !portalAddress || !portalPort || !hostInterface || !remoteAddress ||
+ !localAddress || !sessionId || !connectionId)
+ return kIOReturnBadArgument;
+
+ // Pack the input parameters into a single buffer to send to the kernel
+ const int kNumParams = 6;
+ void * params[kNumParams];
+ size_t paramSize[kNumParams];
+
+ // Add one for string lengths to copy the NULL character (CFGetStringLength
+ // does not include the length of the NULL terminator)
+ paramSize[0] = CFStringGetLength(targetIQN) + 1;
+ paramSize[1] = CFStringGetLength(portalAddress) + 1;
+ paramSize[2] = CFStringGetLength(portalPort) + 1;
+ paramSize[3] = CFStringGetLength(hostInterface) + 1;
+ paramSize[4] = sizeof(struct sockaddr_storage);
+ paramSize[5] = sizeof(struct sockaddr_storage);
+
+ // Populate parameters
+ params[0] = malloc(paramSize[0]);
+ params[1] = malloc(paramSize[1]);
+ params[2] = malloc(paramSize[2]);
+ params[3] = malloc(paramSize[3]);
+ params[4] = (void*)remoteAddress;
+ params[5] = (void*)localAddress;
+
+ CFStringGetCString(targetIQN,params[0],paramSize[0],kCFStringEncodingASCII);
+ CFStringGetCString(portalAddress,params[1],paramSize[1],kCFStringEncodingASCII);
+ CFStringGetCString(portalPort,params[2],paramSize[2],kCFStringEncodingASCII);
+ CFStringGetCString(hostInterface,params[3],paramSize[3],kCFStringEncodingASCII);
+
+ // The input buffer will first have eight bytes to denote the length of
+ // the portion that follows. So for each of the six input parameters,
+ // we'll have six UInt64 blocks that indicate the size up front.
+ size_t header = kNumParams*sizeof(UInt64);
+ size_t inputStructSize = header;
+
+ CFIndex paramIdx = 0;
+ while(paramIdx < kNumParams) {
+ inputStructSize += paramSize[paramIdx];
+ paramIdx++;
+ }
+
+ UInt8 * inputStruct = (UInt8*)malloc(inputStructSize);
+ UInt8 * inputStructPos = inputStruct + header;
+
+ paramIdx = 0;
+ while(paramIdx < kNumParams) {
+ memcpy(inputStructPos,params[paramIdx],paramSize[paramIdx]);
+ inputStructPos += paramSize[paramIdx];
+
+ UInt64 * header = (UInt64*)(inputStruct + sizeof(UInt64)*paramIdx);
+ *header = paramSize[paramIdx];
+ paramIdx++;
+ }
+
+ const UInt32 inputCnt = 1;
+ UInt64 inputs[inputCnt];
+ inputs[0] = kNumParams;
+
+ const UInt32 expOutputCnt = 3;
+ UInt64 output[expOutputCnt];
+ UInt32 outputCnt = expOutputCnt;
+
+ kern_return_t result =
+ IOConnectCallMethod(interface->connect,kiSCSICreateSession,inputs,inputCnt,
+ inputStruct,inputStructSize,output,&outputCnt,0,0);
+
+ // Free allocated memory
+ free(params[0]);
+ free(params[1]);
+ free(params[2]);
+ free(params[3]);
+ free(inputStruct);
+
+ if(result == kIOReturnSuccess && outputCnt == expOutputCnt) {
+ *sessionId = (UInt16)output[0];
+ *connectionId = (UInt32)output[1];
+
+ IOReturn error = (IOReturn)output[2];
+ return error;
+ }
+
+ return result;
+}
+
+/*! Releases an iSCSI session, including all connections associated with that
+ * session.
+ * @param interface an instance of an iSCSIHBAInterface.
+ * @param sessionId the session qualifier part of the ISID.
+ * @return error code indicating result of operation. */
+IOReturn iSCSIHBAInterfaceReleaseSession(iSCSIHBAInterfaceRef interface,
+ SessionIdentifier sessionId)
+{
+ // Check parameters
+ if(!interface || sessionId == kiSCSIInvalidSessionId)
+ return kIOReturnBadArgument;
+
+ // Tell the kernel to drop this session and all of its related resources
+ const UInt32 inputCnt = 1;
+ UInt64 input = sessionId;
+
+ return IOConnectCallScalarMethod(interface->connect,kiSCSIReleaseSession,&input,inputCnt,0,0);
+}
+
+/*! Sets parameter associated with a particular session.
+ * @param interface an instance of an iSCSIHBAInterface.
+ * @param sessionId the qualifier part of the ISID (see RFC3720).
+ * @param parameter the parameter to set.
+ * @param paramVal the value for the specified parameter.
+ * @param paramSize the size, in bytes of paramVal.
+ * @return error code indicating result of operation. */
+IOReturn iSCSIHBAInterfaceSetSessionParameter(iSCSIHBAInterfaceRef interface,
+ SessionIdentifier sessionId,
+ enum iSCSIHBASessionParameters parameter,
+ void * paramVal,
+ size_t paramSize)
+{
+ // Check parameters
+ if(!interface || sessionId == kiSCSIInvalidSessionId || !paramVal || paramSize == 0)
+ return kIOReturnBadArgument;
+
+ UInt64 paramValCopy = 0;
+ memcpy(¶mValCopy,paramVal,paramSize);
+
+ const UInt32 inputCnt = 3;
+ const UInt64 input[] = {sessionId,parameter,paramValCopy};
+
+ return IOConnectCallScalarMethod(interface->connect,kiSCSISetSessionParameter,input,inputCnt,0,0);
+}
+
+/*! Gets parameter associated with a particular session.
+ * @param interface an instance of an iSCSIHBAInterface.
+ * @param sessionId the qualifier part of the ISID (see RFC3720).
+ * @param parameter the parameter to get.
+ * @param paramVal the returned value for the specified parameter.
+ * @param paramSize the size, in bytes of paramVal.
+ * @return error code indicating result of operation. */
+IOReturn iSCSIHBAInterfaceGetSessionParameter(iSCSIHBAInterfaceRef interface,
+ SessionIdentifier sessionId,
+ enum iSCSIHBASessionParameters parameter,
+ void * paramVal,
+ size_t paramSize)
+{
+ // Check parameters
+ if(!interface || sessionId == kiSCSIInvalidSessionId || !paramVal || paramSize == 0)
+ return kIOReturnBadArgument;
+
+ const UInt32 inputCnt = 2;
+ const UInt64 input[] = {sessionId,parameter};
+
+ UInt32 outputCnt = 1;
+ UInt64 output;
+
+ kern_return_t error = IOConnectCallScalarMethod(interface->connect,kiSCSIGetSessionParameter,
+ input,inputCnt,&output,&outputCnt);
+
+ if(error == kIOReturnSuccess)
+ memcpy(paramVal,&output,paramSize);
+
+ return error;
+}
+
+/*! Allocates an additional iSCSI connection for a particular session.
+ * @param interface an instance of an iSCSIHBAInterface.
+ * @param sessionId the session to create a new connection for.
+ * @param portalAddress the portal address (IPv4/IPv6, or DNS name).
+ * @param portalPort the TCP port used to connect to the portal.
+ * @param hostInterface the name of the host interface adapter to use.
+ * @param portalSockaddr the BSD socket structure used to identify the target.
+ * @param hostSockaddr the BSD socket structure used to identify the host. This
+ * specifies the interface that the connection will be bound to.
+ * @param connectionId the identifier of the new connection.
+ * @return error code indicating result of operation. */
+IOReturn iSCSIHBAInterfaceCreateConnection(iSCSIHBAInterfaceRef interface,
+ SessionIdentifier sessionId,
+ CFStringRef portalAddress,
+ CFStringRef portalPort,
+ CFStringRef hostInterface,
+ const struct sockaddr_storage * remoteAddress,
+ const struct sockaddr_storage * localAddress,
+ ConnectionIdentifier * connectionId)
+{
+ // Check parameters
+ if(!interface || sessionId == kiSCSIInvalidSessionId || !portalAddress || !portalPort || !hostInterface || !remoteAddress || !connectionId)
+ return kIOReturnBadArgument;
+
+ // Pack the input parameters into a single buffer to send to the kernel
+ const int kNumParams = 5;
+
+ void * params[kNumParams];
+ size_t paramSize[kNumParams];
+
+ // Add one for string lengths to copy the NULL character (CFGetStringLength
+ // does not include the length of the NULL terminator)
+ paramSize[0] = CFStringGetLength(portalAddress) + 1;
+ paramSize[1] = CFStringGetLength(portalPort) + 1;
+ paramSize[2] = CFStringGetLength(hostInterface) + 1;
+ paramSize[3] = sizeof(struct sockaddr_storage);
+ paramSize[4] = sizeof(struct sockaddr_storage);
+
+ params[0] = malloc(paramSize[0]);
+ params[1] = malloc(paramSize[1]);
+ params[2] = malloc(paramSize[2]);
+ params[3] = (void*)remoteAddress;
+ params[4] = (void*)localAddress;
+
+ CFStringGetCString(portalAddress,params[0],paramSize[0],kCFStringEncodingASCII);
+ CFStringGetCString(portalPort,params[1],paramSize[1],kCFStringEncodingASCII);
+ CFStringGetCString(hostInterface,params[2],paramSize[2],kCFStringEncodingASCII);
+
+ // The input buffer will first have eight bytes to denote the length of
+ // the portion that follows. So for each of the six input parameters,
+ // we'll have six UInt64 blocks that indicate the size up front.
+ size_t header = kNumParams*sizeof(UInt64);
+ size_t inputStructSize = header;
+
+ CFIndex paramIdx = 0;
+ while(paramIdx < kNumParams) {
+ inputStructSize += paramSize[paramIdx];
+ paramIdx++;
+ }
+
+ UInt8 * inputStruct = (UInt8*)malloc(inputStructSize);
+ UInt8 * inputStructPos = inputStruct + header;
+
+ paramIdx = 0;
+ while(paramIdx < kNumParams) {
+ memcpy(inputStructPos,params[paramIdx],paramSize[paramIdx]);
+ inputStructPos += paramSize[paramIdx];
+
+ UInt64 * header = (UInt64*)(inputStruct + sizeof(UInt64)*paramIdx);
+ *header = paramSize[paramIdx];
+ paramIdx++;
+ }
+
+ // Tell the kernel to drop this session and all of its related resources
+ const UInt32 inputCnt = 2;
+ const UInt64 inputs[] = {sessionId,kNumParams};
+
+ const UInt32 expOutputCnt = 2;
+ UInt64 output[expOutputCnt];
+ UInt32 outputCnt = expOutputCnt;
+
+ kern_return_t result =
+ IOConnectCallMethod(interface->connect,kiSCSICreateConnection,inputs,inputCnt,inputStruct,
+ inputStructSize,output,&outputCnt,0,0);
+
+ // Free memory
+ free(params[0]);
+ free(params[1]);
+ free(params[2]);
+
+ if(result == kIOReturnSuccess && outputCnt == expOutputCnt) {
+ *connectionId = (UInt32)output[0];
+ IOReturn error = (IOReturn)output[1];
+
+ return error;
+ }
+
+ return result;
+}
+
+/*! Frees a given iSCSI connection associated with a given session.
+ * The session should be logged out using the appropriate PDUs.
+ * @param interface an instance of an iSCSIHBAInterface.
+ * @return error code indicating result of operation. */
+IOReturn iSCSIHBAInterfaceReleaseConnection(iSCSIHBAInterfaceRef interface,
+ SessionIdentifier sessionId,
+ ConnectionIdentifier connectionId)
+{
+ // Check parameters
+ if(!interface || sessionId == kiSCSIInvalidSessionId || connectionId == kiSCSIInvalidConnectionId)
+ return kIOReturnBadArgument;
+
+ // Tell kernel to drop this connection
+ const UInt32 inputCnt = 2;
+ UInt64 inputs[] = {sessionId,connectionId};
+
+ return IOConnectCallScalarMethod(interface->connect,kiSCSIReleaseConnection,inputs,inputCnt,0,0);
+}
+
+/*! Sends data over a kernel socket associated with iSCSI.
+ * @param interface an instance of an iSCSIHBAInterface.
+ * @param sessionId the qualifier part of the ISID (see RFC3720).
+ * @param connectionId the connection associated with the session.
+ * @param bhs the basic header segment to send over the connection.
+ * @param data the data segment of the PDU to send over the connection.
+ * @param length the length of the data block to send over the connection.
+ * @return error code indicating result of operation. */
+IOReturn iSCSIHBAInterfaceSend(iSCSIHBAInterfaceRef interface,
+ SessionIdentifier sessionId,
+ ConnectionIdentifier connectionId,
+ iSCSIPDUInitiatorBHS * bhs,
+ void * data,
+ size_t length)
+{
+ // Check parameters
+ if(!interface || sessionId == kiSCSIInvalidSessionId || connectionId == kiSCSIInvalidConnectionId || !bhs || (!data && length > 0))
+ return kIOReturnBadArgument;
+
+ // Setup input scalar array
+ const UInt32 inputCnt = 2;
+ const UInt64 inputs[] = {sessionId, connectionId};
+
+ // Call kernel method to send (buffer) bhs and then data
+ kern_return_t result;
+ result = IOConnectCallStructMethod(interface->connect,kiSCSISendBHS,bhs,
+ sizeof(iSCSIPDUInitiatorBHS),NULL,NULL);
+
+ if(result != kIOReturnSuccess)
+ return result;
+
+ return IOConnectCallMethod(interface->connect,kiSCSISendData,inputs,inputCnt,
+ data,length,NULL,NULL,NULL,NULL);
+}
+
+/*! Receives data over a kernel socket associated with iSCSI.
+ * @param interface an instance of an iSCSIHBAInterface.
+ * @param sessionId the qualifier part of the ISID (see RFC3720).
+ * @param connectionId the connection associated with the session.
+ * @param bhs the basic header segment received over the connection.
+ * @param data the data segment of the PDU received over the connection.
+ * @param length the length of the data block received.
+ * @return error code indicating result of operation. */
+IOReturn iSCSIHBAInterfaceReceive(iSCSIHBAInterfaceRef interface,
+ SessionIdentifier sessionId,
+ ConnectionIdentifier connectionId,
+ iSCSIPDUTargetBHS * bhs,
+ void ** data,
+ size_t * length)
+{
+ // Check parameters
+ if(!interface || sessionId == kiSCSIInvalidSessionId || connectionId == kiSCSIInvalidConnectionId || !bhs)
+ return kIOReturnBadArgument;
+
+ // Setup input scalar array
+ const UInt32 inputCnt = 2;
+ UInt64 inputs[] = {sessionId,connectionId};
+
+ size_t bhsLength = sizeof(iSCSIPDUTargetBHS);
+
+ // Call kernel method to determine how much data there is to receive
+ // The inputs are the sesssion qualifier and connection ID
+ // The output is the size of the buffer we need to allocate to hold the data
+ kern_return_t result;
+ result = IOConnectCallMethod(interface->connect,kiSCSIRecvBHS,inputs,inputCnt,NULL,0,
+ NULL,NULL,bhs,&bhsLength);
+
+ if(result != kIOReturnSuccess)
+ return result;
+
+ // Determine how much data to allocate for the data buffer
+ *length = iSCSIPDUGetDataSegmentLength((iSCSIPDUCommonBHS *)bhs);
+
+ // If no data, were done at this point
+ if(*length == 0)
+ return 0;
+
+ *data = iSCSIPDUDataCreate(*length);
+
+ if(*data == NULL)
+ return kIOReturnIOError;
+
+ // Call kernel method to get data from a receive buffer
+ result = IOConnectCallMethod(interface->connect,kiSCSIRecvData,inputs,inputCnt,NULL,0,
+ NULL,NULL,*data,length);
+
+ // If we failed, free the temporary buffer and quit with error
+ if(result != kIOReturnSuccess)
+ iSCSIPDUDataRelease(data);
+
+ return result;
+}
+
+/*! Sets parameter associated with a particular connection.
+ * @param interface an instance of an iSCSIHBAInterface.
+ * @param sessionId the qualifier part of the ISID (see RFC3720).
+ * @param connectionId the connection associated with the session.
+ * @param parameter the parameter to set.
+ * @param paramVal the value for the specified parameter.
+ * @param paramSize the size, in bytes of paramVal.
+ * @return error code indicating result of operation. */
+IOReturn iSCSIHBAInterfaceSetConnectionParameter(iSCSIHBAInterfaceRef interface,
+ SessionIdentifier sessionId,
+ ConnectionIdentifier connectionId,
+ enum iSCSIHBAConnectionParameters parameter,
+ void * paramVal,
+ size_t paramSize)
+{
+ // Check parameters
+ if(!interface || sessionId == kiSCSIInvalidSessionId || connectionId == kiSCSIInvalidConnectionId || !paramVal || paramSize == 0)
+ return kIOReturnBadArgument;
+
+ UInt64 paramValCopy = 0;
+ memcpy(¶mValCopy,paramVal,paramSize);
+
+ const UInt32 inputCnt = 4;
+ const UInt64 inputs[] = {sessionId,connectionId,parameter,paramValCopy};
+
+ return IOConnectCallScalarMethod(interface->connect,kiSCSISetConnectionParameter,inputs,inputCnt,0,0);
+}
+
+/*! Gets parameter associated with a particular connection.
+ * @param interface an instance of an iSCSIHBAInterface.
+ * @param sessionId the qualifier part of the ISID (see RFC3720).
+ * @param connectionId the connection associated with the session.
+ * @param parameter the parameter to get.
+ * @param paramVal the returned value for the specified parameter.
+ * @param paramSize the size, in bytes of paramVal.
+ * @return error code indicating result of operation. */
+IOReturn iSCSIHBAInterfaceGetConnectionParameter(iSCSIHBAInterfaceRef interface,
+ SessionIdentifier sessionId,
+ ConnectionIdentifier connectionId,
+ enum iSCSIHBAConnectionParameters parameter,
+ void * paramVal,
+ size_t paramSize)
+{
+ // Check parameters
+ if(!interface || sessionId == kiSCSIInvalidSessionId || connectionId == kiSCSIInvalidConnectionId || !paramVal || paramSize == 0)
+ return kIOReturnBadArgument;
+
+ const UInt32 inputCnt = 3;
+ const UInt64 input[] = {sessionId,connectionId,parameter};
+
+ UInt32 outputCnt = 1;
+ UInt64 output;
+
+ kern_return_t error = IOConnectCallScalarMethod(interface->connect,kiSCSIGetConnectionParameter,
+ input,inputCnt,&output,&outputCnt);
+
+ if(error == kIOReturnSuccess)
+ memcpy(paramVal,&output,paramSize);
+
+ return error;
+}
+
+/*! Activates an iSCSI connection associated with a session.
+ * @param interface an instance of an iSCSIHBAInterface.
+ * @param sessionId session associated with connection to activate.
+ * @param connectionId connection to activate.
+ * @return error code inidicating result of operation. */
+IOReturn iSCSIHBAInterfaceActivateConnection(iSCSIHBAInterfaceRef interface,
+ SessionIdentifier sessionId,
+ ConnectionIdentifier connectionId)
+{
+ // Check parameters
+ if(!interface || sessionId == kiSCSIInvalidSessionId || connectionId == kiSCSIInvalidConnectionId)
+ return kIOReturnBadArgument;
+
+ // Tell kernel to drop this connection
+ const UInt32 inputCnt = 2;
+ UInt64 inputs[] = {sessionId,connectionId};
+
+ return IOConnectCallScalarMethod(interface->connect,kiSCSIActivateConnection,
+ inputs,inputCnt,NULL,NULL);
+}
+
+/*! Activates all iSCSI connections associated with a session.
+ * @param interface an instance of an iSCSIHBAInterface.
+ * @param sessionId session associated with connection to activate.
+ * @return error code inidicating result of operation. */
+IOReturn iSCSIHBAInterfaceActivateAllConnections(iSCSIHBAInterfaceRef interface,
+ SessionIdentifier sessionId)
+{
+ // Check parameters
+ if(!interface || sessionId == kiSCSIInvalidSessionId)
+ return kIOReturnBadArgument;
+
+ const UInt32 inputCnt = 1;
+ UInt64 input = sessionId;
+
+ return IOConnectCallScalarMethod(interface->connect,kiSCSIActivateAllConnections,
+ &input,inputCnt,NULL,NULL);
+}
+
+/*! Dectivates an iSCSI connection associated with a session.
+ * @param interface an instance of an iSCSIHBAInterface.
+ * @param sessionId session associated with connection to deactivate.
+ * @param connectionId connection to deactivate.
+ * @return error code inidicating result of operation. */
+IOReturn iSCSIHBAInterfaceDeactivateConnection(iSCSIHBAInterfaceRef interface,
+ SessionIdentifier sessionId,
+ ConnectionIdentifier connectionId)
+{
+ // Check parameters
+ if(!interface || sessionId == kiSCSIInvalidSessionId || connectionId == kiSCSIInvalidConnectionId)
+ return kIOReturnBadArgument;
+
+ // Tell kernel to drop this connection
+ const UInt32 inputCnt = 2;
+ UInt64 inputs[] = {sessionId,connectionId};
+
+ return IOConnectCallScalarMethod(interface->connect,kiSCSIDeactivateConnection,
+ inputs,inputCnt,NULL,NULL);
+}
+
+/*! Dectivates all iSCSI sessions associated with a session.
+ * @param interface an instance of an iSCSIHBAInterface.
+ * @param sessionId session associated with connections to deactivate.
+ * @return error code inidicating result of operation. */
+IOReturn iSCSIHBAInterfaceDeactivateAllConnections(iSCSIHBAInterfaceRef interface,
+ SessionIdentifier sessionId)
+{
+ // Check parameters
+ if(!interface || sessionId == kiSCSIInvalidSessionId)
+ return kIOReturnBadArgument;
+
+ const UInt32 inputCnt = 1;
+ UInt64 input = sessionId;
+
+ return IOConnectCallScalarMethod(interface->connect,kiSCSIDeactivateAllConnections,
+ &input,inputCnt,NULL,NULL);
+}
+
+/*! Gets the first connection (the lowest connectionId) for the
+ * specified session.
+ * @param interface an instance of an iSCSIHBAInterface.
+ * @param sessionId obtain an connectionId for this session.
+ * @param connectionId the identifier of the connection.
+ * @return error code indicating result of operation. */
+IOReturn iSCSIHBAInterfaceGetConnection(iSCSIHBAInterfaceRef interface,
+ SessionIdentifier sessionId,
+ ConnectionIdentifier * connectionId)
+{
+ // Check parameters
+ if(!interface || sessionId == kiSCSIInvalidSessionId || !connectionId)
+ return kIOReturnBadArgument;
+
+ const UInt32 inputCnt = 1;
+ UInt64 input = sessionId;
+
+ const UInt32 expOutputCnt = 1;
+ UInt64 output[expOutputCnt];
+ UInt32 outputCnt = expOutputCnt;
+
+ kern_return_t result =
+ IOConnectCallScalarMethod(interface->connect,kiSCSIGetConnection,&input,inputCnt,
+ output,&outputCnt);
+
+ if(result == kIOReturnSuccess && outputCnt == expOutputCnt)
+ *connectionId = (UInt32)output[0];
+
+ return result;
+}
+
+/*! Gets the connection count for the specified session.
+ * @param interface an instance of an iSCSIHBAInterface.
+ * @param sessionId obtain the connection count for this session.
+ * @param numConnections the connection count.
+ * @return error code indicating result of operation. */
+IOReturn iSCSIHBAInterfaceGetNumConnections(iSCSIHBAInterfaceRef interface,
+ SessionIdentifier sessionId,
+ UInt32 * numConnections)
+{
+ // Check parameters
+ if(!interface || sessionId == kiSCSIInvalidSessionId || !numConnections)
+ return kIOReturnBadArgument;
+
+ const UInt32 inputCnt = 1;
+ UInt64 input = sessionId;
+
+ const UInt32 expOutputCnt = 1;
+ UInt64 output[expOutputCnt];
+ UInt32 outputCnt = expOutputCnt;
+
+ kern_return_t result = IOConnectCallScalarMethod(
+ interface->connect,kiSCSIGetNumConnections,&input,inputCnt,output,&outputCnt);
+
+ if(result == kIOReturnSuccess && outputCnt == expOutputCnt)
+ *numConnections = (UInt32)output[0];
+
+ return result;
+}
+
+/*! Looks up the session identifier associated with a particular target name.
+ * @param interface an instance of an iSCSIHBAInterface.
+ * @param targetIQN the IQN name of the target (e.q., iqn.2015-01.com.example)
+ * @return sessionId the session identifier. */
+SessionIdentifier iSCSIHBAInterfaceGetSessionIdForTargetIQN(iSCSIHBAInterfaceRef interface,
+ CFStringRef targetIQN)
+{
+ if(!interface || !targetIQN)
+ return kiSCSIInvalidSessionId;
+
+ const UInt32 expOutputCnt = 1;
+ UInt64 output[expOutputCnt];
+ UInt32 outputCnt = expOutputCnt;
+
+ const int targetIQNBufferSize = (int)CFStringGetLength(targetIQN)+1;
+ char * targetIQNBuffer = (char *)malloc(targetIQNBufferSize);
+ if(!CFStringGetCString(targetIQN,targetIQNBuffer,targetIQNBufferSize,kCFStringEncodingASCII))
+ {
+ free(targetIQNBuffer);
+ return kiSCSIInvalidSessionId;
+ }
+
+ kern_return_t result = IOConnectCallMethod(
+ interface->connect,
+ kiSCSIGetSessionIdForTargetIQN,0,0,
+ targetIQNBuffer,
+ targetIQNBufferSize,
+ output,&outputCnt,0,0);
+
+ free(targetIQNBuffer);
+
+ if(result == kIOReturnSuccess && outputCnt == expOutputCnt)
+ return (SessionIdentifier)output[0];
+
+ return kiSCSIInvalidSessionId;
+}
+
+/*! Looks up the connection identifier associated with a particular portal address.
+ * @param interface an instance of an iSCSIHBAInterface.
+ * @param sessionId the session identifier.
+ * @param portalAddress the address passed to iSCSIHBAInterfaceCreateSession() or
+ * iSCSIHBAInterfaceCreateConnection() when the connection was created.
+ * @return the associated connection identifier. */
+ConnectionIdentifier iSCSIHBAInterfaceGetConnectionIdForPortalAddress(iSCSIHBAInterfaceRef interface,
+ SessionIdentifier sessionId,
+ CFStringRef portalAddress)
+{
+ if(!interface || sessionId == kiSCSIInvalidSessionId || !portalAddress)
+ return kIOReturnBadArgument;
+
+ const UInt32 inputCnt = 1;
+ UInt64 input = sessionId;
+
+ const UInt32 expOutputCnt = 1;
+ UInt64 output[expOutputCnt];
+ UInt32 outputCnt = expOutputCnt;
+
+ const int portalAddressBufferSize = (int)CFStringGetLength(portalAddress)+1;
+ char * portalAddressBuffer = (char*)malloc(portalAddressBufferSize);
+ if(!CFStringGetCString(portalAddress,portalAddressBuffer,portalAddressBufferSize,kCFStringEncodingASCII))
+ {
+ free(portalAddressBuffer);
+ return kIOReturnBadArgument;
+ }
+
+ kern_return_t result =
+ IOConnectCallMethod(interface->connect,kiSCSIGetConnectionIdForPortalAddress,
+ &input,inputCnt,
+ portalAddressBuffer,
+ portalAddressBufferSize,
+ output,&outputCnt,0,0);
+
+ free(portalAddressBuffer);
+
+ if(result != kIOReturnSuccess || outputCnt != expOutputCnt)
+ return kiSCSIInvalidConnectionId;
+
+ return (ConnectionIdentifier)output[0];
+}
+
+/*! Gets an array of session identifiers for each session.
+ * @param interface an instance of an iSCSIHBAInterface.
+ * @param sessionIds an array of session identifiers. This MUST be large
+ * enough to hold the maximum number of sessions (kiSCSIMaxSessions).
+ * @param sessionCount number of session identifiers.
+ * @return error code indicating result of operation. */
+IOReturn iSCSIHBAInterfaceGetSessionIds(iSCSIHBAInterfaceRef interface,
+ SessionIdentifier * sessionIds,
+ UInt16 * sessionCount)
+{
+ if(!interface || !sessionIds || !sessionCount)
+ return kIOReturnBadArgument;
+
+ const UInt32 expOutputCnt = 1;
+ UInt64 output;
+ UInt32 outputCnt = expOutputCnt;
+
+ *sessionCount = 0;
+ size_t outputStructSize = sizeof(SessionIdentifier)*kiSCSIMaxSessions;
+
+ kern_return_t result =
+ IOConnectCallMethod(interface->connect,kiSCSIGetSessionIds,0,0,0,0,
+ &output,&outputCnt,sessionIds,&outputStructSize);
+
+ if(result == kIOReturnSuccess && outputCnt == expOutputCnt)
+ *sessionCount = (UInt16)output;
+
+ return result;
+}
+
+/*! Gets an array of connection identifiers for each session.
+ * @param interface an instance of an iSCSIHBAInterface.
+ * @param sessionId session identifier.
+ * @param connectionIds an array of connection identifiers for the session.
+ * @param connectionCount number of connection identifiers.
+ * @return error code indicating result of operation. */
+IOReturn iSCSIHBAInterfaceGetConnectionIds(iSCSIHBAInterfaceRef interface,
+ SessionIdentifier sessionId,
+ ConnectionIdentifier * connectionIds,
+ UInt32 * connectionCount)
+{
+ if(!interface || sessionId == kiSCSIInvalidSessionId || !connectionIds || !connectionCount)
+ return kIOReturnBadArgument;
+
+ const UInt32 inputCnt = 1;
+ UInt64 input = sessionId;
+
+ const UInt32 expOutputCnt = 1;
+ UInt64 output;
+ UInt32 outputCnt = expOutputCnt;
+
+ *connectionCount = 0;
+ size_t outputStructSize = sizeof(ConnectionIdentifier)*kiSCSIMaxConnectionsPerSession;
+
+ kern_return_t result =
+ IOConnectCallMethod(interface->connect,kiSCSIGetConnectionIds,&input,inputCnt,0,0,
+ &output,&outputCnt,connectionIds,&outputStructSize);
+
+ if(result == kIOReturnSuccess && outputCnt == expOutputCnt)
+ *connectionCount = (UInt32)output;
+
+ return result;
+}
+
+/*! Creates a string containing the target IQN associated with a session.
+ * @param interface an instance of an iSCSIHBAInterface.
+ * @param sessionId session identifier.
+ * @param targetIQN the name of the target.
+ * @param size the size of the targetIQNCString buffer.
+ * @return error code indicating result of operation. */
+CFStringRef iSCSIHBAInterfaceCreateTargetIQNForSessionId(iSCSIHBAInterfaceRef interface,
+ SessionIdentifier sessionId)
+{
+ if(!interface || sessionId == kiSCSIInvalidSessionId)
+ return NULL;
+
+ const UInt32 inputCnt = 1;
+ UInt64 input = sessionId;
+
+ const char targetIQN[NI_MAXHOST];
+ size_t targetIQNLength = NI_MAXHOST;
+
+ kern_return_t result = IOConnectCallMethod(interface->connect,kiSCSICreateTargetIQNForSessionId,
+ &input,inputCnt,0,0,0,0,
+ (void*)targetIQN,&targetIQNLength);
+ if(result != kIOReturnSuccess)
+ return NULL;
+
+ return CFStringCreateWithCString(kCFAllocatorDefault,targetIQN,kCFStringEncodingASCII);
+}
+
+/*! Creates a string containing the address of the portal associated with
+ * the specified connection.
+ * @param interface an instance of an iSCSIHBAInterface.
+ * @param sessionId session identifier.
+ * @param connectionId connection identifier.
+ * @return a string containing the portal address, or NULL if the session or
+ * connection was invalid. */
+CFStringRef iSCSIHBAInterfaceCreatePortalAddressForConnectionId(iSCSIHBAInterfaceRef interface,
+ SessionIdentifier sessionId,
+ ConnectionIdentifier connectionId)
+{
+ if(!interface || sessionId == kiSCSIInvalidSessionId || connectionId == kiSCSIInvalidConnectionId)
+ return NULL;
+
+ const UInt32 inputCnt = 2;
+ UInt64 input[] = {sessionId,connectionId};
+
+ const char portalAddress[NI_MAXHOST];
+ size_t portalAddressLength = NI_MAXHOST;
+
+ kern_return_t result = IOConnectCallMethod(interface->connect,kiSCSIGetPortalAddressForConnectionId,
+ input,inputCnt,0,0,0,0,
+ (void *)portalAddress,&portalAddressLength);
+ if(result != kIOReturnSuccess)
+ return NULL;
+
+ return CFStringCreateWithCString(kCFAllocatorDefault,portalAddress,kCFStringEncodingASCII);
+}
+
+/*! Creates a string containing the TCP port of the portal associated with
+ * the specified connection.
+ * @param interface an instance of an iSCSIHBAInterface.
+ * @param sessionId session identifier.
+ * @param connectionId connection identifier.
+ * @return a string containing the TCP port of the portal, or NULL if the
+ * session or connection was invalid. */
+CFStringRef iSCSIHBAInterfaceCreatePortalPortForConnectionId(iSCSIHBAInterfaceRef interface,
+ SessionIdentifier sessionId,
+ ConnectionIdentifier connectionId)
+{
+ if(!interface || sessionId == kiSCSIInvalidSessionId || connectionId == kiSCSIInvalidConnectionId)
+ return NULL;
+
+ const UInt32 inputCnt = 2;
+ UInt64 input[] = {sessionId,connectionId};
+
+ const char portalPort[NI_MAXSERV];
+ size_t portalPortLength = NI_MAXSERV;
+
+ kern_return_t result = IOConnectCallMethod(interface->connect,kiSCSIGetPortalPortForConnectionId,
+ input,inputCnt,0,0,0,0,
+ (void *)portalPort,&portalPortLength);
+ if(result != kIOReturnSuccess)
+ return NULL;
+
+ return CFStringCreateWithCString(kCFAllocatorDefault,portalPort,kCFStringEncodingASCII);
+}
+
+/*! Creates a string containing the host interface used for the connection.
+ * @param interface an instance of an iSCSIHBAInterface.
+ * @param sessionId session identifier.
+ * @param connectionId connection identifier.
+ * @return a string containing the host interface name, or NULL if the
+ * session or connection was invalid. */
+CFStringRef iSCSIHBAInterfaceCreateHostInterfaceForConnectionId(iSCSIHBAInterfaceRef interface,
+ SessionIdentifier sessionId,
+ ConnectionIdentifier connectionId)
+{
+ if(!interface || sessionId == kiSCSIInvalidSessionId || connectionId == kiSCSIInvalidConnectionId)
+ return NULL;
+
+ const UInt32 inputCnt = 2;
+ UInt64 input[] = {sessionId,connectionId};
+
+
+ const char hostInterface[NI_MAXHOST];
+ size_t hostInterfaceLength = NI_MAXHOST;
+
+ kern_return_t result = IOConnectCallMethod(interface->connect,kiSCSIGetHostInterfaceForConnectionId,
+ input,inputCnt,0,0,0,0,
+ (void *)hostInterface,&hostInterfaceLength);
+ if(result != kIOReturnSuccess)
+ return NULL;
+
+ return CFStringCreateWithCString(kCFAllocatorDefault,hostInterface,kCFStringEncodingASCII);
+}
\ No newline at end of file
diff --git a/Source/User/iscsid/iSCSIHBAInterface.h b/Source/User/iscsid/iSCSIHBAInterface.h
new file mode 100644
index 00000000..13cf8d3c
--- /dev/null
+++ b/Source/User/iscsid/iSCSIHBAInterface.h
@@ -0,0 +1,390 @@
+/*
+ * Copyright (c) 2016, Nareg Sinenian
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INConnectionIdentifierENTAL, 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.
+ */
+
+#ifndef __ISCSI_HBA_INTERFACE_H__
+#define __ISCSI_HBA_INTERFACE_H__
+
+#include "iSCSIHBATypes.h"
+#include "iSCSITypesShared.h"
+#include "iSCSIPDUShared.h"
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+
+typedef struct __iSCSIHBAInterface * iSCSIHBAInterfaceRef;
+
+/*! Notification context that is used when creating a new HBA
+ * instance. This struct is used to pass user-defined data
+ * when the iSCSIHBANotification callback functions are called. */
+typedef struct __iSCSIHBANotificationContext {
+
+ /*! Version of this struct (set to 0). */
+ CFIndex version;
+
+ /*! User-defined data. */
+ void * info;
+
+ /*! Retain callback function (may be NULL). */
+ CFAllocatorRetainCallBack retain;
+
+ /*! Release callback function (may be NULL). */
+ CFAllocatorReleaseCallBack release;
+
+ /*! Copy description callback function (may be NULL). */
+ CFAllocatorCopyDescriptionCallBack copyDescription;
+
+} iSCSIHBANotificationContext;
+
+
+/*! Callback function used to relay notifications from the kernel. */
+typedef void (*iSCSIHBANotificationCallBack)(iSCSIHBAInterfaceRef interface,
+ enum iSCSIHBANotificationTypes type,
+ iSCSIHBANotificationMessage * msg,
+ void * info);
+
+/*! Opens a connection to the iSCSI initiator. A connection must be
+ * successfully opened before any of the supporting functions below can be
+ * called. A callback function is used to process notifications from the
+ * iSCSI kernel extension.
+ * @param allocator the allocator to use.
+ * @param callback the callback function to process notifications.
+ * @return a new iSCSI HBA interface or NULL if one could not be created. */
+iSCSIHBAInterfaceRef iSCSIHBAInterfaceCreate(CFAllocatorRef allocator,
+ iSCSIHBANotificationCallBack callback,
+ iSCSIHBANotificationContext * context);
+
+/*! Closes a connection to the iSCSI initiator.
+ * @return error code indicating the result of the operation. */
+void iSCSIHBAInterfaceRelease(iSCSIHBAInterfaceRef interface);
+
+/*! Schedules execution of various tasks, including handling of kernel notifications
+ * on for the specified interface instance over the designated runloop.
+ * @param interface an instance of an iSCSIHBAInterface.
+ * @param runLoop the runloop to schedule
+ * @param runLoopMode the execution mode for the runLoop. */
+void iSCSIHBAInterfaceScheduleWithRunloop(iSCSIHBAInterfaceRef interface,
+ CFRunLoopRef runLoop,
+ CFStringRef runLoopMode);
+
+/*! Unschedules execution of various tasks, including handling of kernel notifications
+ * on for the specified interface instance over the designated runloop.
+ * @param interface an instance of an iSCSIHBAInterface.
+ * @param runLoop the runloop to schedule
+ * @param runLoopMode the execution mode for the runLoop. */
+void iSCSIHBAInterfaceUnscheduleWithRunloop(iSCSIHBAInterfaceRef interface,
+ CFRunLoopRef runLoop,
+ CFStringRef runLoopMode);
+
+/*! Allocates a new iSCSI session in the kernel and creates an associated
+ * connection to the target portal. Additional connections may be added to the
+ * session by calling iSCSIHBAInterfaceCreateConnection().
+ * @param interface an instance of an iSCSIHBAInterface.
+ * @param targetIQN the name of the target.
+ * @param portalAddress the portal address (IPv4/IPv6, or DNS name).
+ * @param portalPort the TCP port used to connect to the portal.
+ * @param hostInterface the name of the host interface adapter to use.
+ * @param portalSockaddr the BSD socket structure used to identify the target.
+ * @param hostSockaddr the BSD socket structure used to identify the host. This
+ * specifies the interface that the connection will be bound to.
+ * @param sessionId the session identifier for the new session (returned).
+ * @param connectionId the identifier of the new connection (returned).
+ * @return error code indicating the result of the operation. */
+IOReturn iSCSIHBAInterfaceCreateSession(iSCSIHBAInterfaceRef interface,
+ CFStringRef targetIQN,
+ CFStringRef portalAddress,
+ CFStringRef portalPort,
+ CFStringRef hostInterface,
+ const struct sockaddr_storage * remoteAddress,
+ const struct sockaddr_storage * localAddress,
+ SessionIdentifier * sessionId,
+ ConnectionIdentifier * connectionId);
+
+/*! Releases an iSCSI session, including all connections associated with that
+ * session (there is no requirement to release connections individually).
+ * @param sessionId the session qualifier part of the ISID.
+ * @return error code indicating result of operation. */
+IOReturn iSCSIHBAInterfaceReleaseSession(iSCSIHBAInterfaceRef interface,
+ SessionIdentifier sessionId);
+
+/*! Sets parameter associated with a particular session.
+ * @param interface an instance of an iSCSIHBAInterface.
+ * @param sessionId the qualifier part of the ISID (see RFC3720).
+ * @param parameter the parameter to set.
+ * @param paramVal the value for the specified parameter.
+ * @param paramSize the size, in bytes of paramVal.
+ * @return error code indicating result of operation. */
+IOReturn iSCSIHBAInterfaceSetSessionParameter(iSCSIHBAInterfaceRef interface,
+ SessionIdentifier sessionId,
+ enum iSCSIHBASessionParameters parameter,
+ void * paramVal,
+ size_t paramSize);
+
+/*! Gets parameter associated with a particular session.
+ * @param interface an instance of an iSCSIHBAInterface.
+ * @param sessionId the qualifier part of the ISID (see RFC3720).
+ * @param parameter the parameter to get.
+ * @param paramVal the returned value for the specified parameter.
+ * @param paramSize the size, in bytes of paramVal.
+ * @return error code indicating result of operation. */
+IOReturn iSCSIHBAInterfaceGetSessionParameter(iSCSIHBAInterfaceRef interface,
+ SessionIdentifier sessionId,
+ enum iSCSIHBASessionParameters parameter,
+ void * paramVal,
+ size_t paramSize);
+
+/*! Allocates an additional iSCSI connection for a particular session.
+ * @param interface an instance of an iSCSIHBAInterface.
+ * @param sessionId the qualifier part of the ISID (see RFC3720).
+ * @param portalAddress the portal address (IPv4/IPv6, or DNS name).
+ * @param portalPort the TCP port used to connect to the portal.
+ * @param hostInterface the name of the host interface adapter to use.
+ * @param portalSockaddr the BSD socket structure used to identify the target.
+ * @param hostSockaddr the BSD socket structure used to identify the host. This
+ * specifies the interface that the connection will be bound to.
+ * @param connectionId the identifier of the new connection.
+ * @return error code indicating result of operation. */
+IOReturn iSCSIHBAInterfaceCreateConnection(iSCSIHBAInterfaceRef interface,
+ SessionIdentifier sessionId,
+ CFStringRef portalAddress,
+ CFStringRef portalPort,
+ CFStringRef hostInterface,
+ const struct sockaddr_storage * remoteAddress,
+ const struct sockaddr_storage * localAddress,
+ ConnectionIdentifier * connectionId);
+
+/*! Frees a given iSCSI connection associated with a given session.
+ * The session should be logged out using the appropriate PDUs.
+ * @param interface an instance of an iSCSIHBAInterface.
+ * @param sessionId the qualifier part of the ISID (see RFC3720). */
+IOReturn iSCSIHBAInterfaceReleaseConnection(iSCSIHBAInterfaceRef interface,
+ SessionIdentifier sessionId,
+ ConnectionIdentifier connectionId);
+
+/*! Sends data over a kernel socket associated with iSCSI. The data sent should
+ * be specified by the buffer pointer to by data, with a length given by
+ * length. The size of the buffer (length) should include any padding required
+ * to achieve 4-byte alignment.
+ * @param interface an instance of an iSCSIHBAInterface.
+ * @param sessionId the qualifier part of the ISID (see RFC3720).
+ * @param connectionId the connection associated with the session.
+ * @param bhs the basic header segment to send over the connection.
+ * @param data the data segment of the PDU to send over the connection.
+ * @param length the length of the data block to send over the connection.
+ * @return error code indicating result of operation. */
+IOReturn iSCSIHBAInterfaceSend(iSCSIHBAInterfaceRef interface,
+ SessionIdentifier sessionId,
+ ConnectionIdentifier connectionId,
+ iSCSIPDUInitiatorBHS * bhs,
+ void * data,
+ size_t length);
+
+/*! Receives data over a kernel socket associated with iSCSI. Function will
+ * receive the ENTIRE data segment of a PDU at once, and return the length
+ * of the buffer in length. This length includes any padding required to
+ * achieve 4-byte alignement required of PDUs.
+ * @param interface an instance of an iSCSIHBAInterface.
+ * @param sessionId the qualifier part of the ISID (see RFC3720).
+ * @param connectionId the connection associated with the session.
+ * @param bhs the basic header segment received over the connection.
+ * @param data the data segment of the PDU received over the connection.
+ * @param length the length of the data block received.
+ * @return error code indicating result of operation. */
+IOReturn iSCSIHBAInterfaceReceive(iSCSIHBAInterfaceRef interface,
+ SessionIdentifier sessionId,
+ ConnectionIdentifier connectionId,
+ iSCSIPDUTargetBHS * bhs,
+ void * * data,
+ size_t * length);
+
+/*! Sets parameter associated with a particular connection.
+ * @param interface an instance of an iSCSIHBAInterface.
+ * @param sessionId the qualifier part of the ISID (see RFC3720).
+ * @param connectionId the connection associated with the session.
+ * @param parameter the parameter to set.
+ * @param paramVal the value for the specified parameter.
+ * @param paramSize the size, in bytes of paramVal.
+ * @return error code indicating result of operation. */
+IOReturn iSCSIHBAInterfaceSetConnectionParameter(iSCSIHBAInterfaceRef interface,
+ SessionIdentifier sessionId,
+ ConnectionIdentifier connectionId,
+ enum iSCSIHBAConnectionParameters parameter,
+ void * paramVal,
+ size_t paramSize);
+
+/*! Gets parameter associated with a particular connection.
+ * @param interface an instance of an iSCSIHBAInterface.
+ * @param sessionId the qualifier part of the ISID (see RFC3720).
+ * @param connectionId the connection associated with the session.
+ * @param parameter the parameter to get.
+ * @param paramVal the returned value for the specified parameter.
+ * @param paramSize the size, in bytes of paramVal.
+ * @return error code indicating result of operation. */
+IOReturn iSCSIHBAInterfaceGetConnectionParameter(iSCSIHBAInterfaceRef interface,
+ SessionIdentifier sessionId,
+ ConnectionIdentifier connectionId,
+ enum iSCSIHBAConnectionParameters parameter,
+ void * paramVal,
+ size_t paramSize);
+
+/*! Activates an iSCSI connection associated with a session.
+ * @param interface an instance of an iSCSIHBAInterface.
+ * @param sessionId session associated with connection to activate.
+ * @param connectionId connection to activate.
+ * @return error code indicating result of operation. */
+IOReturn iSCSIHBAInterfaceActivateConnection(iSCSIHBAInterfaceRef interface,
+ SessionIdentifier sessionId,
+ ConnectionIdentifier connectionId);
+
+/*! Activates all iSCSI connections associated with a session.
+ * @param interface an instance of an iSCSIHBAInterface.
+ * @param sessionId session associated with connection to activate.
+ * @return error code inidicating result of operation. */
+IOReturn iSCSIHBAInterfaceActivateAllConnections(iSCSIHBAInterfaceRef interface,
+ SessionIdentifier sessionId);
+
+/*! Dectivates an iSCSI connection associated with a session.
+ * @param interface an instance of an iSCSIHBAInterface.
+ * @param sessionId session associated with connection to deactivate.
+ * @param connectionId connection to deactivate.
+ * @return error code inidicating result of operation. */
+IOReturn iSCSIHBAInterfaceDeactivateConnection(iSCSIHBAInterfaceRef interface,
+ SessionIdentifier sessionId,
+ ConnectionIdentifier connectionId);
+
+/*! Dectivates all iSCSI sessions associated with a session.
+ * @param interface an instance of an iSCSIHBAInterface.
+ * @param sessionId session associated with connections to deactivate.
+ * @return error code inidicating result of operation. */
+IOReturn iSCSIHBAInterfaceDeactivateAllConnections(iSCSIHBAInterfaceRef interface,
+ SessionIdentifier sessionId);
+
+/*! Gets the first connection (the lowest connectionId) for the
+ * specified session.
+ * @param interface an instance of an iSCSIHBAInterface.
+ * @param sessionId obtain an connectionId for this session.
+ * @param connectionId the identifier of the connection.
+ * @return error code indicating result of operation. */
+IOReturn iSCSIHBAInterfaceGetConnection(iSCSIHBAInterfaceRef interface,
+ SessionIdentifier sessionId,
+ ConnectionIdentifier * connectionId);
+
+/*! Gets the connection count for the specified session.
+ * @param interface an instance of an iSCSIHBAInterface.
+ * @param sessionId obtain the connection count for this session.
+ * @param numConnections the connection count.
+ * @return error code indicating result of operation. */
+IOReturn iSCSIHBAInterfaceGetNumConnections(iSCSIHBAInterfaceRef interface,
+ SessionIdentifier sessionId,
+ UInt32 * numConnections);
+
+/*! Looks up the session identifier associated with a particular target name.
+ * @param interface an instance of an iSCSIHBAInterface.
+ * @param targetIQN the IQN name of the target (e.q., iqn.2015-01.com.example)
+ * @return sessionId the session identifier. */
+SessionIdentifier iSCSIHBAInterfaceGetSessionIdForTargetIQN(iSCSIHBAInterfaceRef interface,
+ CFStringRef targetIQN);
+
+/*! Looks up the connection identifier associated with a particular portal address.
+ * @param interface an instance of an iSCSIHBAInterface.
+ * @param sessionId the session identifier.
+ * @param portalAddress the address passed to iSCSIHBAInterfaceCreateSession() or
+ * iSCSIHBAInterfaceCreateConnection() when the connection was created.
+ * @return the associated connection identifier. */
+ConnectionIdentifier iSCSIHBAInterfaceGetConnectionIdForPortalAddress(iSCSIHBAInterfaceRef interface,
+ SessionIdentifier sessionId,
+ CFStringRef portalAddress);
+
+/*! Gets an array of session identifiers for each session.
+ * @param interface an instance of an iSCSIHBAInterface.
+ * @param sessionIds an array of session identifiers.
+ * @param sessionCount number of session identifiers.
+ * @return error code indicating result of operation. */
+IOReturn iSCSIHBAInterfaceGetSessionIds(iSCSIHBAInterfaceRef interface,
+ SessionIdentifier * sessionIds,
+ UInt16 * sessionCount);
+
+/*! Gets an array of connection identifiers for each session.
+ * @param interface an instance of an iSCSIHBAInterface.
+ * @param sessionId session identifier.
+ * @param connectionIds an array of connection identifiers for the session.
+ * @param connectionCount number of connection identifiers.
+ * @return error code indicating result of operation. */
+IOReturn iSCSIHBAInterfaceGetConnectionIds(iSCSIHBAInterfaceRef interface,
+ SessionIdentifier sessionId,
+ ConnectionIdentifier * connectionIds,
+ UInt32 * connectionCount);
+
+/*! Creates a string containing the target IQN associated with a session.
+ * @param interface an instance of an iSCSIHBAInterface.
+ * @param sessionId session identifier.
+ * @param targetIQN the name of the target.
+ * @param size the size of the targetIQNCString buffer.
+ * @return error code indicating result of operation. */
+CFStringRef iSCSIHBAInterfaceCreateTargetIQNForSessionId(iSCSIHBAInterfaceRef interface,
+ SessionIdentifier sessionId);
+
+/*! Creates a string containing the address of the portal associated with
+ * the specified connection.
+ * @param interface an instance of an iSCSIHBAInterface.
+ * @param sessionId session identifier.
+ * @param connectionId connection identifier.
+ * @return a string containing the portal address, or NULL if the session or
+ * connection was invalid. */
+CFStringRef iSCSIHBAInterfaceCreatePortalAddressForConnectionId(iSCSIHBAInterfaceRef interface,
+ SessionIdentifier sessionId,
+ ConnectionIdentifier connectionId);
+
+/*! Creates a string containing the TCP port of the portal associated with
+ * the specified connection.
+ * @param interface an instance of an iSCSIHBAInterface.
+ * @param sessionId session identifier.
+ * @param connectionId connection identifier.
+ * @return a string containing the TCP port of the portal, or NULL if the
+ * session or connection was invalid. */
+CFStringRef iSCSIHBAInterfaceCreatePortalPortForConnectionId(iSCSIHBAInterfaceRef interface,
+ SessionIdentifier sessionId,
+ ConnectionIdentifier connectionId);
+
+/*! Creates a string containing the host interface used for the connection.
+ * @param interface an instance of an iSCSIHBAInterface.
+ * @param sessionId session identifier.
+ * @param connectionId connection identifier.
+ * @return a string containing the host interface name, or NULL if the
+ * session or connection was invalid. */
+CFStringRef iSCSIHBAInterfaceCreateHostInterfaceForConnectionId(iSCSIHBAInterfaceRef interface,
+ SessionIdentifier sessionId,
+ ConnectionIdentifier connectionId);
+
+
+#endif /* defined(__ISCSI_HBA_INTERFACE_H__) */
diff --git a/Source/User/iscsid/iSCSIKernelInterface.c b/Source/User/iscsid/iSCSIKernelInterface.c
index 1b4624da..f236e9f1 100644
--- a/Source/User/iscsid/iSCSIKernelInterface.c
+++ b/Source/User/iscsid/iSCSIKernelInterface.c
@@ -34,9 +34,7 @@
#include
#include
-static io_service_t service;
static io_connect_t connection;
-static CFMachPortContext notificationContext;
static CFMachPortRef notificationPort = NULL;
static iSCSIKernelNotificationCallback callback;
@@ -101,7 +99,7 @@ errno_t iSCSIKernelInitialize(iSCSIKernelNotificationCallback callback)
CFMutableDictionaryRef matchingDict = NULL;
matchingDict = IOServiceMatching(kiSCSIVirtualHBA_IOClassName);
- service = IOServiceGetMatchingService(kIOMasterPortDefault,matchingDict);
+ io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault,matchingDict);
// Check to see if the driver was found in the I/O registry
if(service == IO_OBJECT_NULL)
@@ -109,12 +107,14 @@ errno_t iSCSIKernelInitialize(iSCSIKernelNotificationCallback callback)
// Using the service handle, open a connection
result = IOServiceOpen(service,mach_task_self(),0,&connection);
+
+ // No longer need a reference to the service
+ IOObjectRelease(service);
- if(result != kIOReturnSuccess) {
- IOObjectRelease(service);
+ if(result != kIOReturnSuccess)
return kIOReturnNotFound;
- }
+ CFMachPortContext notificationContext;
notificationContext.info = (void *)¬ificationContext;
notificationContext.version = 0;
notificationContext.release = NULL;
@@ -138,7 +138,6 @@ errno_t iSCSIKernelCleanup()
IOConnectCallScalarMethod(connection,kiSCSICloseInitiator,0,0,0,0);
// Clean up (now that we have a connection we no longer need the object)
- IOObjectRelease(service);
IOServiceClose(connection);
if(notificationPort)
diff --git a/Source/User/iscsid/iSCSIQueryTarget.c b/Source/User/iscsid/iSCSIQueryTarget.c
index da1d6ebd..f348b667 100644
--- a/Source/User/iscsid/iSCSIQueryTarget.c
+++ b/Source/User/iscsid/iSCSIQueryTarget.c
@@ -27,7 +27,7 @@
*/
#include "iSCSIQueryTarget.h"
-#include "iSCSIKernelInterface.h"
+#include "iSCSIHBAInterface.h"
errno_t iSCSISessionLoginSingleQuery(struct iSCSILoginQueryContext * context,
enum iSCSILoginStatusCode * statusCode,
@@ -52,9 +52,8 @@ errno_t iSCSISessionLoginSingleQuery(struct iSCSILoginQueryContext * context,
size_t length = 0;
iSCSIPDUDataCreateFromDict(textCmd,&data,&length);
- errno_t error = iSCSIKernelSend(context->sessionId,context->connectionId,
- (iSCSIPDUInitiatorBHS *)&cmd,
- data,length);
+ errno_t error = iSCSIHBAInterfaceSend(context->interface,context->sessionId,context->connectionId,
+ (iSCSIPDUInitiatorBHS *)&cmd,data,length);
iSCSIPDUDataRelease(&data);
if(error) {
@@ -65,8 +64,8 @@ errno_t iSCSISessionLoginSingleQuery(struct iSCSILoginQueryContext * context,
iSCSIPDULoginRspBHS rsp;
do {
- if((error = iSCSIKernelRecv(context->sessionId,context->connectionId,
- (iSCSIPDUTargetBHS *)&rsp,&data,&length)))
+ if((error = iSCSIHBAInterfaceReceive(context->interface,context->sessionId,context->connectionId,
+ (iSCSIPDUTargetBHS *)&rsp,&data,&length)))
{
iSCSIPDUDataRelease(&data);
return error;
@@ -84,8 +83,7 @@ errno_t iSCSISessionLoginSingleQuery(struct iSCSILoginQueryContext * context,
iSCSIPDUDataParseToDict(data,length,textRsp);
// Save & return the TSIH if this is the leading login
- if(context->targetSessionId == 0 &&
- context->nextStage == kiSCSIPDUFullFeaturePhase) {
+ if(context->targetSessionId == 0 && context->nextStage == kiSCSIPDUFullFeaturePhase) {
context->targetSessionId = CFSwapInt16BigToHost(rsp.TSIH);
}
@@ -94,7 +92,6 @@ errno_t iSCSISessionLoginSingleQuery(struct iSCSILoginQueryContext * context,
context->statSN = rsp.statSN;
context->expCmdSN = rsp.expCmdSN;
context->transitNextStage = (rsp.loginStage & kiSCSIPDULoginTransitFlag);
-
}
// For this case some other kind of PDU or invalid data was received
else if(rsp.opCode == kiSCSIPDUOpCodeReject)
@@ -135,6 +132,10 @@ errno_t iSCSISessionLoginQuery(struct iSCSILoginQueryContext * context,
// Try a single query first
errno_t error = iSCSISessionLoginSingleQuery(context,statusCode,rejectCode,textCmd,textRsp);
+ // If error occured, do nothing
+ if(error || *statusCode != kiSCSILoginSuccess)
+ return error;
+
// If we are not transitioning stages, or we are and the target agreed to
// transition, then we can move on...
if(context->currentStage == context->nextStage || context->transitNextStage)
@@ -176,8 +177,8 @@ errno_t iSCSISessionLoginQuery(struct iSCSILoginQueryContext * context,
* @param textCmd a dictionary of key-value pairs to send.
* @param textRsp a dictionary of key-value pairs to receive.
* @return an error code that indicates the result of the operation. */
-errno_t iSCSISessionTextQuery(SID sessionId,
- CID connectionId,
+errno_t iSCSISessionTextQuery(SessionIdentifier sessionId,
+ ConnectionIdentifier connectionId,
CFDictionaryRef textCmd,
CFMutableDictionaryRef textRsp)
{
@@ -190,7 +191,7 @@ errno_t iSCSISessionTextQuery(SID sessionId,
size_t length;
iSCSIPDUDataCreateFromDict(textCmd,&data,&length);
- errno_t error = iSCSIKernelSend(sessionId,
+ errno_t error = iSCSIHBAInterfaceSend(0,sessionId,
connectionId,
(iSCSIPDUInitiatorBHS *)&cmd,
data,length);
@@ -204,7 +205,7 @@ errno_t iSCSISessionTextQuery(SID sessionId,
iSCSIPDUTextRspBHS rsp;
do {
- if((error = iSCSIKernelRecv(sessionId,connectionId,
+ if((error = iSCSIHBAInterfaceReceive(0,sessionId,connectionId,
(iSCSIPDUTargetBHS *)&rsp,&data,&length)))
{
iSCSIPDUDataRelease(&data);
diff --git a/Source/User/iscsid/iSCSIQueryTarget.h b/Source/User/iscsid/iSCSIQueryTarget.h
index 443aad84..391e80e4 100644
--- a/Source/User/iscsid/iSCSIQueryTarget.h
+++ b/Source/User/iscsid/iSCSIQueryTarget.h
@@ -31,17 +31,21 @@
#include "iSCSITypes.h"
#include "iSCSIPDUUser.h"
+#include "iSCSIHBAInterface.h"
/*! Used to perform a login query during the login phase of a connection. */
struct iSCSILoginQueryContext {
// These inputs are required when calling iSCSISessionLoginQuery()
+ /*! Reference to the HBA interface. */
+ iSCSIHBAInterfaceRef interface;
+
/*! The session identifier. */
- SID sessionId;
+ SessionIdentifier sessionId;
/*! The connection identifier. */
- CID connectionId;
+ ConnectionIdentifier connectionId;
/*! The current stage of negotiation process. */
enum iSCSIPDULoginStages currentStage;
@@ -59,7 +63,7 @@ struct iSCSILoginQueryContext {
UInt32 expCmdSN;
/*! The target session identifier. */
- TSIH targetSessionId;
+ TargetSessionIdentifier targetSessionId;
/*! Whether the target agrees to advance to next stage. */
bool transitNextStage;
@@ -101,8 +105,8 @@ errno_t iSCSISessionLoginQuery(struct iSCSILoginQueryContext * context,
* @param textCmd a dictionary of key-value pairs to send.
* @param textRsp a dictionary of key-value pairs to receive.
* @return an error code that indicates the result of the operation. */
-errno_t iSCSISessionTextQuery(SID sessionId,
- CID connectionId,
+errno_t iSCSISessionTextQuery(SessionIdentifier sessionId,
+ ConnectionIdentifier connectionId,
CFDictionaryRef textCmd,
CFMutableDictionaryRef textRsp);
diff --git a/Source/User/iscsid/iSCSISession.c b/Source/User/iscsid/iSCSISession.c
index baff3f28..c82bf600 100644
--- a/Source/User/iscsid/iSCSISession.c
+++ b/Source/User/iscsid/iSCSISession.c
@@ -27,21 +27,13 @@
*/
#include "iSCSISession.h"
+#include "iSCSISessionManager.h"
#include "iSCSIPDUUser.h"
-#include "iSCSIKernelInterface.h"
-#include "iSCSIKernelInterfaceShared.h"
+#include "iSCSIHBAInterface.h"
#include "iSCSIAuth.h"
#include "iSCSIQueryTarget.h"
-#include "iSCSITypes.h"
-#include "iSCSIDA.h"
-#include "iSCSIIORegistry.h"
-#include "iSCSIRFC3720Defaults.h"
-/*! Name of the initiator. */
-CFStringRef kiSCSIInitiatorIQN = CFSTR("iqn.2015-01.com.localhost");
-
-/*! Alias of the initiator. */
-CFStringRef kiSCSIInitiatorAlias = CFSTR("default");
+#include "iSCSI.h"
/*! Maximum number of key-value pairs supported by a dictionary that is used
* to produce the data section of text and login PDUs. */
@@ -201,11 +193,14 @@ void iSCSINegotiateBuildSWDictCommon(iSCSISessionConfigRef sessCfg,
CFDictionaryAddValue(sessCmd,kRFC3720_Key_ErrorRecoveryLevel,value);
}
-errno_t iSCSINegotiateParseSWDictCommon(SID sessionId,
+errno_t iSCSINegotiateParseSWDictCommon(iSCSISessionManagerRef managerRef,
+ SessionIdentifier sessionId,
CFDictionaryRef sessCmd,
CFDictionaryRef sessRsp)
{
+ iSCSIHBAInterfaceRef hbaInterface = iSCSISessionManagerGetHBAInterface(managerRef);
+
// Holds target value & comparison result for keys that we'll process
CFStringRef targetRsp;
@@ -220,8 +215,9 @@ errno_t iSCSINegotiateParseSWDictCommon(SID sessionId,
return ENOTSUP;
defaultTime2Retain = iSCSILVGetMin(initCmd,targetRsp);
- iSCSIKernelSetSessionOpt(sessionId,kiSCSIKernelSODefaultTime2Retain,
- &defaultTime2Retain,sizeof(defaultTime2Retain));
+ iSCSIHBAInterfaceSetSessionParameter(hbaInterface,sessionId,
+ kiSCSIHBASODefaultTime2Retain,
+ &defaultTime2Retain,sizeof(defaultTime2Retain));
}
else
return ENOTSUP;
@@ -238,8 +234,9 @@ errno_t iSCSINegotiateParseSWDictCommon(SID sessionId,
return ENOTSUP;
defaultTime2Wait = iSCSILVGetMin(initCmd,targetRsp);;
- iSCSIKernelSetSessionOpt(sessionId,kiSCSIKernelSODefaultTime2Wait,
- &defaultTime2Wait,sizeof(defaultTime2Wait));
+ iSCSIHBAInterfaceSetSessionParameter(hbaInterface,sessionId,
+ kiSCSIHBASODefaultTime2Wait,
+ &defaultTime2Wait,sizeof(defaultTime2Wait));
}
else
return ENOTSUP;
@@ -255,7 +252,7 @@ errno_t iSCSINegotiateParseSWDictCommon(SID sessionId,
return ENOTSUP;
errorRecoveryLevel = iSCSILVGetMin(initCmd,targetRsp);
- iSCSIKernelSetSessionOpt(sessionId,kiSCSIKernelSOErrorRecoveryLevel,
+ iSCSIHBAInterfaceSetSessionParameter(hbaInterface,sessionId,kiSCSIHBASOErrorRecoveryLevel,
&errorRecoveryLevel,sizeof(errorRecoveryLevel));
}
else
@@ -265,11 +262,14 @@ errno_t iSCSINegotiateParseSWDictCommon(SID sessionId,
return 0;
}
-errno_t iSCSINegotiateParseSWDictNormal(SID sessionId,
+errno_t iSCSINegotiateParseSWDictNormal(iSCSISessionManagerRef managerRef,
+ SessionIdentifier sessionId,
CFDictionaryRef sessCmd,
CFDictionaryRef sessRsp)
{
+ iSCSIHBAInterfaceRef hbaInterface = iSCSISessionManagerGetHBAInterface(managerRef);
+
// Holds target value & comparison result for keys that we'll process
CFStringRef targetRsp;
@@ -284,9 +284,8 @@ errno_t iSCSINegotiateParseSWDictNormal(SID sessionId,
return ENOTSUP;
maxConnections = iSCSILVGetMin(initCmd,targetRsp);
- iSCSIKernelSetSessionOpt(sessionId,kiSCSIKernelSOMaxConnections,
- &maxConnections,sizeof(maxConnections));
-
+ iSCSIHBAInterfaceSetSessionParameter(hbaInterface,sessionId,kiSCSIHBASOMaxConnections,
+ &maxConnections,sizeof(maxConnections));
}
// Grab the OR for initialR2T command and response
@@ -294,8 +293,8 @@ errno_t iSCSINegotiateParseSWDictNormal(SID sessionId,
{
CFStringRef initCmd = CFDictionaryGetValue(sessCmd,kRFC3720_Key_InitialR2T);
Boolean initialR2T = iSCSILVGetOr(initCmd,targetRsp);
- iSCSIKernelSetSessionOpt(sessionId,kiSCSIKernelSOInitialR2T,
- &initialR2T,sizeof(initialR2T));
+ iSCSIHBAInterfaceSetSessionParameter(hbaInterface,sessionId,kiSCSIHBASOInitialR2T,
+ &initialR2T,sizeof(initialR2T));
}
// Grab the AND for immediate data command and response
@@ -303,8 +302,8 @@ errno_t iSCSINegotiateParseSWDictNormal(SID sessionId,
{
CFStringRef initCmd = CFDictionaryGetValue(sessCmd,kRFC3720_Key_ImmediateData);
Boolean immediateData = iSCSILVGetAnd(initCmd,targetRsp);
- iSCSIKernelSetSessionOpt(sessionId,kiSCSIKernelSOImmediateData,
- &immediateData,sizeof(immediateData));
+ iSCSIHBAInterfaceSetSessionParameter(hbaInterface,sessionId,kiSCSIHBASOImmediateData,
+ &immediateData,sizeof(immediateData));
}
// Get the OR of data PDU in order
@@ -312,7 +311,7 @@ errno_t iSCSINegotiateParseSWDictNormal(SID sessionId,
{
CFStringRef initCmd = CFDictionaryGetValue(sessCmd,kRFC3720_Key_DataPDUInOrder);
Boolean dataPDUInOrder = iSCSILVGetAnd(initCmd,targetRsp);
- iSCSIKernelSetSessionOpt(sessionId,kiSCSIKernelSODataPDUInOrder,
+ iSCSIHBAInterfaceSetSessionParameter(hbaInterface,sessionId,kiSCSIHBASODataPDUInOrder,
&dataPDUInOrder,sizeof(dataPDUInOrder));
}
@@ -321,7 +320,7 @@ errno_t iSCSINegotiateParseSWDictNormal(SID sessionId,
{
CFStringRef initCmd = CFDictionaryGetValue(sessCmd,kRFC3720_Key_DataSequenceInOrder);
Boolean dataSequenceInOrder = iSCSILVGetAnd(initCmd,targetRsp);
- iSCSIKernelSetSessionOpt(sessionId,kiSCSIKernelSODataSequenceInOrder,
+ iSCSIHBAInterfaceSetSessionParameter(hbaInterface,sessionId,kiSCSIHBASODataSequenceInOrder,
&dataSequenceInOrder,sizeof(dataSequenceInOrder));
}
@@ -330,7 +329,7 @@ errno_t iSCSINegotiateParseSWDictNormal(SID sessionId,
{
CFStringRef initCmd = CFDictionaryGetValue(sessCmd,kRFC3720_Key_MaxBurstLength);
UInt32 maxBurstLength = iSCSILVGetMin(initCmd,targetRsp);
- iSCSIKernelSetSessionOpt(sessionId,kiSCSIKernelSOMaxBurstLength,
+ iSCSIHBAInterfaceSetSessionParameter(hbaInterface,sessionId,kiSCSIHBASOMaxBurstLength,
&maxBurstLength,sizeof(maxBurstLength));
}
@@ -345,7 +344,7 @@ errno_t iSCSINegotiateParseSWDictNormal(SID sessionId,
return ENOTSUP;
firstBurstLength = iSCSILVGetMin(initCmd,targetRsp);
- iSCSIKernelSetSessionOpt(sessionId,kiSCSIKernelSOFirstBurstLength,
+ iSCSIHBAInterfaceSetSessionParameter(hbaInterface,sessionId,kiSCSIHBASOFirstBurstLength,
&firstBurstLength,sizeof(firstBurstLength));
}
@@ -360,7 +359,7 @@ errno_t iSCSINegotiateParseSWDictNormal(SID sessionId,
return ENOTSUP;
maxOutStandingR2T = iSCSILVGetMin(initCmd,targetRsp);
- iSCSIKernelSetSessionOpt(sessionId,kiSCSIKernelSOMaxOutstandingR2T,
+ iSCSIHBAInterfaceSetSessionParameter(hbaInterface,sessionId,kiSCSIHBASOMaxOutstandingR2T,
&maxOutStandingR2T,sizeof(maxOutStandingR2T));
}
@@ -407,12 +406,15 @@ void iSCSINegotiateBuildCWDict(iSCSIConnectionConfigRef connCfg,
* @param connCfgKernel a connection options object used to store options with
* the iSCSI kernel extension
* there were received from the target. */
-errno_t iSCSINegotiateParseCWDict(SID sessionId,
- CID connectionId,
+errno_t iSCSINegotiateParseCWDict(iSCSISessionManagerRef managerRef,
+ SessionIdentifier sessionId,
+ ConnectionIdentifier connectionId,
CFDictionaryRef connCmd,
CFDictionaryRef connRsp)
{
+ iSCSIHBAInterfaceRef hbaInterface = iSCSISessionManagerGetHBAInterface(managerRef);
+
// Holds target value & comparison result for keys that we'll process
CFStringRef targetRsp;
@@ -427,9 +429,9 @@ errno_t iSCSINegotiateParseCWDict(SID sessionId,
Boolean useDataDigest = agree && iSCSILVGetEqual(targetRsp,kRFC3720_Value_DataDigestCRC32C);
// Store value
- iSCSIKernelSetConnectionOpt(sessionId,connectionId,kiSCSIKernelCOUseDataDigest,
- &useDataDigest,sizeof(useDataDigest));
-
+ iSCSIHBAInterfaceSetConnectionParameter(hbaInterface,sessionId,connectionId,
+ kiSCSIHBACOUseDataDigest,
+ &useDataDigest,sizeof(useDataDigest));
// Reset agreement flag
agree = false;
@@ -441,17 +443,17 @@ errno_t iSCSINegotiateParseCWDict(SID sessionId,
Boolean useHeaderDigest = agree && iSCSILVGetEqual(targetRsp,kRFC3720_Value_HeaderDigestCRC32C);
// Store value
- iSCSIKernelSetConnectionOpt(sessionId,connectionId,kiSCSIKernelCOUseHeaderDigest,
- &useHeaderDigest,sizeof(useHeaderDigest));
-
+ iSCSIHBAInterfaceSetConnectionParameter(hbaInterface,sessionId,connectionId,
+ kiSCSIHBACOUseHeaderDigest,
+ &useHeaderDigest,sizeof(useHeaderDigest));
// This option is declarative; we sent the default length, and the target
// must accept our choice as it is within a valid range
UInt32 maxRecvDataSegmentLength = kRFC3720_MaxRecvDataSegmentLength;
- iSCSIKernelSetConnectionOpt(sessionId,connectionId,kiSCSIKernelCOMaxRecvDataSegmentLength,
- &maxRecvDataSegmentLength,sizeof(maxRecvDataSegmentLength));
-
+ iSCSIHBAInterfaceSetConnectionParameter(hbaInterface,sessionId,connectionId,
+ kiSCSIHBACOMaxRecvDataSegmentLength,
+ &maxRecvDataSegmentLength,sizeof(maxRecvDataSegmentLength));
// This is the declaration made by the target as to the length it can
// receive. Accept the value if it is within the RFC3720 allowed range
@@ -470,18 +472,22 @@ errno_t iSCSINegotiateParseCWDict(SID sessionId,
}
// Store value
- iSCSIKernelSetConnectionOpt(sessionId,connectionId,kiSCSIKernelCOMaxSendDataSegmentLength,
- &maxSendDataSegmentLength,sizeof(maxSendDataSegmentLength));
+ iSCSIHBAInterfaceSetConnectionParameter(hbaInterface,sessionId,connectionId,
+ kiSCSIHBACOMaxSendDataSegmentLength,
+ &maxSendDataSegmentLength,sizeof(maxSendDataSegmentLength));
return 0;
}
-errno_t iSCSINegotiateSession(iSCSIMutableTargetRef target,
- SID sessionId,
- CID connectionId,
+errno_t iSCSINegotiateSession(iSCSISessionManagerRef managerRef,
+ iSCSIMutableTargetRef target,
+ SessionIdentifier sessionId,
+ ConnectionIdentifier connectionId,
iSCSISessionConfigRef sessCfg,
iSCSIConnectionConfigRef connCfg,
enum iSCSILoginStatusCode * statusCode)
{
+ iSCSIHBAInterfaceRef hbaInterface = iSCSISessionManagerGetHBAInterface(managerRef);
+
// Create a new dictionary for connection parameters we want to send
CFMutableDictionaryRef sessCmd = CFDictionaryCreateMutable(
kCFAllocatorDefault,
@@ -507,6 +513,7 @@ errno_t iSCSINegotiateSession(iSCSIMutableTargetRef target,
&kCFTypeDictionaryValueCallBacks);
struct iSCSILoginQueryContext context;
+ context.interface = hbaInterface;
context.sessionId = sessionId;
context.connectionId = connectionId;
context.currentStage = kiSCSIPDULoginOperationalNegotiation;
@@ -526,16 +533,17 @@ errno_t iSCSINegotiateSession(iSCSIMutableTargetRef target,
// The TSIH was recorded by iSCSISessionLoginQuery since we're
// entering the full-feature phase (see iSCSISessionLoginQuery documentation)
- iSCSIKernelSetSessionOpt(sessionId,kiSCSIKernelSOTargetSessionId,
- &context.targetSessionId,sizeof(context.targetSessionId));
+ iSCSIHBAInterfaceSetSessionParameter(hbaInterface,sessionId,
+ kiSCSIHBASOTargetSessionId,
+ &context.targetSessionId,sizeof(context.targetSessionId));
if(!error)
- error = iSCSINegotiateParseSWDictCommon(sessionId,sessCmd,sessRsp);
+ error = iSCSINegotiateParseSWDictCommon(managerRef,sessionId,sessCmd,sessRsp);
if(!error && iSCSITargetGetIQN(target) != NULL)
- error = iSCSINegotiateParseSWDictNormal(sessionId,sessCmd,sessRsp);
+ error = iSCSINegotiateParseSWDictNormal(managerRef,sessionId,sessCmd,sessRsp);
if(!error)
- error = iSCSINegotiateParseCWDict(sessionId,connectionId,sessCmd,sessRsp);
+ error = iSCSINegotiateParseCWDict(managerRef,sessionId,connectionId,sessCmd,sessRsp);
}
// If no error and the target returned an alias save it...
@@ -551,11 +559,14 @@ errno_t iSCSINegotiateSession(iSCSIMutableTargetRef target,
/*! Helper function. Negotiates operational parameters for a connection
* as part of the login and connection instantiation process. */
-errno_t iSCSINegotiateConnection(iSCSITargetRef target,
- SID sessionId,
- CID connectionId,
+errno_t iSCSINegotiateConnection(iSCSISessionManagerRef managerRef,
+ iSCSITargetRef target,
+ SessionIdentifier sessionId,
+ ConnectionIdentifier connectionId,
enum iSCSILoginStatusCode * statusCode)
{
+ iSCSIHBAInterfaceRef hbaInterface = iSCSISessionManagerGetHBAInterface(managerRef);
+
// Create a dictionary to store query request
CFMutableDictionaryRef connCmd = CFDictionaryCreateMutable(
kCFAllocatorDefault,
@@ -574,6 +585,7 @@ errno_t iSCSINegotiateConnection(iSCSITargetRef target,
&kCFTypeDictionaryValueCallBacks);
struct iSCSILoginQueryContext context;
+ context.interface = hbaInterface;
context.sessionId = sessionId;
context.connectionId = connectionId;
context.currentStage = kiSCSIPDULoginOperationalNegotiation;
@@ -583,8 +595,8 @@ errno_t iSCSINegotiateConnection(iSCSITargetRef target,
// active session if we are simply adding a connection, so we
// can't assume that this is the leading login and therefore
// cannot set TSIH to 0.
- iSCSIKernelGetSessionOpt(sessionId,kiSCSIKernelSOTargetSessionId,
- &context.targetSessionId,sizeof(context.targetSessionId));
+ iSCSIHBAInterfaceGetSessionParameter(hbaInterface,sessionId,kiSCSIHBASOTargetSessionId,
+ &context.targetSessionId,sizeof(context.targetSessionId));
// If the target session ID is non-zero, we're simply adding a new
// connection and we can enter the full feature after this negotiation.
@@ -602,7 +614,7 @@ errno_t iSCSINegotiateConnection(iSCSITargetRef target,
// If no error, parse received dictionary and store connection options
if(!error && *statusCode == kiSCSILoginSuccess)
- error = iSCSINegotiateParseCWDict(sessionId,connectionId,connCmd,connRsp);
+ error = iSCSINegotiateParseCWDict(managerRef,sessionId,connectionId,connCmd,connRsp);
CFRelease(connCmd);
CFRelease(connRsp);
@@ -610,21 +622,23 @@ errno_t iSCSINegotiateConnection(iSCSITargetRef target,
}
/*! Helper function used to log out of connections and sessions. */
-errno_t iSCSISessionLogoutCommon(SID sessionId,
- CID connectionId,
+errno_t iSCSISessionLogoutCommon(iSCSISessionManagerRef managerRef,
+ SessionIdentifier sessionId,
+ ConnectionIdentifier connectionId,
enum iSCSIPDULogoutReasons logoutReason,
enum iSCSILogoutStatusCode * statusCode)
{
if(sessionId >= kiSCSIInvalidSessionId || connectionId >= kiSCSIInvalidConnectionId)
return EINVAL;
+ iSCSIHBAInterfaceRef hbaInterface = iSCSISessionManagerGetHBAInterface(managerRef);
errno_t error = 0;
// Create a logout PDU and log out of the session
iSCSIPDULogoutReqBHS cmd = iSCSIPDULogoutReqBHSInit;
cmd.reasonCode = logoutReason | kISCSIPDULogoutReasonCodeFlag;
- if((error = iSCSIKernelSend(sessionId,connectionId,(iSCSIPDUInitiatorBHS *)&cmd,NULL,0)))
+ if((error = iSCSIHBAInterfaceSend(hbaInterface,sessionId,connectionId,(iSCSIPDUInitiatorBHS *)&cmd,NULL,0)))
return error;
// Get response from iSCSI portal
@@ -633,7 +647,7 @@ errno_t iSCSISessionLogoutCommon(SID sessionId,
size_t length = 0;
// Receive response PDU...
- if((error = iSCSIKernelRecv(sessionId,connectionId,(iSCSIPDUTargetBHS *)&rsp,&data,&length)))
+ if((error = iSCSIHBAInterfaceReceive(hbaInterface,sessionId,connectionId,(iSCSIPDUTargetBHS *)&rsp,&data,&length)))
return error;
if(rsp.opCode == kiSCSIPDUOpCodeLogoutRsp)
@@ -647,106 +661,6 @@ errno_t iSCSISessionLogoutCommon(SID sessionId,
return error;
}
-/*! Helper function used to resolve target nodes as specified by connInfo.
- * The target nodes specified in connInfo may be a DNS name, an IPv4 or
- * IPv6 address. */
-errno_t iSCSISessionResolveNode(iSCSIPortalRef portal,
- struct sockaddr_storage * ssTarget,
- struct sockaddr_storage * ssHost)
-{
- if (!portal || !ssTarget || !ssHost)
- return EINVAL;
-
- errno_t error = 0;
-
- // Resolve the target node first and get a sockaddr info for it
- const char * targetAddr, * targetPort;
-
- targetAddr = CFStringGetCStringPtr(iSCSIPortalGetAddress(portal),kCFStringEncodingUTF8);
- targetPort = CFStringGetCStringPtr(iSCSIPortalGetPort(portal),kCFStringEncodingUTF8);
-
- struct addrinfo hints = {
- .ai_family = AF_UNSPEC,
- .ai_socktype = SOCK_STREAM,
- .ai_protocol = IPPROTO_TCP,
- };
-
- struct addrinfo * aiTarget = NULL;
- if((error = getaddrinfo(targetAddr,targetPort,&hints,&aiTarget)))
- return error;
-
- // Copy the sock_addr structure into a sockaddr_storage structure (this
- // may be either an IPv4 or IPv6 sockaddr structure)
- memcpy(ssTarget,aiTarget->ai_addr,aiTarget->ai_addrlen);
-
- freeaddrinfo(aiTarget);
-
- // If the default interface is to be used, prepare a structure for it
- CFStringRef hostIface = iSCSIPortalGetHostInterface(portal);
-
- if(CFStringCompare(hostIface,kiSCSIDefaultHostInterface,0) == kCFCompareEqualTo)
- {
- ssHost->ss_family = ssTarget->ss_family;
-
- // For completeness, setup the sockaddr_in structure
- if(ssHost->ss_family == AF_INET)
- {
- struct sockaddr_in * sa = (struct sockaddr_in *)ssHost;
- sa->sin_port = 0;
- sa->sin_addr.s_addr = htonl(INADDR_ANY);
- sa->sin_len = sizeof(struct sockaddr_in);
- }
-
-// TODO: test IPv6 functionality
- else if(ssHost->ss_family == AF_INET6)
- {
- struct sockaddr_in6 * sa = (struct sockaddr_in6 *)ssHost;
- sa->sin6_addr = in6addr_any;
- }
-
- return error;
- }
-
- // Otherwise we have to search the list of all interfaces for the specified
- // interface and copy the corresponding address structure
- struct ifaddrs * interfaceList;
-
- if((error = getifaddrs(&interfaceList)))
- return error;
-
- error = EAFNOSUPPORT;
- struct ifaddrs * interface = interfaceList;
-
- while(interface)
- {
- // Check if interface supports the targets address family (e.g., IPv4)
- if(interface->ifa_addr->sa_family == ssTarget->ss_family)
- {
- CFStringRef currIface = CFStringCreateWithCStringNoCopy(
- kCFAllocatorDefault,
- interface->ifa_name,
- kCFStringEncodingUTF8,
- kCFAllocatorNull);
-
- Boolean ifaceNameMatch =
- CFStringCompare(currIface,hostIface,kCFCompareCaseInsensitive) == kCFCompareEqualTo;
- CFRelease(currIface);
- // Check if interface names match...
- if(ifaceNameMatch)
- {
- memcpy(ssHost,interface->ifa_addr,interface->ifa_addr->sa_len);
- error = 0;
- break;
- }
- }
- interface = interface->ifa_next;
- }
-
- freeifaddrs(interfaceList);
- return error;
-}
-
-
/*! Adds a new connection to an iSCSI session.
* @param sessionId the new session identifier.
* @param portal specifies the portal to use for the connection.
@@ -756,85 +670,87 @@ errno_t iSCSISessionResolveNode(iSCSIPortalRef portal,
* @param connectionId the new connection identifier.
* @param statusCode iSCSI response code indicating operation status.
* @return an error code indicating whether the operation was successful. */
-errno_t iSCSILoginConnection(SID sessionId,
- iSCSIPortalRef portal,
- iSCSIAuthRef initiatorAuth,
- iSCSIAuthRef targetAuth,
- iSCSIConnectionConfigRef connCfg,
- CID * connectionId,
- enum iSCSILoginStatusCode * statusCode)
+errno_t iSCSISessionAddConnection(iSCSISessionManagerRef managerRef,
+ SessionIdentifier sessionId,
+ iSCSIPortalRef portal,
+ iSCSIAuthRef initiatorAuth,
+ iSCSIAuthRef targetAuth,
+ iSCSIConnectionConfigRef connCfg,
+ ConnectionIdentifier * connectionId,
+ enum iSCSILoginStatusCode * statusCode)
{
if(!portal || sessionId == kiSCSIInvalidSessionId || !connectionId)
return EINVAL;
- // Reset connection ID by default
+ iSCSIHBAInterfaceRef hbaInterface = iSCSISessionManagerGetHBAInterface(managerRef);
*connectionId = kiSCSIInvalidConnectionId;
-
errno_t error = 0;
// Resolve information about the target
struct sockaddr_storage ssTarget, ssHost;
- if((error = iSCSISessionResolveNode(portal,&ssTarget,&ssHost)))
+ if((error = iSCSIUtilsGetAddressForPortal(portal,&ssTarget,&ssHost)))
return error;
// If both target and host were resolved, grab a connection
- error = iSCSIKernelCreateConnection(sessionId,
- iSCSIPortalGetAddress(portal),
- iSCSIPortalGetPort(portal),
- iSCSIPortalGetHostInterface(portal),
- &ssTarget,
- &ssHost,connectionId);
+ error = iSCSIHBAInterfaceCreateConnection(hbaInterface,sessionId,
+ iSCSIPortalGetAddress(portal),
+ iSCSIPortalGetPort(portal),
+ iSCSIPortalGetHostInterface(portal),
+ &ssTarget,
+ &ssHost,connectionId);
// If we can't accomodate a new connection quit; try again later
if(error || *connectionId == kiSCSIInvalidConnectionId)
return EAGAIN;
- iSCSITargetRef targetTemp = iSCSICreateTargetForSessionId(sessionId);
+ iSCSITargetRef targetTemp = iSCSISessionCopyTargetForId(managerRef,sessionId);
iSCSIMutableTargetRef target = iSCSITargetCreateMutableCopy(targetTemp);
iSCSITargetRelease(targetTemp);
// If no error, authenticate (negotiate security parameters)
if(!error && *statusCode == kiSCSILoginSuccess)
- error = iSCSIAuthNegotiate(target,initiatorAuth,targetAuth,sessionId,*connectionId,statusCode);
+ error = iSCSIAuthNegotiate(managerRef,target,initiatorAuth,targetAuth,sessionId,*connectionId,statusCode);
if(!error && *statusCode == kiSCSILoginSuccess)
- iSCSIKernelActivateConnection(sessionId,*connectionId);
+ iSCSIHBAInterfaceActivateConnection(hbaInterface,sessionId,*connectionId);
else
- iSCSIKernelReleaseConnection(sessionId,*connectionId);
+ iSCSIHBAInterfaceReleaseConnection(hbaInterface,sessionId,*connectionId);
iSCSITargetRelease(target);
return 0;
}
-errno_t iSCSILogoutConnection(SID sessionId,
- CID connectionId,
- enum iSCSILogoutStatusCode * statusCode)
+errno_t iSCSISessionRemoveConnection(iSCSISessionManagerRef managerRef,
+ SessionIdentifier sessionId,
+ ConnectionIdentifier connectionId,
+ enum iSCSILogoutStatusCode * statusCode)
{
if(sessionId >= kiSCSIInvalidSessionId || connectionId >= kiSCSIInvalidConnectionId)
return EINVAL;
+ iSCSIHBAInterfaceRef hbaInterface = iSCSISessionManagerGetHBAInterface(managerRef);
errno_t error = 0;
// Release the session instead if there's only a single connection
// for this session
UInt32 numConnections = 0;
- if((error = iSCSIKernelGetNumConnections(sessionId,&numConnections)))
+ if((error = iSCSIHBAInterfaceGetNumConnections(hbaInterface,sessionId,&numConnections)))
return error;
if(numConnections == 1)
- return iSCSILogoutSession(sessionId,statusCode);
+ return iSCSISessionLogout(managerRef,sessionId,statusCode);
// Deactivate connection before we remove it (this is optional but good
// practice, as the kernel will deactivate the connection for us).
- if(!(error = iSCSIKernelDeactivateConnection(sessionId,connectionId))) {
+ if(!(error = iSCSIHBAInterfaceDeactivateConnection(hbaInterface,sessionId,connectionId))) {
// Logout the connection or session, as necessary
- error = iSCSISessionLogoutCommon(sessionId,connectionId,
+ error = iSCSISessionLogoutCommon(managerRef,sessionId,connectionId,
kISCSIPDULogoutCloseConnection,statusCode);
}
// Release the connection in the kernel
- iSCSIKernelReleaseConnection(sessionId,connectionId);
+ iSCSIHBAInterfaceReleaseConnection(hbaInterface,sessionId,connectionId);
return error;
}
@@ -851,37 +767,38 @@ errno_t iSCSILogoutConnection(SID sessionId,
* @param connectionId the new connection identifier.
* @param statusCode iSCSI response code indicating operation status.
* @return an error code indicating whether the operation was successful. */
-errno_t iSCSILoginSession(iSCSIMutableTargetRef target,
+errno_t iSCSISessionLogin(iSCSISessionManagerRef managerRef,
+ iSCSIMutableTargetRef target,
iSCSIPortalRef portal,
iSCSIAuthRef initiatorAuth,
iSCSIAuthRef targetAuth,
iSCSISessionConfigRef sessCfg,
iSCSIConnectionConfigRef connCfg,
- SID * sessionId,
- CID * connectionId,
+ SessionIdentifier * sessionId,
+ ConnectionIdentifier * connectionId,
enum iSCSILoginStatusCode * statusCode)
{
if(!target || !portal || !sessCfg || !connCfg || !sessionId || !connectionId ||
!statusCode || !initiatorAuth || !targetAuth)
return EINVAL;
- // Store errno from helpers and pass back to up the call chain
+ iSCSIHBAInterfaceRef hbaInterface = iSCSISessionManagerGetHBAInterface(managerRef);
errno_t error = 0;
// Resolve the target address
struct sockaddr_storage ssTarget, ssHost;
- if((error = iSCSISessionResolveNode(portal,&ssTarget,&ssHost)))
+ if((error = iSCSIUtilsGetAddressForPortal(portal,&ssTarget,&ssHost)))
return error;
-
// Create a new session in the kernel. This allocates session and
// connection identifiers
- error = iSCSIKernelCreateSession(iSCSITargetGetIQN(target),
- iSCSIPortalGetAddress(portal),
- iSCSIPortalGetPort(portal),
- iSCSIPortalGetHostInterface(portal),
- &ssTarget,&ssHost,sessionId,connectionId);
+ error = iSCSIHBAInterfaceCreateSession(hbaInterface,
+ iSCSITargetGetIQN(target),
+ iSCSIPortalGetAddress(portal),
+ iSCSIPortalGetPort(portal),
+ iSCSIPortalGetHostInterface(portal),
+ &ssTarget,&ssHost,sessionId,connectionId);
// If session couldn't be allocated were maxed out; try again later
if(!error && (*sessionId == kiSCSIInvalidSessionId || *connectionId == kiSCSIInvalidConnectionId))
@@ -889,20 +806,20 @@ errno_t iSCSILoginSession(iSCSIMutableTargetRef target,
// If no error, authenticate (negotiate security parameters)
if(!error) {
- error = iSCSIAuthNegotiate(target,initiatorAuth,targetAuth,
+ error = iSCSIAuthNegotiate(managerRef,target,initiatorAuth,targetAuth,
*sessionId,*connectionId,statusCode);
}
// Negotiate session & connection parameters
if(!error && *statusCode == kiSCSILoginSuccess)
- error = iSCSINegotiateSession(target,*sessionId,*connectionId,sessCfg,connCfg,statusCode);
+ error = iSCSINegotiateSession(managerRef,target,*sessionId,*connectionId,sessCfg,connCfg,statusCode);
// Only activate connections for kernel use if no errors have occurred and
// the session is not a discovery session
if(error || *statusCode != kiSCSILoginSuccess)
- iSCSIKernelReleaseSession(*sessionId);
+ iSCSIHBAInterfaceReleaseSession(hbaInterface,*sessionId);
else if(CFStringCompare(iSCSITargetGetIQN(target),kiSCSIUnspecifiedTargetIQN,0) != kCFCompareEqualTo)
- iSCSIKernelActivateConnection(*sessionId,*connectionId);
+ iSCSIHBAInterfaceActivateConnection(hbaInterface,*sessionId,*connectionId);
return error;
}
@@ -914,25 +831,27 @@ errno_t iSCSILoginSession(iSCSIMutableTargetRef target,
* sessions the future.
* @param sessionId the session to release.
* @return an error code indicating whether the operation was successful. */
-errno_t iSCSILogoutSession(SID sessionId,
+errno_t iSCSISessionLogout(iSCSISessionManagerRef managerRef,
+ SessionIdentifier sessionId,
enum iSCSILogoutStatusCode * statusCode)
{
if(sessionId == kiSCSIInvalidSessionId)
return EINVAL;
+ iSCSIHBAInterfaceRef hbaInterface = iSCSISessionManagerGetHBAInterface(managerRef);
errno_t error = 0;
// First deactivate all of the connections
- if((error = iSCSIKernelDeactivateAllConnections(sessionId)))
+ if((error = iSCSIHBAInterfaceDeactivateAllConnections(hbaInterface,sessionId)))
return error;
// Grab a handle to any connection so we can logout of the session
- CID connectionId = kiSCSIInvalidConnectionId;
- if(!(error = iSCSIKernelGetConnection(sessionId,&connectionId)))
- error = iSCSISessionLogoutCommon(sessionId, connectionId,kiSCSIPDULogoutCloseSession,statusCode);
+ ConnectionIdentifier connectionId = kiSCSIInvalidConnectionId;
+ if(!(error = iSCSIHBAInterfaceGetConnection(hbaInterface,sessionId,&connectionId)))
+ error = iSCSISessionLogoutCommon(managerRef,sessionId,connectionId,kiSCSIPDULogoutCloseSession,statusCode);
// Release all of the connections in the kernel by releasing the session
- iSCSIKernelReleaseSession(sessionId);
+ iSCSIHBAInterfaceReleaseSession(hbaInterface,sessionId);
return error;
}
@@ -996,7 +915,8 @@ void iSCSIPDUDataParseToDiscoveryRecCallback(void * keyContainer,CFStringRef key
* @param discoveryRec a discovery record, containing the query results.
* @param statusCode iSCSI response code indicating operation status.
* @return an error code indicating whether the operation was successful. */
-errno_t iSCSIQueryPortalForTargets(iSCSIPortalRef portal,
+errno_t iSCSIQueryPortalForTargets(iSCSISessionManagerRef managerRef,
+ iSCSIPortalRef portal,
iSCSIAuthRef initiatorAuth,
iSCSIMutableDiscoveryRecRef * discoveryRec,
enum iSCSILoginStatusCode * statusCode)
@@ -1009,15 +929,15 @@ errno_t iSCSIQueryPortalForTargets(iSCSIPortalRef portal,
iSCSIMutableTargetRef target = iSCSITargetCreateMutable();
iSCSITargetSetIQN(target,kiSCSIUnspecifiedTargetIQN);
- SID sessionId;
- CID connectionId;
+ SessionIdentifier sessionId;
+ ConnectionIdentifier connectionId;
iSCSIMutableSessionConfigRef sessCfg = iSCSISessionConfigCreateMutable();
iSCSIMutableConnectionConfigRef connCfg = iSCSIConnectionConfigCreateMutable();
iSCSIAuthRef targetAuth = iSCSIAuthCreateNone();
- errno_t error = iSCSILoginSession(target,portal,initiatorAuth,targetAuth,
+ errno_t error = iSCSISessionLogin(managerRef,target,portal,initiatorAuth,targetAuth,
sessCfg,connCfg,&sessionId,
&connectionId,statusCode);
@@ -1048,8 +968,9 @@ errno_t iSCSIQueryPortalForTargets(iSCSIPortalRef portal,
iSCSIPDUTextReqBHS cmd = iSCSIPDUTextReqBHSInit;
cmd.textReqStageFlags |= kiSCSIPDUTextReqFinalFlag;
cmd.targetTransferTag = kiSCSIPDUTargetTransferTagReserved;
-
- error = iSCSIKernelSend(sessionId,connectionId,(iSCSIPDUInitiatorBHS *)&cmd,data,length);
+
+ iSCSIHBAInterfaceRef hbaInterface = iSCSISessionManagerGetHBAInterface(managerRef);
+ error = iSCSIHBAInterfaceSend(hbaInterface,sessionId,connectionId,(iSCSIPDUInitiatorBHS *)&cmd,data,length);
iSCSIPDUDataRelease(&data);
CFRelease(textCmd);
@@ -1057,7 +978,7 @@ errno_t iSCSIQueryPortalForTargets(iSCSIPortalRef portal,
if(error)
{
enum iSCSILogoutStatusCode statusCode;
- iSCSILogoutSession(sessionId,&statusCode);
+ iSCSISessionLogout(managerRef,sessionId,&statusCode);
return error;
}
@@ -1067,12 +988,12 @@ errno_t iSCSIQueryPortalForTargets(iSCSIPortalRef portal,
*discoveryRec = iSCSIDiscoveryRecCreateMutable();
do {
- if((error = iSCSIKernelRecv(sessionId,connectionId,(iSCSIPDUTargetBHS *)&rsp,&data,&length)))
+ if((error = iSCSIHBAInterfaceReceive(hbaInterface,sessionId,connectionId,(iSCSIPDUTargetBHS *)&rsp,&data,&length)))
{
iSCSIPDUDataRelease(&data);
enum iSCSILogoutStatusCode statusCode;
- iSCSILogoutSession(sessionId,&statusCode);
+ iSCSISessionLogout(managerRef,sessionId,&statusCode);
return error;
}
@@ -1094,7 +1015,7 @@ errno_t iSCSIQueryPortalForTargets(iSCSIPortalRef portal,
iSCSIPDUDataRelease(&data);
enum iSCSILogoutStatusCode logoutStatusCode;
- iSCSILogoutSession(sessionId,&logoutStatusCode);
+ iSCSISessionLogout(managerRef,sessionId,&logoutStatusCode);
// Per RFC3720, the "TargetAddress" key is optional in a SendTargets
// discovery operation. Therefore, certain targets may respond with
@@ -1136,21 +1057,22 @@ errno_t iSCSIQueryPortalForTargets(iSCSIPortalRef portal,
* @param initiatorAuth specifies the initiator authentication parameters.
* @param statusCode iSCSI response code indicating operation status.
* @return an error code indicating whether the operation was successful. */
-errno_t iSCSIQueryTargetForAuthMethod(iSCSIPortalRef portal,
+errno_t iSCSIQueryTargetForAuthMethod(iSCSISessionManagerRef managerRef,
+ iSCSIPortalRef portal,
CFStringRef targetIQN,
enum iSCSIAuthMethods * authMethod,
enum iSCSILoginStatusCode * statusCode)
{
if(!portal || !authMethod)
return EINVAL;
-
- // Store errno from helpers and pass back up the call chain
+
+ iSCSIHBAInterfaceRef hbaInterface = iSCSISessionManagerGetHBAInterface(managerRef);
errno_t error = 0;
// Resolve information about the target
struct sockaddr_storage ssTarget, ssHost;
- if((error = iSCSISessionResolveNode(portal,&ssTarget,&ssHost)))
+ if((error = iSCSIUtilsGetAddressForPortal(portal,&ssTarget,&ssHost)))
return error;
// Create a discovery session to the portal
@@ -1159,9 +1081,10 @@ errno_t iSCSIQueryTargetForAuthMethod(iSCSIPortalRef portal,
// Create session (incl. qualifier) and a new connection (incl. Id)
// Reset qualifier and connection ID by default
- SID sessionId;
- CID connectionId;
- error = iSCSIKernelCreateSession(targetIQN,
+ SessionIdentifier sessionId;
+ ConnectionIdentifier connectionId;
+ error = iSCSIHBAInterfaceCreateSession(hbaInterface,
+ targetIQN,
iSCSIPortalGetAddress(portal),
iSCSIPortalGetPort(portal),
iSCSIPortalGetHostInterface(portal),
@@ -1172,13 +1095,14 @@ errno_t iSCSIQueryTargetForAuthMethod(iSCSIPortalRef portal,
// If no error, authenticate (negotiate security parameters)
if(!error)
- error = iSCSIAuthInterrogate(target,
+ error = iSCSIAuthInterrogate(managerRef,
+ target,
sessionId,
connectionId,
authMethod,
statusCode);
- iSCSIKernelReleaseSession(sessionId);
+ iSCSIHBAInterfaceReleaseSession(hbaInterface,sessionId);
iSCSITargetRelease(target);
return error;
@@ -1187,29 +1111,35 @@ errno_t iSCSIQueryTargetForAuthMethod(iSCSIPortalRef portal,
/*! Gets the session identifier associated with the specified target.
* @param targetIQN the name of the target.
* @return the session identiifer. */
-SID iSCSIGetSessionIdForTarget(CFStringRef targetIQN)
+SessionIdentifier iSCSISessionGetSessionIdForTarget(iSCSISessionManagerRef managerRef,
+ CFStringRef targetIQN)
{
- return iSCSIKernelGetSessionIdForTargetIQN(targetIQN);
+ iSCSIHBAInterfaceRef hbaInterface = iSCSISessionManagerGetHBAInterface(managerRef);
+ return iSCSIHBAInterfaceGetSessionIdForTargetIQN(hbaInterface,targetIQN);
}
/*! Gets the connection identifier associated with the specified portal.
* @param sessionId the session identifier.
* @param portal the portal connected on the specified session.
* @return the associated connection identifier. */
-CID iSCSIGetConnectionIdForPortal(SID sessionId,iSCSIPortalRef portal)
+ConnectionIdentifier iSCSISessionGetConnectionIdForPortal(iSCSISessionManagerRef managerRef,
+ SessionIdentifier sessionId,
+ iSCSIPortalRef portal)
{
- return iSCSIKernelGetConnectionIdForPortalAddress(sessionId,iSCSIPortalGetAddress(portal));
+ iSCSIHBAInterfaceRef hbaInterface = iSCSISessionManagerGetHBAInterface(managerRef);
+ return iSCSIHBAInterfaceGetConnectionIdForPortalAddress(hbaInterface,sessionId,iSCSIPortalGetAddress(portal));
}
/*! Gets an array of session identifiers for each session.
* @param sessionIds an array of session identifiers.
* @return an array of session identifiers. */
-CFArrayRef iSCSICreateArrayOfSessionIds()
+CFArrayRef iSCSISessionCopyArrayOfSessionIds(iSCSISessionManagerRef managerRef)
{
- SID sessionIds[kiSCSIMaxSessions];
+ iSCSIHBAInterfaceRef hbaInterface = iSCSISessionManagerGetHBAInterface(managerRef);
+ SessionIdentifier sessionIds[kiSCSIMaxSessions];
UInt16 sessionCount;
-
- if(iSCSIKernelGetSessionIds(sessionIds,&sessionCount))
+
+ if(iSCSIHBAInterfaceGetSessionIds(hbaInterface,sessionIds,&sessionCount))
return NULL;
return CFArrayCreate(kCFAllocatorDefault,(const void **) sessionIds,sessionCount,NULL);
@@ -1218,15 +1148,17 @@ CFArrayRef iSCSICreateArrayOfSessionIds()
/*! Gets an array of connection identifiers for each session.
* @param sessionId session identifier.
* @return an array of connection identifiers. */
-CFArrayRef iSCSICreateArrayOfConnectionsIds(SID sessionId)
+CFArrayRef iSCSISessionCopyArrayOfConnectionIds(iSCSISessionManagerRef managerRef,
+ SessionIdentifier sessionId)
{
if(sessionId == kiSCSIInvalidSessionId)
return NULL;
- CID connectionIds[kiSCSIMaxConnectionsPerSession];
+ iSCSIHBAInterfaceRef hbaInterface = iSCSISessionManagerGetHBAInterface(managerRef);
+ ConnectionIdentifier connectionIds[kiSCSIMaxConnectionsPerSession];
UInt32 connectionCount;
- if(iSCSIKernelGetConnectionIds(sessionId,connectionIds,&connectionCount))
+ if(iSCSIHBAInterfaceGetConnectionIds(hbaInterface,sessionId,connectionIds,&connectionCount))
return NULL;
return CFArrayCreate(kCFAllocatorDefault,(const void **)&connectionIds,connectionCount,NULL);
@@ -1235,12 +1167,13 @@ CFArrayRef iSCSICreateArrayOfConnectionsIds(SID sessionId)
/*! Creates a target object for the specified session.
* @param sessionId the session identifier.
* @return target the target object. */
-iSCSITargetRef iSCSICreateTargetForSessionId(SID sessionId)
+iSCSITargetRef iSCSISessionCopyTargetForId(iSCSISessionManagerRef managerRef,SessionIdentifier sessionId)
{
if(sessionId == kiSCSIInvalidSessionId)
return NULL;
- CFStringRef targetIQN = iSCSIKernelCreateTargetIQNForSessionId(sessionId);
+ iSCSIHBAInterfaceRef hbaInterface = iSCSISessionManagerGetHBAInterface(managerRef);
+ CFStringRef targetIQN = iSCSIHBAInterfaceCreateTargetIQNForSessionId(hbaInterface,sessionId);
if(!targetIQN)
return NULL;
@@ -1257,24 +1190,27 @@ iSCSITargetRef iSCSICreateTargetForSessionId(SID sessionId)
* @param sessionId the session identifier.
* @param connectionId the connection identifier.
* @return portal information about the portal. */
-iSCSIPortalRef iSCSICreatePortalForConnectionId(SID sessionId,CID connectionId)
+iSCSIPortalRef iSCSISessionCopyPortalForConnectionId(iSCSISessionManagerRef managerRef,
+ SessionIdentifier sessionId,
+ ConnectionIdentifier connectionId)
{
if(sessionId == kiSCSIInvalidSessionId || connectionId == kiSCSIInvalidConnectionId)
return NULL;
+ iSCSIHBAInterfaceRef hbaInterface = iSCSISessionManagerGetHBAInterface(managerRef);
CFStringRef address,port,hostInterface;
- if(!(address = iSCSIKernelCreatePortalAddressForConnectionId(sessionId,connectionId)))
+ if(!(address = iSCSIHBAInterfaceCreatePortalAddressForConnectionId(hbaInterface,sessionId,connectionId)))
return NULL;
- if(!(port = iSCSIKernelCreatePortalPortForConnectionId(sessionId,connectionId)))
+ if(!(port = iSCSIHBAInterfaceCreatePortalPortForConnectionId(hbaInterface,sessionId,connectionId)))
{
CFRelease(address);
return NULL;
}
- if(!(hostInterface = iSCSIKernelCreateHostInterfaceForConnectionId(sessionId,connectionId)))
+ if(!(hostInterface = iSCSIHBAInterfaceCreateHostInterfaceForConnectionId(hbaInterface,sessionId,connectionId)))
{
CFRelease(address);
CFRelease(port);
@@ -1298,51 +1234,53 @@ iSCSIPortalRef iSCSICreatePortalForConnectionId(SID sessionId,CID connectionId)
* @param target the target to check for associated sessions to generate
* a dictionary of session parameters.
* @return a dictionary of session properties. */
-CFDictionaryRef iSCSICreateCFPropertiesForSession(iSCSITargetRef target)
+CFDictionaryRef iSCSISessionCopyCFPropertiesForTarget(iSCSISessionManagerRef managerRef,
+ iSCSITargetRef target)
{
if(!target)
return NULL;
+ iSCSIHBAInterfaceRef hbaInterface = iSCSISessionManagerGetHBAInterface(managerRef);
CFDictionaryRef dictionary = NULL;
- SID sessionId = iSCSIGetSessionIdForTarget(iSCSITargetGetIQN(target));
+
+ SessionIdentifier sessionId = iSCSISessionGetSessionIdForTarget(managerRef,iSCSITargetGetIQN(target));
if(sessionId == kiSCSIInvalidSessionId)
return NULL;
// Get session options from kernel
-
- UInt32 optVal32 = 0;
+ UInt32 paramVal32 = 0;
- iSCSIKernelGetSessionOpt(sessionId,kiSCSIKernelSOMaxConnections,&optVal32,sizeof(optVal32));
- CFNumberRef maxConnections = CFNumberCreate(kCFAllocatorDefault,kCFNumberIntType,&optVal32);
+ iSCSIHBAInterfaceGetSessionParameter(hbaInterface,sessionId,kiSCSIHBASOMaxConnections,¶mVal32,sizeof(paramVal32));
+ CFNumberRef maxConnections = CFNumberCreate(kCFAllocatorDefault,kCFNumberIntType,¶mVal32);
- iSCSIKernelGetSessionOpt(sessionId,kiSCSIKernelSOMaxBurstLength,&optVal32,sizeof(optVal32));
- CFNumberRef maxBurstLength = CFNumberCreate(kCFAllocatorDefault,kCFNumberIntType,&optVal32);
+ iSCSIHBAInterfaceGetSessionParameter(hbaInterface,sessionId,kiSCSIHBASOMaxBurstLength,¶mVal32,sizeof(paramVal32));
+ CFNumberRef maxBurstLength = CFNumberCreate(kCFAllocatorDefault,kCFNumberIntType,¶mVal32);
- iSCSIKernelGetSessionOpt(sessionId,kiSCSIKernelSOFirstBurstLength,&optVal32,sizeof(optVal32));
- CFNumberRef firstBurstLength = CFNumberCreate(kCFAllocatorDefault,kCFNumberIntType,&optVal32);
+ iSCSIHBAInterfaceGetSessionParameter(hbaInterface,sessionId,kiSCSIHBASOFirstBurstLength,¶mVal32,sizeof(paramVal32));
+ CFNumberRef firstBurstLength = CFNumberCreate(kCFAllocatorDefault,kCFNumberIntType,¶mVal32);
- iSCSIKernelGetSessionOpt(sessionId,kiSCSIKernelSOMaxOutstandingR2T,&optVal32,sizeof(optVal32));
- CFNumberRef maxOutStandingR2T = CFNumberCreate(kCFAllocatorDefault,kCFNumberIntType,&optVal32);
+ iSCSIHBAInterfaceGetSessionParameter(hbaInterface,sessionId,kiSCSIHBASOMaxOutstandingR2T,¶mVal32,sizeof(paramVal32));
+ CFNumberRef maxOutStandingR2T = CFNumberCreate(kCFAllocatorDefault,kCFNumberIntType,¶mVal32);
- iSCSIKernelGetSessionOpt(sessionId,kiSCSIKernelSODefaultTime2Retain,&optVal32,sizeof(optVal32));
- CFNumberRef defaultTime2Retain = CFNumberCreate(kCFAllocatorDefault,kCFNumberIntType,&optVal32);
+ iSCSIHBAInterfaceGetSessionParameter(hbaInterface,sessionId,kiSCSIHBASODefaultTime2Retain,¶mVal32,sizeof(paramVal32));
+ CFNumberRef defaultTime2Retain = CFNumberCreate(kCFAllocatorDefault,kCFNumberIntType,¶mVal32);
- iSCSIKernelGetSessionOpt(sessionId,kiSCSIKernelSODefaultTime2Wait,&optVal32,sizeof(optVal32));
- CFNumberRef defaultTime2Wait = CFNumberCreate(kCFAllocatorDefault,kCFNumberIntType,&optVal32);
+ iSCSIHBAInterfaceGetSessionParameter(hbaInterface,sessionId,kiSCSIHBASODefaultTime2Wait,¶mVal32,sizeof(paramVal32));
+ CFNumberRef defaultTime2Wait = CFNumberCreate(kCFAllocatorDefault,kCFNumberIntType,¶mVal32);
- TPGT tpgt = 0;
- iSCSIKernelGetSessionOpt(sessionId,kiSCSIKernelSOTargetPortalGroupTag,&tpgt,sizeof(TPGT));
+ TargetPortalGroupTag tpgt = 0;
+ iSCSIHBAInterfaceGetSessionParameter(hbaInterface,sessionId,kiSCSIHBASOTargetPortalGroupTag,&tpgt,sizeof(TargetPortalGroupTag));
CFNumberRef targetPortalGroupTag = CFNumberCreate(kCFAllocatorDefault,kCFNumberSInt16Type,&tpgt);
- TSIH tsih = 0;
- iSCSIKernelGetSessionOpt(sessionId,kiSCSIKernelSOTargetSessionId,&tsih,sizeof(TSIH));
+ TargetSessionIdentifier tsih = 0;
+ iSCSIHBAInterfaceGetSessionParameter(hbaInterface,sessionId,kiSCSIHBASOTargetSessionId,&tsih,sizeof(TargetSessionIdentifier));
CFNumberRef targetSessionId = CFNumberCreate(kCFAllocatorDefault,kCFNumberSInt16Type,&tsih);
- UInt8 optVal8 = 0;
- iSCSIKernelGetSessionOpt(sessionId,kiSCSIKernelSOErrorRecoveryLevel,&optVal8,sizeof(optVal8));
- CFNumberRef errorRecoveryLevel = CFNumberCreate(kCFAllocatorDefault,kCFNumberSInt8Type,&optVal8);
+ UInt8 paramVal8 = 0;
+ iSCSIHBAInterfaceGetSessionParameter(hbaInterface,sessionId,kiSCSIHBASOErrorRecoveryLevel,¶mVal8,sizeof(paramVal8));
+ CFNumberRef errorRecoveryLevel = CFNumberCreate(kCFAllocatorDefault,kCFNumberSInt8Type,¶mVal8);
CFNumberRef sessionIdentifier = CFNumberCreate(kCFAllocatorDefault,kCFNumberSInt16Type,&sessionId);
@@ -1351,22 +1289,22 @@ CFDictionaryRef iSCSICreateCFPropertiesForSession(iSCSITargetRef target)
CFStringRef dataPDUInOrder = kRFC3720_Value_No;
CFStringRef dataSequenceInOrder = kRFC3720_Value_No;
- Boolean optValBool = false;
+ Boolean paramValBool = false;
- iSCSIKernelGetSessionOpt(sessionId,kiSCSIKernelSOImmediateData,&optValBool,sizeof(Boolean));
- if(optValBool)
+ iSCSIHBAInterfaceGetSessionParameter(hbaInterface,sessionId,kiSCSIHBASOImmediateData,¶mValBool,sizeof(Boolean));
+ if(paramValBool)
immediateData = kRFC3720_Value_Yes;
- iSCSIKernelGetSessionOpt(sessionId,kiSCSIKernelSOInitialR2T,&optValBool,sizeof(Boolean));
- if(optValBool)
+ iSCSIHBAInterfaceGetSessionParameter(hbaInterface,sessionId,kiSCSIHBASOInitialR2T,¶mValBool,sizeof(Boolean));
+ if(paramValBool)
initialR2T = kRFC3720_Value_Yes;
- iSCSIKernelGetSessionOpt(sessionId,kiSCSIKernelSODataPDUInOrder,&optValBool,sizeof(Boolean));
- if(optValBool)
+ iSCSIHBAInterfaceGetSessionParameter(hbaInterface,sessionId,kiSCSIHBASODataPDUInOrder,¶mValBool,sizeof(Boolean));
+ if(paramValBool)
dataPDUInOrder = kRFC3720_Value_Yes;
- iSCSIKernelGetSessionOpt(sessionId,kiSCSIKernelSODataSequenceInOrder,&optValBool,sizeof(Boolean));
- if(optValBool)
+ iSCSIHBAInterfaceGetSessionParameter(hbaInterface,sessionId,kiSCSIHBASODataSequenceInOrder,¶mValBool,sizeof(Boolean));
+ if(paramValBool)
dataSequenceInOrder = kRFC3720_Value_Yes;
const void * keys[] = {
@@ -1418,45 +1356,47 @@ CFDictionaryRef iSCSICreateCFPropertiesForSession(iSCSITargetRef target)
* @param portal the portal to check for active connections to generate
* a dictionary of connection parameters.
* @return a dictionary of connection properties. */
-CFDictionaryRef iSCSICreateCFPropertiesForConnection(iSCSITargetRef target,
+CFDictionaryRef iSCSISessionCopyCFPropertiesForPortal(iSCSISessionManagerRef managerRef,
+ iSCSITargetRef target,
iSCSIPortalRef portal)
{
if(!target || !portal)
return NULL;
+ iSCSIHBAInterfaceRef hbaInterface = iSCSISessionManagerGetHBAInterface(managerRef);
CFDictionaryRef dictionary = NULL;
- SID sessionId = iSCSIGetSessionIdForTarget(iSCSITargetGetIQN(target));
- CID connectionId = kiSCSIInvalidConnectionId;
+ SessionIdentifier sessionId = iSCSISessionGetSessionIdForTarget(managerRef,iSCSITargetGetIQN(target));
+ ConnectionIdentifier connectionId = kiSCSIInvalidConnectionId;
if(sessionId == kiSCSIInvalidSessionId)
return NULL;
// Validate connection identifier
- connectionId = iSCSIGetConnectionIdForPortal(sessionId,portal);
+ connectionId = iSCSISessionGetConnectionIdForPortal(managerRef,sessionId,portal);
if(connectionId == kiSCSIInvalidConnectionId)
return NULL;
// Get connection options from kernel
- UInt32 optVal32 = 0;
- iSCSIKernelGetConnectionOpt(sessionId,connectionId,kiSCSIKernelCOMaxRecvDataSegmentLength,&optVal32,sizeof(optVal32));
- CFNumberRef maxRecvDataSegmentLength = CFNumberCreate(kCFAllocatorDefault,kCFNumberIntType,&optVal32);
+ UInt32 paramVal32 = 0;
+ iSCSIHBAInterfaceGetConnectionParameter(hbaInterface,sessionId,connectionId,kiSCSIHBACOMaxRecvDataSegmentLength,¶mVal32,sizeof(paramVal32));
+ CFNumberRef maxRecvDataSegmentLength = CFNumberCreate(kCFAllocatorDefault,kCFNumberIntType,¶mVal32);
CFNumberRef connectionIdentifier = CFNumberCreate(kCFAllocatorDefault,kCFNumberIntType,&connectionId);
-
+
enum iSCSIDigestTypes dataDigestType = kiSCSIDigestNone;
enum iSCSIDigestTypes headerDigestType = kiSCSIDigestNone;
- Boolean optValBool = false;
+ Boolean paramValBool = false;
- iSCSIKernelGetConnectionOpt(sessionId,connectionId,kiSCSIKernelCOUseDataDigest,&optValBool,sizeof(Boolean));
- if(optValBool)
+ iSCSIHBAInterfaceGetConnectionParameter(hbaInterface,sessionId,connectionId,kiSCSIHBACOUseDataDigest,¶mValBool,sizeof(Boolean));
+ if(paramValBool)
dataDigestType = kiSCSIDigestCRC32C;
- iSCSIKernelGetConnectionOpt(sessionId,connectionId,kiSCSIKernelCOUseHeaderDigest,&optValBool,sizeof(Boolean));
- if(optValBool)
+ iSCSIHBAInterfaceGetConnectionParameter(hbaInterface,sessionId,connectionId,kiSCSIHBACOUseHeaderDigest,¶mValBool,sizeof(Boolean));
+ if(paramValBool)
dataDigestType = kiSCSIDigestCRC32C;
CFNumberRef dataDigest = CFNumberCreate(kCFAllocatorDefault,
@@ -1487,109 +1427,4 @@ CFDictionaryRef iSCSICreateCFPropertiesForConnection(iSCSITargetRef target,
return dictionary;
}
-/*! Sets the name of this initiator. This is the IQN-format name that is
- * exchanged with a target during negotiation.
- * @param initiatorIQN the initiator name. */
-void iSCSISetInitiatorName(CFStringRef initiatorIQN)
-{
- if(!initiatorIQN)
- return;
-
- CFRelease(kiSCSIInitiatorIQN);
- kiSCSIInitiatorIQN = CFStringCreateCopy(kCFAllocatorDefault,initiatorIQN);
-}
-
-/*! Sets the alias of this initiator. This is the IQN-format alias that is
- * exchanged with a target during negotiation.
- * @param initiatorAlias the initiator alias. */
-void iSCSISetInitiatorAlias(CFStringRef initiatorAlias)
-{
- if(!initiatorAlias)
- return;
-
- CFRelease(kiSCSIInitiatorAlias);
- kiSCSIInitiatorAlias = CFStringCreateCopy(kCFAllocatorDefault,initiatorAlias);
-}
-
-/*! The kernel calls this function only for asynchronous events that
- * involve dropped sessions, connections, logout requests and parameter
- * negotiation. This function is not called for asynchronous SCSI messages
- * or vendor-specific messages. */
-void iSCSISessionHandleKernelNotificationAsyncMessage(iSCSIKernelNotificationAsyncMessage * msg)
-{
- enum iSCSIPDUAsyncMsgEvent asyncEvent = (enum iSCSIPDUAsyncMsgEvent)msg->asyncEvent;
- enum iSCSILogoutStatusCode statusCode;
-
- CFStringRef statusString = CFStringCreateWithFormat(kCFAllocatorDefault,0,
- CFSTR("iSCSI asynchronous message (code %d) received (sid: %d, cid: %d)"),
- asyncEvent,msg->sessionId,msg->connectionId);
-
- asl_log(NULL,NULL,ASL_LEVEL_WARNING,"%s",CFStringGetCStringPtr(statusString,kCFStringEncodingASCII));
-
- CFRelease(statusString);
-
- switch (asyncEvent) {
-
- // We are required to issue a logout request
- case kiSCSIPDUAsyncMsgLogout:
- iSCSILogoutConnection(msg->sessionId,msg->connectionId,&statusCode);
- break;
-
- // We have been asked to re-negotiate parameters for this connection
- // (this is currently unsupported and we logout)
- case kiSCSIPDUAsyncMsgNegotiateParams:
- iSCSILogoutConnection(msg->sessionId,msg->connectionId,&statusCode);
- break;
-
- default:
- break;
- }
-}
-
-/*! This function is called by the kernel extension to notify the daemon
- * of an event that has occured within the kernel extension. */
-void iSCSISessionHandleKernelNotifications(enum iSCSIKernelNotificationTypes type,
- iSCSIKernelNotificationMessage * msg)
-{
- // Process an asynchronous message
- switch(type)
- {
- // The kernel received an iSCSI asynchronous event message
- case kiSCSIKernelNotificationAsyncMessage:
- iSCSISessionHandleKernelNotificationAsyncMessage((iSCSIKernelNotificationAsyncMessage *)msg);
- break;
- case kISCSIKernelNotificationTerminate: break;
- default: break;
- };
-}
-
-/*! Call to initialize iSCSI session management functions. This function will
- * initialize the kernel layer after which other session-related functions
- * may be called.
- * @param rl the runloop to use for executing session-related functions.
- * @return an error code indicating the result of the operation. */
-errno_t iSCSIInitialize(CFRunLoopRef rl)
-{
- errno_t error = iSCSIKernelInitialize(&iSCSISessionHandleKernelNotifications);
-
- if(!error) {
- CFRunLoopSourceRef source;
-
- // Create a run loop source tied to the kernel notification system;
- // if fail then kext may not be loaded, try again later
- if((source = iSCSIKernelCreateRunLoopSource()))
- CFRunLoopAddSource(rl,source,kCFRunLoopDefaultMode);
- else
- error = EAGAIN;
- }
- return error;
-}
-/*! Called to cleanup kernel resources used by the iSCSI session management
- * functions. This function will close any connections to the kernel
- * and stop processing messages related to the kernel.
- * @return an error code indicating the result of the operation. */
-errno_t iSCSICleanup()
-{
- return iSCSIKernelCleanup();
-}
diff --git a/Source/User/iscsid/iSCSISession.h b/Source/User/iscsid/iSCSISession.h
index dd7c235a..d6da6126 100644
--- a/Source/User/iscsid/iSCSISession.h
+++ b/Source/User/iscsid/iSCSISession.h
@@ -30,28 +30,13 @@
#define __ISCSI_SESSION_H__
#include
-#include
-#include
-#include
-
-#include "iSCSITypes.h"
-#include "iSCSIRFC3720Keys.h"
-
-/*! Call to initialize iSCSI session management functions. This function will
- * initialize the kernel layer after which other session-related functions
- * may be called.
- * @param rl the runloop to use for executing session-related functions.
- * @return an error code indicating the result of the operation. */
-errno_t iSCSIInitialize(CFRunLoopRef rl);
-
-/*! Called to cleanup kernel resources used by the iSCSI session management
- * functions. This function will close any connections to the kernel
- * and stop processing messages related to the kernel.
- * @return an error code indicating the result of the operation. */
-errno_t iSCSICleanup();
+
+#include "iSCSISessionManager.h"
+#include "iSCSI.h"
/*! Creates a normal iSCSI session and returns a handle to the session. Users
* must call iSCSISessionClose to close this session and free resources.
+ * @param managerRef a session manager instance.
* @param target specifies the target and connection parameters to use.
* @param portal specifies the portal to use for the new session.
* @param initiatorAuth specifies the initiator authentication parameters.
@@ -62,22 +47,26 @@ errno_t iSCSICleanup();
* @param connectionId the new connection identifier.
* @param statusCode iSCSI response code indicating operation status.
* @return an error code indicating whether the operation was successful. */
-errno_t iSCSILoginSession(iSCSIMutableTargetRef target,
+errno_t iSCSISessionLogin(iSCSISessionManagerRef managerRef,
+ iSCSIMutableTargetRef target,
iSCSIPortalRef portal,
iSCSIAuthRef initiatorAuth,
iSCSIAuthRef targetAuth,
iSCSISessionConfigRef sessCfg,
iSCSIConnectionConfigRef connCfg,
- SID * sessionId,
- CID * connectionId,
+ SessionIdentifier * sessionId,
+ ConnectionIdentifier * connectionId,
enum iSCSILoginStatusCode * statusCode);
/*! Closes the iSCSI connection and frees the session qualifier.
+ * @param managerRef a session manager instance.
* @param sessionId the session to free. */
-errno_t iSCSILogoutSession(SID sessionId,
+errno_t iSCSISessionLogout(iSCSISessionManagerRef managerRef,
+ SessionIdentifier sessionId,
enum iSCSILogoutStatusCode * statusCode);
/*! Adds a new connection to an iSCSI session.
+ * @param managerRef a session manager instance.
* @param sessionId the new session identifier.
* @param portal specifies the portal to use for the connection.
* @param initiatorAuth specifies the initiator authentication parameters.
@@ -86,77 +75,95 @@ errno_t iSCSILogoutSession(SID sessionId,
* @param connectionId the new connection identifier.
* @param statusCode iSCSI response code indicating operation status.
* @return an error code indicating whether the operation was successful. */
-errno_t iSCSILoginConnection(SID sessionId,
- iSCSIPortalRef portal,
- iSCSIAuthRef initiatorAuth,
- iSCSIAuthRef targetAuth,
- iSCSIConnectionConfigRef connCfg,
- CID * connectionId,
- enum iSCSILoginStatusCode * statusCode);
+errno_t iSCSISessionAddConnection(iSCSISessionManagerRef managerRef,
+ SessionIdentifier sessionId,
+ iSCSIPortalRef portal,
+ iSCSIAuthRef initiatorAuth,
+ iSCSIAuthRef targetAuth,
+ iSCSIConnectionConfigRef connCfg,
+ ConnectionIdentifier * connectionId,
+ enum iSCSILoginStatusCode * statusCode);
/*! Removes a connection from an existing session.
+ * @param managerRef a session manager instance.
* @param sessionId the session to remove a connection from.
* @param connectionId the connection to remove.
* @param statusCode iSCSI response code indicating operation status.
* @return an error code indicating whether the operation was successful. */
-errno_t iSCSILogoutConnection(SID sessionId,
- CID connectionId,
- enum iSCSILogoutStatusCode * statusCode);
+errno_t iSCSISessionRemoveConnection(iSCSISessionManagerRef managerRef,
+ SessionIdentifier sessionId,
+ ConnectionIdentifier connectionId,
+ enum iSCSILogoutStatusCode * statusCode);
/*! Queries a portal for available targets (utilizes iSCSI SendTargets).
+ * @param managerRef a session manager instance.
* @param portal the iSCSI portal to query.
* @param auth specifies the authentication parameters to use.
* @param discoveryRec a discovery record, containing the query results.
* @param statusCode iSCSI response code indicating operation status.
* @return an error code indicating whether the operation was successful. */
-errno_t iSCSIQueryPortalForTargets(iSCSIPortalRef portal,
+errno_t iSCSIQueryPortalForTargets(iSCSISessionManagerRef managerRef,
+ iSCSIPortalRef portal,
iSCSIAuthRef initiatorAuth,
iSCSIMutableDiscoveryRecRef * discoveryRec,
enum iSCSILoginStatusCode * statuscode);
/*! Retrieves a list of targets available from a give portal.
+ * @param managerRef a session manager instance.
* @param portal the iSCSI portal to look for targets.
* @param initiatorAuth specifies the initiator authentication parameters.
* @param statusCode iSCSI response code indicating operation status.
* @return an error code indicating whether the operation was successful. */
-errno_t iSCSIQueryTargetForAuthMethod(iSCSIPortalRef portal,
+errno_t iSCSIQueryTargetForAuthMethod(iSCSISessionManagerRef managerRef,
+ iSCSIPortalRef portal,
CFStringRef targetIQN,
enum iSCSIAuthMethods * authMethod,
enum iSCSILoginStatusCode * statusCode);
/*! Gets the session identifier associated with the specified target.
+ * @param managerRef a session manager instance.
* @param targetIQN the name of the target.
* @return the session identiifer. */
-SID iSCSIGetSessionIdForTarget(CFStringRef targetIQN);
+SessionIdentifier iSCSISessionGetSessionIdForTarget(iSCSISessionManagerRef managerRef,
+ CFStringRef targetIQN);
/*! Gets the connection identifier associated with the specified portal.
+ * @param managerRef a session manager instance.
* @param sessionId the session identifier.
* @param portal the portal connected on the specified session.
* @return the associated connection identifier. */
-CID iSCSIGetConnectionIdForPortal(SID sessionId,iSCSIPortalRef portal);
+ConnectionIdentifier iSCSISessionGetConnectionIdForPortal(iSCSISessionManagerRef managerRef,
+ SessionIdentifier sessionId,
+ iSCSIPortalRef portal);
/*! Gets an array of session identifiers for each session.
+ * @param managerRef a session manager instance.
* @param sessionIds an array of session identifiers.
* @return an array of session identifiers. */
-CFArrayRef iSCSICreateArrayOfSessionIds();
+CFArrayRef iSCSISessionCopyArrayOfSessionIds(iSCSISessionManagerRef managerRef);
/*! Gets an array of connection identifiers for each session.
+ * @param managerRef a session manager instance.
* @param sessionId session identifier.
* @return an array of connection identifiers. */
-CFArrayRef iSCSICreateArrayOfConnectionsIds(SID sessionId);
+CFArrayRef iSCSISessionCopyArrayOfConnectionIds(iSCSISessionManagerRef managerRef,
+ SessionIdentifier sessionId);
/*! Creates a target object for the specified session.
+ * @param managerRef a session manager instance.
* @param sessionId the session identifier.
* @return target the target object. */
-iSCSITargetRef iSCSICreateTargetForSessionId(SID sessionId);
+iSCSITargetRef iSCSISessionCopyTargetForId(iSCSISessionManagerRef managerRef,
+ SessionIdentifier sessionId);
/*! Creates a connection object for the specified connection.
+ * @param managerRef a session manager instance.
* @param sessionId the session identifier.
* @param connectionId the connection identifier.
* @return portal information about the portal. */
-iSCSIPortalRef iSCSICreatePortalForConnectionId(SID sessionId,CID connectionId);
-
-
+iSCSIPortalRef iSCSISessionCopyPortalForConnectionId(iSCSISessionManagerRef managerRef,
+ SessionIdentifier sessionId,
+ ConnectionIdentifier connectionId);
/*! Creates a dictionary of session parameters for the session associated with
* the specified target, if one exists. The following keys are guaranteed
@@ -177,11 +184,12 @@ iSCSIPortalRef iSCSICreatePortalForConnectionId(SID sessionId,CID connectionId);
* kRFC3720_Key_TargetSessionId (CFNumberRef, kCFNumberSInt16Type)
* kRFC3720_Key_SessionId (CFNumberRef, kCFNumberSInt16Type)
*
- * @param handle a handle to a daemon connection.
+ * @param managerRef a session manager instance.
* @param target the target to check for associated sessions to generate
* a dictionary of session parameters.
* @return a dictionary of session properties. */
-CFDictionaryRef iSCSICreateCFPropertiesForSession(iSCSITargetRef target);
+CFDictionaryRef iSCSISessionCopyCFPropertiesForTarget(iSCSISessionManagerRef managerRef,
+ iSCSITargetRef target);
/*! Creates a dictionary of connection parameters for the connection associated
* with the specified target and portal, if one exists. The following keys
@@ -192,23 +200,14 @@ CFDictionaryRef iSCSICreateCFPropertiesForSession(iSCSITargetRef target);
* kRFC3720_Key_MaxRecvDataSegmentLength (CFNumberRef)
* kRFC3720_Key_ConnectionId (CFNumberRef)
*
- * @param handle a handle to a daemon connection.
+ * @param managerRef a session manager instance.
* @param target the target associated with the the specified portal.
* @param portal the portal to check for active connections to generate
* a dictionary of connection parameters.
* @return a dictionary of connection properties. */
-CFDictionaryRef iSCSICreateCFPropertiesForConnection(iSCSITargetRef target,
- iSCSIPortalRef portal);
-
-/*! Sets the name of this initiator. This is the IQN-format name that is
- * exchanged with a target during negotiation.
- * @param initiatorIQN the initiator name. */
-void iSCSISetInitiatorName(CFStringRef initiatorIQN);
-
-/*! Sets the alias of this initiator. This is the IQN-format alias that is
- * exchanged with a target during negotiation.
- * @param initiatorAlias the initiator alias. */
-void iSCSISetInitiatorAlias(CFStringRef initiatorAlias);
+CFDictionaryRef iSCSISessionCopyCFPropertiesForPortal(iSCSISessionManagerRef managerRef,
+ iSCSITargetRef target,
+ iSCSIPortalRef portal);
#endif
diff --git a/Source/User/iscsid/iSCSISessionManager.c b/Source/User/iscsid/iSCSISessionManager.c
new file mode 100644
index 00000000..1aa32a6f
--- /dev/null
+++ b/Source/User/iscsid/iSCSISessionManager.c
@@ -0,0 +1,210 @@
+/*
+ * Copyright (c) 2016, Nareg Sinenian
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.
+ */
+
+#include "iSCSISessionManager.h"
+
+#include "iSCSISession.h"
+#include "iSCSIHBAInterface.h"
+
+/*! Name of the initiator. */
+CFStringRef kiSCSIInitiatorIQN = CFSTR("iqn.2015-01.com.localhost");
+
+/*! Alias of the initiator. */
+CFStringRef kiSCSIInitiatorAlias = CFSTR("default");
+
+struct __iSCSISessionManager
+{
+ CFAllocatorRef allocator;
+ iSCSIHBAInterfaceRef hbaInterface;
+ iSCSISessionManagerCallBacks callbacks;
+ CFStringRef initiatorName;
+ CFStringRef initiatorAlias;
+
+};
+
+/*! This function is called handle session or connection network timeouts.
+ * When a timeout occurs the kernel deactivates the session and connection.
+ * The session layer (this layer) must release the connection after propogating
+ * the notification onto the user of the session manager. */
+ void iSCSIHBANotificationTimeoutMessageHandler(iSCSISessionManagerRef managerRef,
+ iSCSIHBANotificationMessage * msg)
+ {
+ // Retrieve the target name and portal address associated with
+ // the timeout. Pass information along to pre-designated runloop
+ // so that clients of this layer can act
+ iSCSITargetRef target = iSCSISessionCopyTargetForId(managerRef,msg->sessionId);
+ iSCSIPortalRef portal = iSCSISessionCopyPortalForConnectionId(managerRef,msg->sessionId,msg->connectionId);
+
+ // Release the stale session/connection
+ iSCSIHBAInterfaceReleaseConnection(managerRef->hbaInterface,msg->sessionId,msg->connectionId);
+
+ // Call user-defined callback function if one exists
+ if(managerRef->callbacks.timeoutCallback)
+ managerRef->callbacks.timeoutCallback(target,portal);
+ }
+
+/*! Called to handle asynchronous events that involve dropped sessions, connections,
+ * logout requests and parameter negotiation. This function is not called for asynchronous
+ * SCSI messages or vendor-specific messages. */
+void iSCSIHBANotificationAsyncMessageHandler(iSCSISessionManagerRef managerRef,
+ iSCSIHBANotificationAsyncMessage * msg)
+{
+ enum iSCSIPDUAsyncMsgEvent asyncEvent = (enum iSCSIPDUAsyncMsgEvent)msg->asyncEvent;
+ enum iSCSILogoutStatusCode statusCode;
+
+ switch (asyncEvent) {
+
+ // We are required to issue a logout request
+ case kiSCSIPDUAsyncMsgLogout:
+ iSCSISessionRemoveConnection(managerRef,msg->sessionId,msg->connectionId,&statusCode);
+ break;
+
+ // We have been asked to re-negotiate parameters for this connection
+ // (this is currently unsupported and we logout)
+ case kiSCSIPDUAsyncMsgNegotiateParams:
+ iSCSISessionRemoveConnection(managerRef,msg->sessionId,msg->connectionId,&statusCode);
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void iSCSIHBANotificationHandler(iSCSIHBAInterfaceRef interface,
+ enum iSCSIHBANotificationTypes type,
+ iSCSIHBANotificationMessage * msg,void * info)
+{
+ iSCSISessionManagerRef managerRef = (iSCSISessionManagerRef)info;
+
+ // Process an asynchronous message
+ switch(type)
+ {
+ // The kernel received an iSCSI asynchronous event message
+ case kiSCSIHBANotificationAsyncMessage:
+ iSCSIHBANotificationAsyncMessageHandler(managerRef,(iSCSIHBANotificationAsyncMessage *)msg);
+ break;
+ case kiSCSIHBANotificationTimeout:
+ iSCSIHBANotificationTimeoutMessageHandler(managerRef,(iSCSIHBANotificationMessage *)msg);
+ break;
+ case kiSCSIHBANotificationTerminate: break;
+ default: break;
+ };
+}
+
+/*! Call to initialize iSCSI session management functions. This function will
+ * initialize the kernel layer after which other session-related functions
+ * may be called.
+ * @param rl the runloop to use for executing session-related functions.
+ * @return an error code indicating the result of the operation. */
+iSCSISessionManagerRef iSCSISessionManagerCreate(CFAllocatorRef allocator,
+ iSCSISessionManagerCallBacks callbacks)
+{
+ iSCSISessionManagerRef managerRef = CFAllocatorAllocate(allocator,sizeof(struct __iSCSISessionManager),0);
+
+ iSCSIHBANotificationContext notifyContext;
+ notifyContext.version = 0;
+ notifyContext.info = managerRef;
+ notifyContext.release = 0;
+ notifyContext.retain = 0;
+ notifyContext.copyDescription = 0;
+
+ iSCSIHBAInterfaceRef interface = iSCSIHBAInterfaceCreate(allocator,iSCSIHBANotificationHandler,¬ifyContext);
+
+ managerRef->allocator = allocator;
+ managerRef->hbaInterface = interface;
+ managerRef->callbacks = callbacks;
+ managerRef->initiatorName = kiSCSIInitiatorIQN;
+ managerRef->initiatorAlias = kiSCSIInitiatorAlias;
+
+ return managerRef;
+}
+
+/*! Called to cleanup kernel resources used by the iSCSI session management
+ * functions. This function will close any connections to the kernel
+ * and stop processing messages related to the kernel.
+ * @param managerRef an instance of an iSCSISessionManagerRef. */
+void iSCSISessionManagerRelease(iSCSISessionManagerRef managerRef)
+{
+ CFAllocatorDeallocate(managerRef->allocator,managerRef);
+}
+
+/*! Creates a runloop source used to run the callback functions associated
+ * with the session manager reference. */
+/*! Schedules execution of various tasks, including handling of kernel notifications
+ * on for the specified interface instance over the designated runloop.
+ * @param managerRef an instance of an iSCSISessionManagerRef.
+ * @param runLoop the runloop to schedule
+ * @param runLoopMode the execution mode for the runLoop. */
+void iSCSISessionManagerScheduleWithRunLoop(iSCSISessionManagerRef managerRef,
+ CFRunLoopRef runLoop,
+ CFStringRef runLoopMode)
+{
+ iSCSIHBAInterfaceScheduleWithRunloop(managerRef->hbaInterface,runLoop,runLoopMode);
+}
+
+/*! Unschedules execution of various tasks, including handling of session notifications
+ * on for the specified interface instance over the designated runloop.
+ * @param managerRef an instance of an iSCSISessionManagerRef.
+ * @param runLoop the runloop to schedule
+ * @param runLoopMode the execution mode for the runLoop. */
+void iSCSISessionManagerUnscheduleWithRunloop(iSCSISessionManagerRef managerRef,
+ CFRunLoopRef runLoop,
+ CFStringRef runLoopMode)
+{
+ iSCSIHBAInterfaceScheduleWithRunloop(managerRef->hbaInterface,runLoop,runLoopMode);
+}
+
+/*! Returns a reference to the underlying HBA interface instance.
+ * @param managerRef an instance of an iSCSISessionManagerRef.
+ * @return a reference to the underlying HBA interface instance. */
+iSCSIHBAInterfaceRef iSCSISessionManagerGetHBAInterface(iSCSISessionManagerRef managerRef)
+{
+ return managerRef->hbaInterface;
+}
+
+/*! Sets the initiator name to use for new sessions. This is the IQN-format name that is
+ * exchanged with a target during negotiation.
+ * @param managerRef an instance of an iSCSISessionManagerRef.
+ * @param initiatorIQN the initiator name. */
+void iSCSISessionManagerSetInitiatorName(iSCSISessionManagerRef managerRef,
+ CFStringRef initiatorIQN)
+{
+ CFRelease(managerRef->initiatorName);
+ managerRef->initiatorName = CFStringCreateCopy(kCFAllocatorDefault,initiatorIQN);
+}
+
+/*! Sets the initiator alias to use for new sessions. This is the IQN-format alias that is
+ * exchanged with a target during negotiation.
+ * @param managerRef an instance of an iSCSISessionManagerRef.
+ * @param initiatorAlias the initiator alias. */
+void iSCSISessionManagerSetInitiatorAlias(iSCSISessionManagerRef managerRef,
+ CFStringRef initiatorAlias)
+{
+ CFRelease(managerRef->initiatorAlias);
+ managerRef->initiatorAlias = CFStringCreateCopy(kCFAllocatorDefault,initiatorAlias);
+}
diff --git a/Source/User/iscsid/iSCSISessionManager.h b/Source/User/iscsid/iSCSISessionManager.h
new file mode 100644
index 00000000..16dd1122
--- /dev/null
+++ b/Source/User/iscsid/iSCSISessionManager.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2016, Nareg Sinenian
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.
+ */
+
+#ifndef __ISCSI_SESSION_MANAGER_H__
+#define __ISCSI_SESSION_MANAGER_H__
+
+#include
+#include "iSCSI.h"
+#include "iSCSIHBAInterface.h"
+
+/*! Opaque session manager reference. */
+typedef struct __iSCSISessionManager * iSCSISessionManagerRef;
+
+/*! Callback function called when a session or connection timeout occurs. */
+typedef void (*iSCSISessionTimeoutCallback)(iSCSITargetRef target,iSCSIPortalRef portal);
+
+/*! Callback types used by the session manager. */
+typedef struct iSCSISessionManagerCallBacks
+{
+ iSCSISessionTimeoutCallback timeoutCallback;
+
+} iSCSISessionManagerCallBacks;
+
+/*! Call to initialize iSCSI session management functions. This function will
+ * initialize the kernel layer after which other session-related functions
+ * may be called.
+ * @param rl the runloop to use for executing session-related functions.
+ * @return an error code indicating the result of the operation. */
+iSCSISessionManagerRef iSCSISessionManagerCreate(CFAllocatorRef allocator,
+ iSCSISessionManagerCallBacks callbacks);
+
+/*! Called to cleanup kernel resources used by the iSCSI session management
+ * functions. This function will close any connections to the kernel
+ * and stop processing messages related to the kernel.
+ * @param sessionManager an instance of an iSCSISessionManagerRef. */
+void iSCSISessionManagerRelease(iSCSISessionManagerRef managerRef);
+
+/*! Creates a runloop source used to run the callback functions associated
+ * with the session manager reference. */
+/*! Schedules execution of various tasks, including handling of kernel notifications
+ * on for the specified interface instance over the designated runloop.
+ * @param managerRef an instance of an iSCSISessionManagerRef.
+ * @param runLoop the runloop to schedule
+ * @param runLoopMode the execution mode for the runLoop. */
+void iSCSISessionManagerScheduleWithRunLoop(iSCSISessionManagerRef managerRef,
+ CFRunLoopRef runLoop,
+ CFStringRef runLoopMode);
+
+/*! Unschedules execution of various tasks, including handling of session notifications
+ * on for the specified interface instance over the designated runloop.
+ * @param managerRef an instance of an iSCSISessionManagerRef.
+ * @param runLoop the runloop to schedule
+ * @param runLoopMode the execution mode for the runLoop. */
+void iSCSISessionManagerUnscheduleWithRunloop(iSCSISessionManagerRef managerRef,
+ CFRunLoopRef runLoop,
+ CFStringRef runLoopMode);
+
+/*! Returns a reference to the underlying HBA interface instance.
+ * @param managerRef an instance of an iSCSISessionManagerRef.
+ * @return a reference to the underlying HBA interface instance. */
+iSCSIHBAInterfaceRef iSCSISessionManagerGetHBAInterface(iSCSISessionManagerRef managerRef);
+
+/*! Sets the initiator name to use for new sessions. This is the IQN-format name that is
+ * exchanged with a target during negotiation.
+ * @param managerRef an instance of an iSCSISessionManagerRef.
+ * @param initiatorIQN the initiator name. */
+void iSCSISessionManagerSetInitiatorName(iSCSISessionManagerRef managerRef,
+ CFStringRef initiatorIQN);
+
+/*! Sets the initiator aliias to use for new sessions. This is the IQN-format alias that is
+ * exchanged with a target during negotiation.
+ * @param managerRef an instance of an iSCSISessionManagerRef.
+ * @param initiatorAlias the initiator alias. */
+void iSCSISessionManagerSetInitiatorAlias(iSCSISessionManagerRef managerRef,
+ CFStringRef initiatorAlias);
+
+
+#endif
diff --git a/iSCSIInitiator.xcodeproj/project.pbxproj b/iSCSIInitiator.xcodeproj/project.pbxproj
index e97979c5..8179496f 100644
--- a/iSCSIInitiator.xcodeproj/project.pbxproj
+++ b/iSCSIInitiator.xcodeproj/project.pbxproj
@@ -9,10 +9,11 @@
/* Begin PBXBuildFile section */
2B171E421CE23677003C3E08 /* iSCSIAuthRights.c in Sources */ = {isa = PBXBuildFile; fileRef = 2B171E401CE23677003C3E08 /* iSCSIAuthRights.c */; };
2B171E431CE23677003C3E08 /* iSCSIAuthRights.h in Headers */ = {isa = PBXBuildFile; fileRef = 2B171E411CE23677003C3E08 /* iSCSIAuthRights.h */; };
- 2B1EDC121CFAEC1F007BAB99 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 2B1EDC111CFAEC1F007BAB99 /* AppDelegate.m */; };
- 2B1EDC151CFAEC1F007BAB99 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 2B1EDC141CFAEC1F007BAB99 /* main.m */; };
- 2B1EDC1A1CFAEC1F007BAB99 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2B1EDC191CFAEC1F007BAB99 /* Assets.xcassets */; };
- 2B1EDC1D1CFAEC1F007BAB99 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2B1EDC1B1CFAEC1F007BAB99 /* Main.storyboard */; };
+ 2B180B861D3B752A005EFF14 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2B180B851D3B752A005EFF14 /* SystemConfiguration.framework */; };
+ 2B1A490F1D3D40FE00D3ED0D /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = 2B1A490E1D3D40FE00D3ED0D /* main.c */; };
+ 2B1A49131D3D412700D3ED0D /* iSCSI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2B7A0B741C8AEC47008290E9 /* iSCSI.framework */; };
+ 2B1A49141D3D416000D3ED0D /* iSCSIPDUUser.c in Sources */ = {isa = PBXBuildFile; fileRef = 2BDE5E331C8B0281004BDB5F /* iSCSIPDUUser.c */; };
+ 2B1A49151D3D416800D3ED0D /* iSCSIHBAInterface.c in Sources */ = {isa = PBXBuildFile; fileRef = 2BDE5E311C8B0281004BDB5F /* iSCSIHBAInterface.c */; };
2B459D551B7B8192008F656F /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2B459D541B7B8192008F656F /* Security.framework */; };
2B4A60371A3E6F690006AFCC /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2B5935C21810DF7100FFC3D3 /* IOKit.framework */; };
2B4A60381A3E6F830006AFCC /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2B9CAB9A185527EC00F3A9C6 /* CoreFoundation.framework */; };
@@ -21,18 +22,14 @@
2B5C213C1C70871A00ED8791 /* DiskArbitration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2BC4CBB11AA55046003611F7 /* DiskArbitration.framework */; };
2B5C213D1C70872400ED8791 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2B459D541B7B8192008F656F /* Security.framework */; };
2B5C213E1C70872E00ED8791 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2B9CAB9A185527EC00F3A9C6 /* CoreFoundation.framework */; };
- 2B7762991CFF220D003093CC /* NodeViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2B7762921CFEF9E7003093CC /* NodeViewController.m */; };
- 2B77629A1CFF2211003093CC /* Node.m in Sources */ = {isa = PBXBuildFile; fileRef = 2B7762941CFEF9E7003093CC /* Node.m */; };
- 2B77629B1D00B388003093CC /* iSCSI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2B7A0B741C8AEC47008290E9 /* iSCSI.framework */; };
- 2B77629E1D02CC9D003093CC /* InitiatorViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2B77629D1D02CC9D003093CC /* InitiatorViewController.m */; };
+ 2B6BCCB91D3A7857003522BC /* iSCSISessionManager.c in Sources */ = {isa = PBXBuildFile; fileRef = 2B6BCCB61D354EA0003522BC /* iSCSISessionManager.c */; };
2B9E3C941C493BAA00440116 /* iSCSIInitiator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2B9E3C711C493B9C00440116 /* iSCSIInitiator.cpp */; settings = {COMPILER_FLAGS = "-Wno-inconsistent-missing-override"; }; };
- 2B9E3C961C493BAA00440116 /* iSCSIInitiatorClient.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2B9E3C731C493B9C00440116 /* iSCSIInitiatorClient.cpp */; settings = {COMPILER_FLAGS = "-Wno-inconsistent-missing-override"; }; };
+ 2B9E3C961C493BAA00440116 /* iSCSIHBAUserClient.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2B9E3C731C493B9C00440116 /* iSCSIHBAUserClient.cpp */; settings = {COMPILER_FLAGS = "-Wno-inconsistent-missing-override"; }; };
2B9E3C981C493BAA00440116 /* iSCSIIOEventSource.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2B9E3C751C493B9C00440116 /* iSCSIIOEventSource.cpp */; settings = {COMPILER_FLAGS = "-Wno-inconsistent-missing-override"; }; };
2B9E3C9C1C493BAA00440116 /* iSCSIPDUKernel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2B9E3C791C493B9C00440116 /* iSCSIPDUKernel.cpp */; settings = {COMPILER_FLAGS = "-Wno-inconsistent-missing-override"; }; };
2B9E3CA01C493BAA00440116 /* iSCSITaskQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2B9E3C7D1C493B9C00440116 /* iSCSITaskQueue.cpp */; settings = {COMPILER_FLAGS = "-Wno-inconsistent-missing-override"; }; };
2B9E3CA31C493BAA00440116 /* iSCSIVirtualHBA.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2B9E3C801C493B9C00440116 /* iSCSIVirtualHBA.cpp */; settings = {COMPILER_FLAGS = "-Wno-inconsistent-missing-override"; }; };
2B9E3CBE1C49ED0000440116 /* crc32c.c in Sources */ = {isa = PBXBuildFile; fileRef = 2B9E3CBA1C49ECF900440116 /* crc32c.c */; };
- 2BAAB8B71D03E8EF00C01C79 /* SplitViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2BAAB8B61D03E8EF00C01C79 /* SplitViewController.m */; };
2BC4CBB21AA55046003611F7 /* DiskArbitration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2BC4CBB11AA55046003611F7 /* DiskArbitration.framework */; };
2BDE5E281C8B0274004BDB5F /* iscsictl.8 in Resources */ = {isa = PBXBuildFile; fileRef = 2BDE5E261C8B0274004BDB5F /* iscsictl.8 */; };
2BDE5E6E1C8B0292004BDB5F /* Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 2BDE5E481C8B028B004BDB5F /* Info.plist */; };
@@ -57,7 +54,7 @@
2BDE5E881C8B3E7D004BDB5F /* iSCSIAuth.c in Sources */ = {isa = PBXBuildFile; fileRef = 2BDE5E2B1C8B0281004BDB5F /* iSCSIAuth.c */; };
2BDE5E891C8B3E7D004BDB5F /* iSCSIDaemon.c in Sources */ = {isa = PBXBuildFile; fileRef = 2BDE5E2E1C8B0281004BDB5F /* iSCSIDaemon.c */; };
2BDE5E8A1C8B3E7D004BDB5F /* iSCSIDiscovery.c in Sources */ = {isa = PBXBuildFile; fileRef = 2BDE5E2F1C8B0281004BDB5F /* iSCSIDiscovery.c */; };
- 2BDE5E8B1C8B3E7D004BDB5F /* iSCSIKernelInterface.c in Sources */ = {isa = PBXBuildFile; fileRef = 2BDE5E311C8B0281004BDB5F /* iSCSIKernelInterface.c */; };
+ 2BDE5E8B1C8B3E7D004BDB5F /* iSCSIHBAInterface.c in Sources */ = {isa = PBXBuildFile; fileRef = 2BDE5E311C8B0281004BDB5F /* iSCSIHBAInterface.c */; };
2BDE5E8C1C8B3E7D004BDB5F /* iSCSIPDUUser.c in Sources */ = {isa = PBXBuildFile; fileRef = 2BDE5E331C8B0281004BDB5F /* iSCSIPDUUser.c */; };
2BDE5E8D1C8B3E7D004BDB5F /* iSCSIQueryTarget.c in Sources */ = {isa = PBXBuildFile; fileRef = 2BDE5E351C8B0281004BDB5F /* iSCSIQueryTarget.c */; };
2BDE5E8E1C8B3E7D004BDB5F /* iSCSISession.c in Sources */ = {isa = PBXBuildFile; fileRef = 2BDE5E371C8B0281004BDB5F /* iSCSISession.c */; };
@@ -80,6 +77,15 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
+ 2B1A490A1D3D40FE00D3ED0D /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
2BA96D9318D4F60200F135E3 /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 12;
@@ -96,14 +102,10 @@
/* Begin PBXFileReference section */
2B171E401CE23677003C3E08 /* iSCSIAuthRights.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = iSCSIAuthRights.c; path = "Source/User/iSCSI Framework/iSCSIAuthRights.c"; sourceTree = ""; };
2B171E411CE23677003C3E08 /* iSCSIAuthRights.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = iSCSIAuthRights.h; path = "Source/User/iSCSI Framework/iSCSIAuthRights.h"; sourceTree = ""; };
+ 2B180B851D3B752A005EFF14 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; };
+ 2B1A490C1D3D40FE00D3ED0D /* iSCSIHBATest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = iSCSIHBATest; sourceTree = BUILT_PRODUCTS_DIR; };
+ 2B1A490E1D3D40FE00D3ED0D /* main.c */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.objc; path = main.c; sourceTree = ""; };
2B1B972A1C4937B400DA5281 /* Scripts */ = {isa = PBXFileReference; lastKnownFileType = folder; path = Scripts; sourceTree = ""; };
- 2B1EDC0E1CFAEC1F007BAB99 /* iSCSI Utility.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "iSCSI Utility.app"; sourceTree = BUILT_PRODUCTS_DIR; };
- 2B1EDC101CFAEC1F007BAB99 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; };
- 2B1EDC111CFAEC1F007BAB99 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; };
- 2B1EDC141CFAEC1F007BAB99 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; };
- 2B1EDC191CFAEC1F007BAB99 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
- 2B1EDC1C1CFAEC1F007BAB99 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
- 2B1EDC1E1CFAEC1F007BAB99 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
2B20904F18C6E43C00C43190 /* libsystem_kernel.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libsystem_kernel.dylib; path = usr/lib/system/libsystem_kernel.dylib; sourceTree = SDKROOT; };
2B459D541B7B8192008F656F /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; };
2B56ACEC1C4A48C800930E79 /* Distribution */ = {isa = PBXFileReference; lastKnownFileType = folder; path = Distribution; sourceTree = ""; };
@@ -114,24 +116,20 @@
2B59357F1810D3C800FFC3D3 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; };
2B5935801810D3C800FFC3D3 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
2B5935C21810DF7100FFC3D3 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; };
- 2B7762911CFEF9E7003093CC /* NodeViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NodeViewController.h; sourceTree = ""; };
- 2B7762921CFEF9E7003093CC /* NodeViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NodeViewController.m; sourceTree = ""; };
- 2B7762931CFEF9E7003093CC /* Node.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Node.h; sourceTree = ""; };
- 2B7762941CFEF9E7003093CC /* Node.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Node.m; sourceTree = ""; };
- 2B77629C1D02CC9D003093CC /* InitiatorViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InitiatorViewController.h; sourceTree = ""; };
- 2B77629D1D02CC9D003093CC /* InitiatorViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = InitiatorViewController.m; sourceTree = ""; };
+ 2B6BCCB61D354EA0003522BC /* iSCSISessionManager.c */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.objc; fileEncoding = 4; name = iSCSISessionManager.c; path = Source/User/iscsid/iSCSISessionManager.c; sourceTree = ""; };
+ 2B6BCCB71D354EA0003522BC /* iSCSISessionManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = iSCSISessionManager.h; path = Source/User/iscsid/iSCSISessionManager.h; sourceTree = ""; };
2B7A0B741C8AEC47008290E9 /* iSCSI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = iSCSI.framework; sourceTree = BUILT_PRODUCTS_DIR; };
2B84883C1BEBCE0E0038DC53 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; };
2B9CAB9A185527EC00F3A9C6 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; };
2B9E3C701C493B9C00440116 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = Source/Kernel/Info.plist; sourceTree = ""; };
2B9E3C711C493B9C00440116 /* iSCSIInitiator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = iSCSIInitiator.cpp; path = Source/Kernel/iSCSIInitiator.cpp; sourceTree = ""; };
2B9E3C721C493B9C00440116 /* iSCSIInitiator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = iSCSIInitiator.h; path = Source/Kernel/iSCSIInitiator.h; sourceTree = ""; };
- 2B9E3C731C493B9C00440116 /* iSCSIInitiatorClient.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = iSCSIInitiatorClient.cpp; path = Source/Kernel/iSCSIInitiatorClient.cpp; sourceTree = ""; };
- 2B9E3C741C493B9C00440116 /* iSCSIInitiatorClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = iSCSIInitiatorClient.h; path = Source/Kernel/iSCSIInitiatorClient.h; sourceTree = ""; };
+ 2B9E3C731C493B9C00440116 /* iSCSIHBAUserClient.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = iSCSIHBAUserClient.cpp; path = Source/Kernel/iSCSIHBAUserClient.cpp; sourceTree = ""; };
+ 2B9E3C741C493B9C00440116 /* iSCSIHBAUserClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = iSCSIHBAUserClient.h; path = Source/Kernel/iSCSIHBAUserClient.h; sourceTree = ""; };
2B9E3C751C493B9C00440116 /* iSCSIIOEventSource.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = iSCSIIOEventSource.cpp; path = Source/Kernel/iSCSIIOEventSource.cpp; sourceTree = ""; };
2B9E3C761C493B9C00440116 /* iSCSIIOEventSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = iSCSIIOEventSource.h; path = Source/Kernel/iSCSIIOEventSource.h; sourceTree = ""; };
2B9E3C771C493B9C00440116 /* iSCSIKernelClasses.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = iSCSIKernelClasses.h; path = Source/Kernel/iSCSIKernelClasses.h; sourceTree = ""; };
- 2B9E3C781C493B9C00440116 /* iSCSIKernelInterfaceShared.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = iSCSIKernelInterfaceShared.h; path = Source/Kernel/iSCSIKernelInterfaceShared.h; sourceTree = ""; };
+ 2B9E3C781C493B9C00440116 /* iSCSIHBATypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = iSCSIHBATypes.h; path = Source/Kernel/iSCSIHBATypes.h; sourceTree = ""; };
2B9E3C791C493B9C00440116 /* iSCSIPDUKernel.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = iSCSIPDUKernel.cpp; path = Source/Kernel/iSCSIPDUKernel.cpp; sourceTree = ""; };
2B9E3C7A1C493B9C00440116 /* iSCSIPDUKernel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = iSCSIPDUKernel.h; path = Source/Kernel/iSCSIPDUKernel.h; sourceTree = ""; };
2B9E3C7B1C493B9C00440116 /* iSCSIPDUShared.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = iSCSIPDUShared.h; path = Source/Kernel/iSCSIPDUShared.h; sourceTree = ""; };
@@ -144,29 +142,23 @@
2B9E3C821C493B9C00440116 /* Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Prefix.pch; path = Source/Kernel/Prefix.pch; sourceTree = ""; };
2B9E3CBA1C49ECF900440116 /* crc32c.c */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; fileEncoding = 4; name = crc32c.c; path = Source/Kernel/crc32c.c; sourceTree = ""; };
2B9E3CBB1C49ECF900440116 /* crc32c.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; fileEncoding = 4; name = crc32c.h; path = Source/Kernel/crc32c.h; sourceTree = ""; };
- 2BAAB8B51D03E8EF00C01C79 /* SplitViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SplitViewController.h; sourceTree = ""; };
- 2BAAB8B61D03E8EF00C01C79 /* SplitViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SplitViewController.m; sourceTree = ""; };
- 2BB321F31D087AAA0030DB94 /* libcurses.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libcurses.tbd; path = usr/lib/libcurses.tbd; sourceTree = SDKROOT; };
- 2BB321F41D087AAA0030DB94 /* libncurses.5.4.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libncurses.5.4.tbd; path = usr/lib/libncurses.5.4.tbd; sourceTree = SDKROOT; };
- 2BB321F51D087AAA0030DB94 /* libncurses.5.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libncurses.5.tbd; path = usr/lib/libncurses.5.tbd; sourceTree = SDKROOT; };
- 2BB321F61D087AAA0030DB94 /* libncurses.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libncurses.tbd; path = usr/lib/libncurses.tbd; sourceTree = SDKROOT; };
2BC4CBB11AA55046003611F7 /* DiskArbitration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = DiskArbitration.framework; path = System/Library/Frameworks/DiskArbitration.framework; sourceTree = SDKROOT; };
2BDE5E261C8B0274004BDB5F /* iscsictl.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = iscsictl.8; path = Source/User/iscsictl/iscsictl.8; sourceTree = ""; };
2BDE5E271C8B0274004BDB5F /* iSCSICtl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = iSCSICtl.m; path = Source/User/iscsictl/iSCSICtl.m; sourceTree = ""; };
2BDE5E2A1C8B0281004BDB5F /* com.github.iscsi-osx.iscsid.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "com.github.iscsi-osx.iscsid.plist"; path = "Source/User/iscsid/com.github.iscsi-osx.iscsid.plist"; sourceTree = ""; };
- 2BDE5E2B1C8B0281004BDB5F /* iSCSIAuth.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = iSCSIAuth.c; path = Source/User/iscsid/iSCSIAuth.c; sourceTree = ""; };
+ 2BDE5E2B1C8B0281004BDB5F /* iSCSIAuth.c */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.objc; fileEncoding = 4; name = iSCSIAuth.c; path = Source/User/iscsid/iSCSIAuth.c; sourceTree = ""; };
2BDE5E2C1C8B0281004BDB5F /* iSCSIAuth.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = iSCSIAuth.h; path = Source/User/iscsid/iSCSIAuth.h; sourceTree = ""; };
2BDE5E2D1C8B0281004BDB5F /* iscsid.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = iscsid.8; path = Source/User/iscsid/iscsid.8; sourceTree = ""; };
- 2BDE5E2E1C8B0281004BDB5F /* iSCSIDaemon.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = iSCSIDaemon.c; path = Source/User/iscsid/iSCSIDaemon.c; sourceTree = ""; };
- 2BDE5E2F1C8B0281004BDB5F /* iSCSIDiscovery.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = iSCSIDiscovery.c; path = Source/User/iscsid/iSCSIDiscovery.c; sourceTree = ""; };
+ 2BDE5E2E1C8B0281004BDB5F /* iSCSIDaemon.c */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.objc; fileEncoding = 4; name = iSCSIDaemon.c; path = Source/User/iscsid/iSCSIDaemon.c; sourceTree = ""; };
+ 2BDE5E2F1C8B0281004BDB5F /* iSCSIDiscovery.c */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.objc; fileEncoding = 4; name = iSCSIDiscovery.c; path = Source/User/iscsid/iSCSIDiscovery.c; sourceTree = ""; };
2BDE5E301C8B0281004BDB5F /* iSCSIDiscovery.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = iSCSIDiscovery.h; path = Source/User/iscsid/iSCSIDiscovery.h; sourceTree = ""; };
- 2BDE5E311C8B0281004BDB5F /* iSCSIKernelInterface.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = iSCSIKernelInterface.c; path = Source/User/iscsid/iSCSIKernelInterface.c; sourceTree = ""; };
- 2BDE5E321C8B0281004BDB5F /* iSCSIKernelInterface.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = iSCSIKernelInterface.h; path = Source/User/iscsid/iSCSIKernelInterface.h; sourceTree = ""; };
- 2BDE5E331C8B0281004BDB5F /* iSCSIPDUUser.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = iSCSIPDUUser.c; path = Source/User/iscsid/iSCSIPDUUser.c; sourceTree = ""; };
+ 2BDE5E311C8B0281004BDB5F /* iSCSIHBAInterface.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = iSCSIHBAInterface.c; path = Source/User/iscsid/iSCSIHBAInterface.c; sourceTree = ""; };
+ 2BDE5E321C8B0281004BDB5F /* iSCSIHBAInterface.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = iSCSIHBAInterface.h; path = Source/User/iscsid/iSCSIHBAInterface.h; sourceTree = ""; };
+ 2BDE5E331C8B0281004BDB5F /* iSCSIPDUUser.c */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.objc; fileEncoding = 4; name = iSCSIPDUUser.c; path = Source/User/iscsid/iSCSIPDUUser.c; sourceTree = ""; };
2BDE5E341C8B0281004BDB5F /* iSCSIPDUUser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = iSCSIPDUUser.h; path = Source/User/iscsid/iSCSIPDUUser.h; sourceTree = ""; };
- 2BDE5E351C8B0281004BDB5F /* iSCSIQueryTarget.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = iSCSIQueryTarget.c; path = Source/User/iscsid/iSCSIQueryTarget.c; sourceTree = ""; };
+ 2BDE5E351C8B0281004BDB5F /* iSCSIQueryTarget.c */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.objc; fileEncoding = 4; name = iSCSIQueryTarget.c; path = Source/User/iscsid/iSCSIQueryTarget.c; sourceTree = ""; };
2BDE5E361C8B0281004BDB5F /* iSCSIQueryTarget.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = iSCSIQueryTarget.h; path = Source/User/iscsid/iSCSIQueryTarget.h; sourceTree = ""; };
- 2BDE5E371C8B0281004BDB5F /* iSCSISession.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = iSCSISession.c; path = Source/User/iscsid/iSCSISession.c; sourceTree = ""; };
+ 2BDE5E371C8B0281004BDB5F /* iSCSISession.c */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.objc; fileEncoding = 4; name = iSCSISession.c; path = Source/User/iscsid/iSCSISession.c; sourceTree = ""; };
2BDE5E381C8B0281004BDB5F /* iSCSISession.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = iSCSISession.h; path = Source/User/iscsid/iSCSISession.h; sourceTree = ""; };
2BDE5E481C8B028B004BDB5F /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = "Source/User/iSCSI Framework/Info.plist"; sourceTree = ""; };
2BDE5E491C8B028B004BDB5F /* iSCSI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = iSCSI.h; path = "Source/User/iSCSI Framework/iSCSI.h"; sourceTree = ""; };
@@ -205,11 +197,11 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
- 2B1EDC0B1CFAEC1F007BAB99 /* Frameworks */ = {
+ 2B1A49091D3D40FE00D3ED0D /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- 2B77629B1D00B388003093CC /* iSCSI.framework in Frameworks */,
+ 2B1A49131D3D412700D3ED0D /* iSCSI.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -231,6 +223,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
+ 2B180B861D3B752A005EFF14 /* SystemConfiguration.framework in Frameworks */,
2BDE5E901C8B3ED0004BDB5F /* iSCSI.framework in Frameworks */,
2B459D551B7B8192008F656F /* Security.framework in Frameworks */,
2BC4CBB21AA55046003611F7 /* DiskArbitration.framework in Frameworks */,
@@ -242,33 +235,12 @@
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
- 2B1EDC0F1CFAEC1F007BAB99 /* iSCSI Utility */ = {
- isa = PBXGroup;
- children = (
- 2B7762911CFEF9E7003093CC /* NodeViewController.h */,
- 2B7762921CFEF9E7003093CC /* NodeViewController.m */,
- 2B77629C1D02CC9D003093CC /* InitiatorViewController.h */,
- 2B77629D1D02CC9D003093CC /* InitiatorViewController.m */,
- 2BAAB8B51D03E8EF00C01C79 /* SplitViewController.h */,
- 2BAAB8B61D03E8EF00C01C79 /* SplitViewController.m */,
- 2B7762931CFEF9E7003093CC /* Node.h */,
- 2B7762941CFEF9E7003093CC /* Node.m */,
- 2B1EDC101CFAEC1F007BAB99 /* AppDelegate.h */,
- 2B1EDC111CFAEC1F007BAB99 /* AppDelegate.m */,
- 2B1EDC191CFAEC1F007BAB99 /* Assets.xcassets */,
- 2B1EDC1B1CFAEC1F007BAB99 /* Main.storyboard */,
- 2B1EDC1E1CFAEC1F007BAB99 /* Info.plist */,
- 2B1EDC131CFAEC1F007BAB99 /* Supporting Files */,
- );
- path = "iSCSI Utility";
- sourceTree = "";
- };
- 2B1EDC131CFAEC1F007BAB99 /* Supporting Files */ = {
+ 2B1A490D1D3D40FE00D3ED0D /* iSCSIHBATest */ = {
isa = PBXGroup;
children = (
- 2B1EDC141CFAEC1F007BAB99 /* main.m */,
+ 2B1A490E1D3D40FE00D3ED0D /* main.c */,
);
- name = "Supporting Files";
+ path = iSCSIHBATest;
sourceTree = "";
};
2B5935541810CE6800FFC3D3 = {
@@ -279,22 +251,20 @@
2B1B972A1C4937B400DA5281 /* Scripts */,
2B56ACEC1C4A48C800930E79 /* Distribution */,
2B84883C1BEBCE0E0038DC53 /* README.md */,
+ 2B1A490D1D3D40FE00D3ED0D /* iSCSIHBATest */,
2B5935631810D38E00FFC3D3 /* Frameworks */,
2BDEA9401A715C7B00D5B48B /* iSCSIInitiator.kext */,
2BDEA9411A715C7B00D5B48B /* iscsid */,
2BDEA9421A715C7B00D5B48B /* iscsictl */,
2B7A0B741C8AEC47008290E9 /* iSCSI.framework */,
- 2B1EDC0E1CFAEC1F007BAB99 /* iSCSI Utility.app */,
+ 2B1A490C1D3D40FE00D3ED0D /* iSCSIHBATest */,
);
sourceTree = "";
};
2B5935631810D38E00FFC3D3 /* Frameworks */ = {
isa = PBXGroup;
children = (
- 2BB321F31D087AAA0030DB94 /* libcurses.tbd */,
- 2BB321F41D087AAA0030DB94 /* libncurses.5.4.tbd */,
- 2BB321F51D087AAA0030DB94 /* libncurses.5.tbd */,
- 2BB321F61D087AAA0030DB94 /* libncurses.tbd */,
+ 2B180B851D3B752A005EFF14 /* SystemConfiguration.framework */,
2B459D541B7B8192008F656F /* Security.framework */,
2BC4CBB11AA55046003611F7 /* DiskArbitration.framework */,
2B20904F18C6E43C00C43190 /* libsystem_kernel.dylib */,
@@ -326,12 +296,12 @@
2B9E3CBB1C49ECF900440116 /* crc32c.h */,
2B9E3C711C493B9C00440116 /* iSCSIInitiator.cpp */,
2B9E3C721C493B9C00440116 /* iSCSIInitiator.h */,
- 2B9E3C731C493B9C00440116 /* iSCSIInitiatorClient.cpp */,
- 2B9E3C741C493B9C00440116 /* iSCSIInitiatorClient.h */,
+ 2B9E3C731C493B9C00440116 /* iSCSIHBAUserClient.cpp */,
+ 2B9E3C741C493B9C00440116 /* iSCSIHBAUserClient.h */,
2B9E3C751C493B9C00440116 /* iSCSIIOEventSource.cpp */,
2B9E3C761C493B9C00440116 /* iSCSIIOEventSource.h */,
2B9E3C771C493B9C00440116 /* iSCSIKernelClasses.h */,
- 2B9E3C781C493B9C00440116 /* iSCSIKernelInterfaceShared.h */,
+ 2B9E3C781C493B9C00440116 /* iSCSIHBATypes.h */,
2B9E3C791C493B9C00440116 /* iSCSIPDUKernel.cpp */,
2B9E3C7A1C493B9C00440116 /* iSCSIPDUKernel.h */,
2B9E3C7B1C493B9C00440116 /* iSCSIPDUShared.h */,
@@ -357,7 +327,6 @@
2BDE5E1A1C8B020A004BDB5F /* User */ = {
isa = PBXGroup;
children = (
- 2B1EDC0F1CFAEC1F007BAB99 /* iSCSI Utility */,
2BDE5E231C8B0255004BDB5F /* iscsictl */,
2BDE5E221C8B024A004BDB5F /* iscsid */,
2BDE5E211C8B0241004BDB5F /* iSCSI Framwork */,
@@ -403,14 +372,16 @@
2BDE5E2E1C8B0281004BDB5F /* iSCSIDaemon.c */,
2BDE5E2F1C8B0281004BDB5F /* iSCSIDiscovery.c */,
2BDE5E301C8B0281004BDB5F /* iSCSIDiscovery.h */,
- 2BDE5E311C8B0281004BDB5F /* iSCSIKernelInterface.c */,
- 2BDE5E321C8B0281004BDB5F /* iSCSIKernelInterface.h */,
+ 2BDE5E311C8B0281004BDB5F /* iSCSIHBAInterface.c */,
+ 2BDE5E321C8B0281004BDB5F /* iSCSIHBAInterface.h */,
2BDE5E331C8B0281004BDB5F /* iSCSIPDUUser.c */,
2BDE5E341C8B0281004BDB5F /* iSCSIPDUUser.h */,
2BDE5E351C8B0281004BDB5F /* iSCSIQueryTarget.c */,
2BDE5E361C8B0281004BDB5F /* iSCSIQueryTarget.h */,
2BDE5E371C8B0281004BDB5F /* iSCSISession.c */,
2BDE5E381C8B0281004BDB5F /* iSCSISession.h */,
+ 2B6BCCB61D354EA0003522BC /* iSCSISessionManager.c */,
+ 2B6BCCB71D354EA0003522BC /* iSCSISessionManager.h */,
);
name = iscsid;
sourceTree = "";
@@ -473,22 +444,22 @@
productReference = 2BDEA9421A715C7B00D5B48B /* iscsictl */;
productType = "com.apple.product-type.tool";
};
- 2B1EDC0D1CFAEC1F007BAB99 /* iSCSI Utility */ = {
+ 2B1A490B1D3D40FE00D3ED0D /* iSCSIHBATest */ = {
isa = PBXNativeTarget;
- buildConfigurationList = 2B1EDC1F1CFAEC1F007BAB99 /* Build configuration list for PBXNativeTarget "iSCSI Utility" */;
+ buildConfigurationList = 2B1A49101D3D40FE00D3ED0D /* Build configuration list for PBXNativeTarget "iSCSIHBATest" */;
buildPhases = (
- 2B1EDC0A1CFAEC1F007BAB99 /* Sources */,
- 2B1EDC0B1CFAEC1F007BAB99 /* Frameworks */,
- 2B1EDC0C1CFAEC1F007BAB99 /* Resources */,
+ 2B1A49081D3D40FE00D3ED0D /* Sources */,
+ 2B1A49091D3D40FE00D3ED0D /* Frameworks */,
+ 2B1A490A1D3D40FE00D3ED0D /* CopyFiles */,
);
buildRules = (
);
dependencies = (
);
- name = "iSCSI Utility";
- productName = "iSCSI Utility";
- productReference = 2B1EDC0E1CFAEC1F007BAB99 /* iSCSI Utility.app */;
- productType = "com.apple.product-type.application";
+ name = iSCSIHBATest;
+ productName = iSCSIHBATest;
+ productReference = 2B1A490C1D3D40FE00D3ED0D /* iSCSIHBATest */;
+ productType = "com.apple.product-type.tool";
};
2B7A0B731C8AEC47008290E9 /* iSCSI */ = {
isa = PBXNativeTarget;
@@ -553,7 +524,7 @@
LastSwiftUpdateCheck = 0730;
LastUpgradeCheck = 0700;
TargetAttributes = {
- 2B1EDC0D1CFAEC1F007BAB99 = {
+ 2B1A490B1D3D40FE00D3ED0D = {
CreatedOnToolsVersion = 7.3.1;
};
2B7A0B731C8AEC47008290E9 = {
@@ -578,21 +549,12 @@
2BA96D8818D4F60200F135E3 /* iscsid */,
2B16EEC8196085A40061E7FA /* iscsictl */,
2B7A0B731C8AEC47008290E9 /* iSCSI */,
- 2B1EDC0D1CFAEC1F007BAB99 /* iSCSI Utility */,
+ 2B1A490B1D3D40FE00D3ED0D /* iSCSIHBATest */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
- 2B1EDC0C1CFAEC1F007BAB99 /* Resources */ = {
- isa = PBXResourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 2B1EDC1A1CFAEC1F007BAB99 /* Assets.xcassets in Resources */,
- 2B1EDC1D1CFAEC1F007BAB99 /* Main.storyboard in Resources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
2B7A0B721C8AEC47008290E9 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
@@ -631,16 +593,13 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
- 2B1EDC0A1CFAEC1F007BAB99 /* Sources */ = {
+ 2B1A49081D3D40FE00D3ED0D /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
- 2B77629A1CFF2211003093CC /* Node.m in Sources */,
- 2BAAB8B71D03E8EF00C01C79 /* SplitViewController.m in Sources */,
- 2B7762991CFF220D003093CC /* NodeViewController.m in Sources */,
- 2B77629E1D02CC9D003093CC /* InitiatorViewController.m in Sources */,
- 2B1EDC151CFAEC1F007BAB99 /* main.m in Sources */,
- 2B1EDC121CFAEC1F007BAB99 /* AppDelegate.m in Sources */,
+ 2B1A49141D3D416000D3ED0D /* iSCSIPDUUser.c in Sources */,
+ 2B1A490F1D3D40FE00D3ED0D /* main.c in Sources */,
+ 2B1A49151D3D416800D3ED0D /* iSCSIHBAInterface.c in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -664,7 +623,7 @@
buildActionMask = 2147483647;
files = (
2B9E3C941C493BAA00440116 /* iSCSIInitiator.cpp in Sources */,
- 2B9E3C961C493BAA00440116 /* iSCSIInitiatorClient.cpp in Sources */,
+ 2B9E3C961C493BAA00440116 /* iSCSIHBAUserClient.cpp in Sources */,
2B9E3C981C493BAA00440116 /* iSCSIIOEventSource.cpp in Sources */,
2B9E3CBE1C49ED0000440116 /* crc32c.c in Sources */,
2B9E3C9C1C493BAA00440116 /* iSCSIPDUKernel.cpp in Sources */,
@@ -677,29 +636,19 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
- 2BDE5E8E1C8B3E7D004BDB5F /* iSCSISession.c in Sources */,
- 2BDE5E8B1C8B3E7D004BDB5F /* iSCSIKernelInterface.c in Sources */,
- 2BDE5E881C8B3E7D004BDB5F /* iSCSIAuth.c in Sources */,
- 2BDE5E891C8B3E7D004BDB5F /* iSCSIDaemon.c in Sources */,
- 2BDE5E8A1C8B3E7D004BDB5F /* iSCSIDiscovery.c in Sources */,
+ 2BDE5E8B1C8B3E7D004BDB5F /* iSCSIHBAInterface.c in Sources */,
+ 2B6BCCB91D3A7857003522BC /* iSCSISessionManager.c in Sources */,
2BDE5E8C1C8B3E7D004BDB5F /* iSCSIPDUUser.c in Sources */,
2BDE5E8D1C8B3E7D004BDB5F /* iSCSIQueryTarget.c in Sources */,
+ 2BDE5E881C8B3E7D004BDB5F /* iSCSIAuth.c in Sources */,
+ 2BDE5E8E1C8B3E7D004BDB5F /* iSCSISession.c in Sources */,
+ 2BDE5E8A1C8B3E7D004BDB5F /* iSCSIDiscovery.c in Sources */,
+ 2BDE5E891C8B3E7D004BDB5F /* iSCSIDaemon.c in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
-/* Begin PBXVariantGroup section */
- 2B1EDC1B1CFAEC1F007BAB99 /* Main.storyboard */ = {
- isa = PBXVariantGroup;
- children = (
- 2B1EDC1C1CFAEC1F007BAB99 /* Base */,
- );
- name = Main.storyboard;
- sourceTree = "";
- };
-/* End PBXVariantGroup section */
-
/* Begin XCBuildConfiguration section */
2B16EED0196085A40061E7FA /* Debug */ = {
isa = XCBuildConfiguration;
@@ -719,7 +668,7 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "";
COPY_PHASE_STRIP = NO;
- DYLIB_CURRENT_VERSION = "1.0.0-beta";
+ DYLIB_CURRENT_VERSION = 1.0.0;
GCC_C_LANGUAGE_STANDARD = "compiler-default";
GCC_DYNAMIC_NO_PIC = NO;
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
@@ -761,7 +710,7 @@
CODE_SIGN_IDENTITY = "";
COPY_PHASE_STRIP = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
- DYLIB_CURRENT_VERSION = "1.0.0-beta";
+ DYLIB_CURRENT_VERSION = 1.0.0;
ENABLE_NS_ASSERTIONS = NO;
GCC_C_LANGUAGE_STANDARD = "compiler-default";
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
@@ -778,11 +727,10 @@
};
name = Release;
};
- 2B1EDC201CFAEC1F007BAB99 /* Debug */ = {
+ 2B1A49111D3D40FE00D3ED0D /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
- ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
@@ -798,7 +746,6 @@
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "-";
- COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
@@ -816,20 +763,16 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- INFOPLIST_FILE = "iSCSI Utility/Info.plist";
- LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
MACOSX_DEPLOYMENT_TARGET = 10.11;
MTL_ENABLE_DEBUG_INFO = YES;
- PRODUCT_BUNDLE_IDENTIFIER = "com.github.iscsi-osx.iSCSI-Utility";
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Debug;
};
- 2B1EDC211CFAEC1F007BAB99 /* Release */ = {
+ 2B1A49121D3D40FE00D3ED0D /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
- ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
@@ -845,7 +788,6 @@
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "-";
- COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
@@ -858,11 +800,8 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- INFOPLIST_FILE = "iSCSI Utility/Info.plist";
- LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
MACOSX_DEPLOYMENT_TARGET = 10.11;
MTL_ENABLE_DEBUG_INFO = NO;
- PRODUCT_BUNDLE_IDENTIFIER = "com.github.iscsi-osx.iSCSI-Utility";
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;
@@ -872,7 +811,7 @@
buildSettings = {
CF_PREFERENCES_APP_ID = "$(NAME_PREFIX_D).iSCSIInitiator";
CODE_SIGN_IDENTITY = "";
- CURRENT_PROJECT_VERSION = "1.0.0-beta2";
+ CURRENT_PROJECT_VERSION = "1.0.0-beta4";
ENABLE_TESTABILITY = YES;
GCC_PREPROCESSOR_DEFINITIONS = (
"CF_PREFERENCES_APP_ID=\\\"$(NAME_PREFIX_D).iSCSIInitiator\\\"",
@@ -894,7 +833,7 @@
buildSettings = {
CF_PREFERENCES_APP_ID = "$(NAME_PREFIX_D).iSCSIInitiator";
CODE_SIGN_IDENTITY = "";
- CURRENT_PROJECT_VERSION = "1.0.0-beta2";
+ CURRENT_PROJECT_VERSION = "1.0.0-beta4";
GCC_PREPROCESSOR_DEFINITIONS = (
"CF_PREFERENCES_APP_ID=\\\"$(NAME_PREFIX_D).iSCSIInitiator\\\"",
"NAME_PREFIX_U=$(NAME_PREFIX_U)",
@@ -1029,7 +968,7 @@
CODE_SIGN_IDENTITY = "";
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = NO;
- DYLIB_CURRENT_VERSION = "1.0.0-beta";
+ DYLIB_CURRENT_VERSION = 1.0.0;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
@@ -1083,7 +1022,7 @@
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
- DYLIB_CURRENT_VERSION = "1.0.0-beta";
+ DYLIB_CURRENT_VERSION = 1.0.0;
ENABLE_NS_ASSERTIONS = NO;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
@@ -1129,7 +1068,7 @@
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
- DYLIB_CURRENT_VERSION = "1.0.0-beta";
+ DYLIB_CURRENT_VERSION = 1.0.0;
GCC_C_LANGUAGE_STANDARD = "compiler-default";
GCC_DYNAMIC_NO_PIC = NO;
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
@@ -1172,7 +1111,7 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
- DYLIB_CURRENT_VERSION = "1.0.0-beta";
+ DYLIB_CURRENT_VERSION = 1.0.0;
ENABLE_NS_ASSERTIONS = NO;
GCC_C_LANGUAGE_STANDARD = "compiler-default";
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
@@ -1203,11 +1142,11 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
- 2B1EDC1F1CFAEC1F007BAB99 /* Build configuration list for PBXNativeTarget "iSCSI Utility" */ = {
+ 2B1A49101D3D40FE00D3ED0D /* Build configuration list for PBXNativeTarget "iSCSIHBATest" */ = {
isa = XCConfigurationList;
buildConfigurations = (
- 2B1EDC201CFAEC1F007BAB99 /* Debug */,
- 2B1EDC211CFAEC1F007BAB99 /* Release */,
+ 2B1A49111D3D40FE00D3ED0D /* Debug */,
+ 2B1A49121D3D40FE00D3ED0D /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;