diff --git a/Distribution/package.sh b/Distribution/package.sh index e8d91ecd..106692ab 100755 --- a/Distribution/package.sh +++ b/Distribution/package.sh @@ -1,7 +1,7 @@ # Package parameters NAME="iSCSI Initiator for macOS" BUNDLE_ID="com.github.iscsi-osx.iSCSIInitiator" -VERSION="1.0.0-beta5" +VERSION="1.0.0-beta6" # Output of final DMG RELEASE="../Release" diff --git a/Source/Kernel/iSCSIHBAUserClient.cpp b/Source/Kernel/iSCSIHBAUserClient.cpp index 9ad77579..7fd4abd6 100644 --- a/Source/Kernel/iSCSIHBAUserClient.cpp +++ b/Source/Kernel/iSCSIHBAUserClient.cpp @@ -1393,7 +1393,7 @@ IOReturn iSCSIHBAUserClient::GetTargetIQNForSessionId(iSCSIHBAUserClient * targe IOLockUnlock(target->accessLock); - OSSafeRelease(iterator); + OSSafeReleaseNULL(iterator); return retVal; } diff --git a/Source/Kernel/iSCSIIOEventSource.cpp b/Source/Kernel/iSCSIIOEventSource.cpp index 16d8925f..0dc843b1 100644 --- a/Source/Kernel/iSCSIIOEventSource.cpp +++ b/Source/Kernel/iSCSIIOEventSource.cpp @@ -51,11 +51,7 @@ bool iSCSIIOEventSource::init(iSCSIVirtualHBA * owner, iSCSIIOEventSource::session = session; iSCSIIOEventSource::connection = connection; - - // Initialize task queue to store parallel SCSI tasks for processing - queue_init(&taskQueue); - taskQueueLock = IOSimpleLockAlloc(); - + return true; } @@ -93,4 +89,4 @@ bool iSCSIIOEventSource::checkForWork() // Tell workloop thread not to call us again until we signal again... return false; -} \ No newline at end of file +} diff --git a/Source/Kernel/iSCSIIOEventSource.h b/Source/Kernel/iSCSIIOEventSource.h index e2a1c410..e79ce56e 100644 --- a/Source/Kernel/iSCSIIOEventSource.h +++ b/Source/Kernel/iSCSIIOEventSource.h @@ -100,15 +100,6 @@ class iSCSIIOEventSource : public IOEventSource /*! The iSCSI connection associated with this event source. */ iSCSIConnection * connection; - queue_head_t taskQueue; - - /*! Flag used to indicate whether the task at the head of the queue is a - * new task that has not yet been processed. */ - bool newTask; - - /*! Mutex lock used to prevent simultaneous access to the iSCSI task queue - * (e.g., simultaneous calls to addTaskToQueue() and removeTaskFromQueue(). */ - IOSimpleLock * taskQueueLock; }; #endif /* defined(__ISCSI_EVENT_SOURCE_H__) */ diff --git a/Source/Kernel/iSCSITaskQueue.cpp b/Source/Kernel/iSCSITaskQueue.cpp index 4ea40cd8..e508c7df 100644 --- a/Source/Kernel/iSCSITaskQueue.cpp +++ b/Source/Kernel/iSCSITaskQueue.cpp @@ -118,12 +118,6 @@ UInt32 iSCSITaskQueue::completeCurrentTask() return taskTag; } -/*! Gets the iSCSI task tag of the task that is current being processed. - * @return iSCSI task tag of the current task. */ -UInt32 getCurrentTask() -{ - return 0; -} bool iSCSITaskQueue::checkForWork() { diff --git a/Source/Kernel/iSCSITaskQueue.h b/Source/Kernel/iSCSITaskQueue.h index 471dec8b..68310ad8 100644 --- a/Source/Kernel/iSCSITaskQueue.h +++ b/Source/Kernel/iSCSITaskQueue.h @@ -83,10 +83,6 @@ class iSCSITaskQueue : public IOEventSource /*! Removes all tasks from the queue. */ void clearTasksFromQueue(); - /*! Gets the iSCSI task tag of the task that is current being processed. - * @return iSCSI task tag of the current task. */ - UInt32 getCurrentTask(); - protected: /*! Called by the attached work loop to check if there is any processing @@ -109,4 +105,4 @@ class iSCSITaskQueue : public IOEventSource }; -#endif \ No newline at end of file +#endif diff --git a/Source/Kernel/iSCSIVirtualHBA.cpp b/Source/Kernel/iSCSIVirtualHBA.cpp index dc9235d6..19d03b0c 100644 --- a/Source/Kernel/iSCSIVirtualHBA.cpp +++ b/Source/Kernel/iSCSIVirtualHBA.cpp @@ -156,9 +156,11 @@ bool iSCSIVirtualHBA::InitializeTargetForID(SCSITargetIdentifier targetId) if(targetIQN) { protocolDict->setObject("iSCSI Qualified Name",targetIQN); - device->setProperty(kIOPropertyProtocolCharacteristicsKey,protocolDict); } + protocolDict->setObject(kIOPropertyPhysicalInterconnectTypeKey,OSString::withCString("iSCSI")); + device->setProperty(kIOPropertyProtocolCharacteristicsKey,protocolDict); + protocolDict->release(); } @@ -354,12 +356,13 @@ bool iSCSIVirtualHBA::InitializeController() SetHBAProperty(kIOPropertyProductNameKey,OSString::withCString(ISCSI_PRODUCT_NAME)); SetHBAProperty(kIOPropertyProductRevisionLevelKey,OSString::withCString(ISCSI_PRODUCT_REVISION_LEVEL)); + // Generate an initiator id using a random number (per RFC3720) + kInitiatorId = random(); + // Make ourselves discoverable to user clients (we do this last after // everything is initialized). registerService(); - - // Generate an initiator id using a random number (per RFC3720) - kInitiatorId = random(); + // Successfully initialized controller return true; @@ -452,8 +455,6 @@ void iSCSIVirtualHBA::HandleConnectionTimeout(SessionIdentifier sessionId,Connec 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) @@ -463,14 +464,17 @@ void iSCSIVirtualHBA::HandleConnectionTimeout(SessionIdentifier sessionId,Connec // 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) + iSCSIHBAUserClient * client = (iSCSIHBAUserClient*)getClient(); + + if(client) + client->sendTimeoutMessageNotification(sessionId,connectionId); + else { if(connectionCount > 1) ReleaseConnection(sessionId,connectionId); else ReleaseSession(sessionId); } - } SCSIServiceResponse iSCSIVirtualHBA::ProcessParallelTask(SCSIParallelTaskIdentifier parallelTask) @@ -937,6 +941,7 @@ void iSCSIVirtualHBA::ProcessSCSIResponse(iSCSISession * session, SetRealizedDataTransferCount(parallelTask,(UInt32)GetRequestedDataTransferCount(parallelTask)); // Process sense data if the PDU came with any... + bool senseDataPresent = false; if(length >= senseDataHeaderSize) { // First two bytes of the data segment are the size of the sense data @@ -955,6 +960,8 @@ void iSCSIVirtualHBA::ProcessSCSIResponse(iSCSISession * session, // Incorporate sense data into the task SetAutoSenseData(parallelTask,newSenseData,senseDataLength); + senseDataPresent = true; + DBLog("iscsi: Processed sense data (sid: %d, cid: %d)\n", session->sessionId,connection->cid); } @@ -964,6 +971,13 @@ void iSCSIVirtualHBA::ProcessSCSIResponse(iSCSISession * session, // know that we're done with this task... SCSITaskStatus completionStatus = (SCSITaskStatus)bhs->status; + + // If sense data has been included along with a check condition response, + // the macOS SCSI stack expects that the task status is "GOOD". Otherwise, + // it queries for auto sense data. + if(completionStatus == kSCSITaskStatus_CHECK_CONDITION && senseDataPresent) + completionStatus = kSCSITaskStatus_GOOD; + SCSIServiceResponse serviceResponse; if(bhs->response == kiSCSIPDUSCSICmdCompleted) @@ -978,6 +992,7 @@ void iSCSIVirtualHBA::ProcessSCSIResponse(iSCSISession * session, DBLog("iscsi: Processed SCSI response (sid: %d, cid: %d)\n", session->sessionId,connection->cid); + } void iSCSIVirtualHBA::ProcessDataIn(iSCSISession * session, @@ -1534,7 +1549,7 @@ errno_t iSCSIVirtualHBA::CreateConnection(SessionIdentifier sessionId, goto EVENTSOURCE_ADD_FAILURE; newConn->dataRecvEventSource->disable(); - + // Create a new socket (per RFC3720, only TCP sockets are used. // Domain can be either IPv4 or IPv6. error = sock_socket(portalSockaddr->ss_family, diff --git a/Source/User/iSCSI Framework/iSCSIUtils.c b/Source/User/iSCSI Framework/iSCSIUtils.c index 403b8fca..c6641f93 100644 --- a/Source/User/iSCSI Framework/iSCSIUtils.c +++ b/Source/User/iSCSI Framework/iSCSIUtils.c @@ -27,6 +27,7 @@ */ #include "iSCSIUtils.h" +#include /*! Minimum TCP port. */ static int PORT_MIN = 0; @@ -43,7 +44,7 @@ Boolean iSCSIUtilsValidateIQN(CFStringRef IQN) { // IEEE regular expression for matching IQN name const char pattern[] = "^iqn[.][0-9]{4}-[0-9]{2}[.][[:alnum:]]{1,}[.]" - "[-A-Za-z0-9.]{1,255}:[-A-Za-z0-9.]{1,255}" + "[-A-Za-z0-9.]{1,255}" "|^eui[.][[:xdigit:]]{16}$"; Boolean validName = false; diff --git a/Source/User/iSCSI Framework/iSCSIUtils.h b/Source/User/iSCSI Framework/iSCSIUtils.h index c66adcce..6468668b 100644 --- a/Source/User/iSCSI Framework/iSCSIUtils.h +++ b/Source/User/iSCSI Framework/iSCSIUtils.h @@ -33,11 +33,12 @@ #include #include -#include #include #include "iSCSITypes.h" +struct sockaddr_storage; + /*! Verifies whether specified iSCSI qualified name (IQN) is valid per RFC3720. * This function also validates 64-bit EUI names expressed as strings that * start with the "eui" prefix. diff --git a/Source/User/iscsid/iSCSIDaemon.c b/Source/User/iscsid/iSCSIDaemon.c index 72e064f8..d6d02236 100644 --- a/Source/User/iscsid/iSCSIDaemon.c +++ b/Source/User/iscsid/iSCSIDaemon.c @@ -1643,6 +1643,12 @@ void iSCSIDProcessQueuedLogin(SCNetworkReachabilityRef reachabilityTarget, * portal when the network becomes available. */ void iSCSIDQueueLogin(iSCSITargetRef target,iSCSIPortalRef portal) { + if(!target || !portal) + return; + + iSCSITargetRetain(target); + iSCSIPortalRetain(portal); + SCNetworkReachabilityRef reachabilityTarget; SCNetworkReachabilityContext reachabilityContext; @@ -1707,10 +1713,6 @@ void iSCSIDSessionTimeoutHandler(iSCSITargetRef target,iSCSIPortalRef portal) // 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. @@ -1731,13 +1733,17 @@ void iSCSIDAutoLogin() for(CFIndex idx = 0; idx < targetsCount; idx++) { CFStringRef targetIQN = CFArrayGetValueAtIndex(targets,idx); - iSCSITargetRef target = iSCSIPreferencesCopyTarget(preferences,targetIQN); + iSCSITargetRef target = NULL; + + if(!(target = iSCSIPreferencesCopyTarget(preferences,targetIQN))) + continue; // See if this target requires auto-login and process it if(iSCSIPreferencesGetAutoLoginForTarget(preferences,targetIQN)) { - CFArrayRef portals = iSCSIPreferencesCreateArrayOfPortalsForTarget(preferences,targetIQN); - if(!portals) + CFArrayRef portals = NULL; + + if(!(portals = iSCSIPreferencesCreateArrayOfPortalsForTarget(preferences,targetIQN))) continue; CFIndex portalsCount = CFArrayGetCount(portals); @@ -1747,12 +1753,17 @@ void iSCSIDAutoLogin() { CFStringRef portalAddress = CFArrayGetValueAtIndex(portals,portalIdx); iSCSIPortalRef portal = iSCSIPreferencesCopyPortalForTarget(preferences,targetIQN,portalAddress); - iSCSIDQueueLogin(target,portal); + + if(portal) { + iSCSIDQueueLogin(target,portal); + iSCSIPortalRelease(portal); + } } - iSCSITargetRelease(target); CFRelease(portals); } + + iSCSITargetRelease(target); } CFRelease(targets); } @@ -2132,7 +2143,7 @@ int main(void) discoveryContext.info = &discoveryRecords; discoveryContext.perform = iSCSIDProcessDiscoveryData; discoverySource = CFRunLoopSourceCreate(kCFAllocatorDefault,1,&discoveryContext); - CFRunLoopAddSource(CFRunLoopGetMain(),sockSourceRead,kCFRunLoopDefaultMode); + CFRunLoopAddSource(CFRunLoopGetMain(),discoverySource,kCFRunLoopDefaultMode); asl_log(NULL,NULL,ASL_LEVEL_INFO,"daemon started"); diff --git a/Source/User/iscsid/iSCSISession.c b/Source/User/iscsid/iSCSISession.c index c82bf600..ef06eebe 100644 --- a/Source/User/iscsid/iSCSISession.c +++ b/Source/User/iscsid/iSCSISession.c @@ -273,6 +273,9 @@ errno_t iSCSINegotiateParseSWDictNormal(iSCSISessionManagerRef managerRef, // Holds target value & comparison result for keys that we'll process CFStringRef targetRsp; + // Holds parameters that are used to process other parameters + Boolean initialR2T = false, immediateData = false; + // Get data digest key and compare to requested value if(CFDictionaryGetValueIfPresent(sessRsp,kRFC3720_Key_MaxConnections,(void*)&targetRsp)) { @@ -292,7 +295,7 @@ errno_t iSCSINegotiateParseSWDictNormal(iSCSISessionManagerRef managerRef, if(CFDictionaryGetValueIfPresent(sessRsp,kRFC3720_Key_InitialR2T,(void*)&targetRsp)) { CFStringRef initCmd = CFDictionaryGetValue(sessCmd,kRFC3720_Key_InitialR2T); - Boolean initialR2T = iSCSILVGetOr(initCmd,targetRsp); + initialR2T = iSCSILVGetOr(initCmd,targetRsp); iSCSIHBAInterfaceSetSessionParameter(hbaInterface,sessionId,kiSCSIHBASOInitialR2T, &initialR2T,sizeof(initialR2T)); } @@ -301,7 +304,7 @@ errno_t iSCSINegotiateParseSWDictNormal(iSCSISessionManagerRef managerRef, if(CFDictionaryGetValueIfPresent(sessRsp,kRFC3720_Key_ImmediateData,(void*)&targetRsp)) { CFStringRef initCmd = CFDictionaryGetValue(sessCmd,kRFC3720_Key_ImmediateData); - Boolean immediateData = iSCSILVGetAnd(initCmd,targetRsp); + immediateData = iSCSILVGetAnd(initCmd,targetRsp); iSCSIHBAInterfaceSetSessionParameter(hbaInterface,sessionId,kiSCSIHBASOImmediateData, &immediateData,sizeof(immediateData)); } @@ -336,16 +339,20 @@ errno_t iSCSINegotiateParseSWDictNormal(iSCSISessionManagerRef managerRef, // Grab minimum of first burst length if(CFDictionaryGetValueIfPresent(sessRsp,kRFC3720_Key_FirstBurstLength,(void*)&targetRsp)) { - CFStringRef initCmd = CFDictionaryGetValue(sessCmd,kRFC3720_Key_FirstBurstLength); - UInt32 firstBurstLength = CFStringGetIntValue(targetRsp); + // This parameter is irrelevant when initialR2T = yes and immediateData = no. + if(!initialR2T || immediateData) { - // Range-check value... - if(iSCSILVRangeInvalid(firstBurstLength,kRFC3720_FirstBurstLength_Min,kRFC3720_FirstBurstLength_Max)) - return ENOTSUP; + CFStringRef initCmd = CFDictionaryGetValue(sessCmd,kRFC3720_Key_FirstBurstLength); + UInt32 firstBurstLength = CFStringGetIntValue(targetRsp); - firstBurstLength = iSCSILVGetMin(initCmd,targetRsp); - iSCSIHBAInterfaceSetSessionParameter(hbaInterface,sessionId,kiSCSIHBASOFirstBurstLength, - &firstBurstLength,sizeof(firstBurstLength)); + // Range-check value... + if(iSCSILVRangeInvalid(firstBurstLength,kRFC3720_FirstBurstLength_Min,kRFC3720_FirstBurstLength_Max)) + return ENOTSUP; + + firstBurstLength = iSCSILVGetMin(initCmd,targetRsp); + iSCSIHBAInterfaceSetSessionParameter(hbaInterface,sessionId,kiSCSIHBASOFirstBurstLength, + &firstBurstLength,sizeof(firstBurstLength)); + } } // Grab minimum of max outstanding R2T @@ -499,7 +506,8 @@ errno_t iSCSINegotiateSession(iSCSISessionManagerRef managerRef, iSCSINegotiateBuildSWDictCommon(sessCfg,sessCmd); // If target name is specified, this is a normal session; add parameters - if(iSCSITargetGetIQN(target) != NULL) + Boolean discoverySession = CFStringCompare(iSCSITargetGetIQN(target),kiSCSIUnspecifiedTargetIQN,0) == kCFCompareEqualTo; + if(!discoverySession) iSCSINegotiateBuildSWDictNormal(sessCfg,sessCmd); // Add connection parameters diff --git a/Source/User/iscsid/iSCSISessionManager.c b/Source/User/iscsid/iSCSISessionManager.c index 8b8f4a81..9486dd8a 100644 --- a/Source/User/iscsid/iSCSISessionManager.c +++ b/Source/User/iscsid/iSCSISessionManager.c @@ -66,6 +66,9 @@ struct __iSCSISessionManager // Call user-defined callback function if one exists if(managerRef->callbacks.timeoutCallback) managerRef->callbacks.timeoutCallback(target,portal); + + iSCSITargetRelease(target); + iSCSIPortalRelease(portal); } /*! Called to handle asynchronous events that involve dropped sessions, connections,