How do I pass SCSI (CDB) commands through a USB connection - macos

I am trying to talk to a MSC USB device (interface class 8, subclass 6, protocol 0x50) via a plain USB API with endpoints (all set up for me).
Provided I have a valid CDB, such as for "Test Unit Ready", how to I send that over the USB interface?
Where can I find examples or docs for how this is done?
Background: The actual platform is macOS, which doesn't provide SCSI-passthrough for block devices, and the native SCSI API is also not available in this case.
I have, however, been able to initiate communication on the USB level with the device, and am now trying to circumvent the blocked SCSI device level access by talking thru USB directly.

Most such devices implement the so-called “Bulk Only” protocol, which is specified here: https://usb.org/document-library/mass-storage-bulk-only-10
Essentially, you send a 31-byte “Command Block Wrapper”, which includes the CDB and is specified in section 5.1 of the spec, to the device via the bulk out endpoint. You then read or write the data to be transferred from the input bulk endpoint or to the output bulk endpoint and finally read the 13-byte command status wrapper from the bulk in pipe.
However, note that you’ll need to make sure the OS hasn’t already loaded a driver for the device - from user space, the system won’t give you access to the endpoints when a kernel driver has claimed them anyway, but if you were to attempt to use the same pipes as the default driver from a kext, you’d get unpredictable results.

Related

USB stack confusion/serial emulator

I am looking at implementing USB communication on a MCU which has a USB engine built into it. Basically you have access to the pipes/endpoints.
I am a little bit confused on the USB stack now. It appears that drivers operate on another level above the pipe/endpoint setup, so the pipe/endpoint is like a middle level layer that drivers are built on. Is this correct?
Secondly, I am interested in simulating serial communication over USB. It appears windows has a premade driver so on the computer side I do not need to program the pipe level.
How do I find out what I need to implement on the MCU to make it behave correctly with the generic serial driver?
This is an answer to your second question regarding the serial communication.
The USB standard defines a communication device class (CDC) for serial communication. The required drivers on the host side are implemented by Windows, macOS, Linux and many more operation systems.
The relevant CDC subclass is PSTN. The relevant documents are found in Class definition for Communication Devices 1.2.
The device basically implements four endpoints:
Control endpoint for configuration requests (baud rate, DTR state etc.). Have a look at SetLineCodeing, GetLineCoding and SetControlLineState.
Bulk endpoint for USB to serial transmission
Bulk endpoint for serial to USB transmission
Interrupt endpoint for notifications (DCD state, errors). See SerialState.
And of course you need to get the device descriptor right.
On top of that, you need to implement all the standard USB requests.
Chances are high that this has already been written for your MCU, both the standard requests and the serial communication. So why not use the existing code?

In Bluetooth LE GATT, is there any way to detect when Long Term Keys are invalid?

I am using Windows Bluetooth LE GATT library to connect to and pair with a BLE-supporting device, D. Since D has a limited amount of storage space, if more than N Clients bond with it, then it will remove the first Long Term Key pair that was created during bonding.
Let's say that the device for which this key-pair was removed was a Windows Enabled machine. Let's call this W. The next time W attempts to connect with D, when it receives the LTK_Request_Event from W, it responds with Long_Term_Key_Requested_Negative_Reply, and W terminates the connection.
But here's where things get really exasperating. Even though the Windows BLE Stack seems to be aware of this response (because it disconnects), this does not seem to be communicated downstream to applications using the Bluetooth LE GATT library. In fact, from the application's side, a pairing request will return with "Already Paired", and does not indicate that anything went wrong. Of course, once the application tries to access protected characteristics, it won't be able to, and that, so far, is the only indication that Pairing was not successful. Even worse, the errors it receives aren't consistent. Sometimes, it gets "Unreachable". Sometimes, it gets protocol errors. Other times, it receives ABORTs.
Now, as a heuristic, I could use detection of this case as criteria for attempting to re-pair. Unfortunately, this is not ideal, since none of these errors actually imply that the device no longer honored the LTKs, and could, instead, indicate other issues, like that the device is out of range.
Is there any way to detect that existing LTKs have been rejected by the device?
Let's see what the Bluetooth specification says about this.
Bluetooth Core version 5.2, Vol 3 (Host), Part C (Generic Access Profile)
Section 10.3.2 Initiating a service request:
In this section the local device is the device initiating a service request to a
remote device. In the L2CAP protocol the local device sends the connection
request and the remote device sends the connection response. In GATT, the
local device is the GATT client and the remote device is the GATT server.
When a local device initiates a service request to a remote device it shall
behave according to the following rules:
[...]
If an LTK is available and encryption is required (LE security mode 1) then
encryption shall be enabled before the service request proceeds as defined proceed. If encryption fails either the bond no longer exists on the remote
device, or the wrong device has been connected. The local device must,
after user interaction to confirm the remote device, re-bond, perform service
discovery and re-configure the remote device. [...]
If Windows's BLE stack doesn't allow for what the specification mandates, it is not specification compliant, in my eyes, so please file an issue report at Microsoft.
The reason for requiring user interaction and not blindly re-bond is to avoid a situation where a hacker can simply spoof the bluetooth device address, indicate it has lost the bond and automatically re-bond without the user noticing anything.
EDIT:
The Security Manager chapter also has a table of actions to do when encryption fails due to deleted keys. See section 2.4.4.2 of Vol 3, Part H.
It specifically says when the devices were bonded before that the action to take when enabling encryption fails is to "Notify user of security failure."

Windows10 USB Transfer mode

Will USB communication in Windows 10 be done in Bulk mode?
I'm in the process of selecting a PC and would like to know how to transfer Windows 10 to other devices for USB communication.
There are four transfer methods for USB communication, Control, Interrupt, Bulk, and Isochronous, and which one is used depends on the host.
I'm hoping to use the Bulk method of communication because I don't want USB communication without retransmission.
Thank you!
and which one is used depends on the host
Yes and no. The host must use the method appropriate for a device, and the device has endpoint descriptors which define whether an endpoint is bulk,interrupt or isochronous.
Note that common devices have specific endpoint type requirements: Mass storage use bulk while HID devices (e.g. mice or keyboards) use interrupt ep.

How to get USB device descriptor by doing DeviceIoControl() directly on the device?

I want to get the Device descriptor of USB devices on my system. I am creating a userspace application in Windows(un-managed, native c++ ). From these descriptors, I want to identify billboard devices and parse billboard capability descriptor (parsing bos descriptor).
Here is my approach.
Get USB devices on a system by SetupDiGetClassDevs(&GUID_CLASS_USB_DEVICE,...)
Get device path of each device using SetupDiGetDeviceInterfaceDetail()
Use CreateFile() on device path to get handle to the device.
Issue IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION IOCTL using DeviceIoControl(), and the handle, to get the device descriptor.
I am stuck on the 4th step (getLastError() - Invalid Function).
Other projects (like this sample code from Intel), enumerate all USB controllers on the system, root hubs, ports, and interfaces, and issue IOCTL on the root hub's handle, specifying the port number to which a device is connected.
I do not want to concern myself with the USB hierarchy of the system.
It is less error-prone and easier to get USB devices in the system using setup API. However, nowhere I can see IOCTL being issued to them directly.
Update1
From learn.microsoft.com:
IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION I/O control request retrieves one or more descriptors for the device that is associated with the indicated port index. This request targets the USB hub device (GUID_DEVINTERFACE_USB_HUB). Thus this ioctl which can give me device descriptor of a USB device is meant to be handled by USB Hub, and NOT by a USB device.
Therefore the other solutions pass handle of hub to DeviceIoControl(), as can be seen on Line 68 of the source code from Intel (Linked here).
I instead want to use the handle obtained in step 3 (handle of the device) above to get the device descriptor. So, the IOCTL could be different, or possibly there is a way to get handle of the hub, and index of port to which the device is connected using the handle of the USB device.
The way I see it, device descriptor is an intrinsic property of a USB device, and therefore there must be a way to get it directly from the USB device.
Assuming you already have USB device handle first you need to get DEVPKEY_Device_Driver property string from it (by means of CM_Get_DevNode_PropertyW or SetupDiGetDevicePropertyW).
You'll receive string like {36fc9e60-c465-11cf-8056-444553540000}\0010.
Next you need to iterate over each USB hub in system (devices that have GUID_DEVINTERFACE_USB_HUB interface) and for each:
Open it via CreateFile() call
Call DeviceIoControl(hubInterfaceHandle, IOCTL_USB_GET_NODE_INFORMATION, ...) to get USB_NODE_INFORMATION structure that contains number of USB ports in its hubInfo.u.HubInformation.HubDescriptor.bNumberOfPorts
For each port from 1 (they are one based!!!) to bNumberOfPorts call DeviceIoControl(hubInterfaceHandle, IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME, ...) to get unique DriverKey of device connected to this port.
Compare DriverKey string you have on previous step with string you have from DEVPKEY_Device_Driver call. If they are same - congratulations you have found USB hub and port that have your USB device connected!
Now you can call DeviceIoControl(usbHubInterfaceHandle, IOCTL_USB_GET_NODE_CONNECTION_INFORMATION, ...) to get USB_NODE_CONNECTION_INFORMATION structure that contains USB_DEVICE_DESCRIPTOR!
Also you can additionally call DeviceIoControl(usbHubInterfaceHandle, IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, ...) with USB_DESCRIPTOR_REQUEST to get other USB descriptors in addition to basic USB_DEVICE_DESCRIPTOR.
For example code see EnumerateHubPorts() and GetDriverKeyName() in official USBView sample.
Also I just did that in my RawInputDemo repo here.
UPDATE: There is easier way to get USB device number in a parent USB HUB - just get DEVPKEY_Device_Address property from a USB devnode.

How can I access a DDC/CI Display Dependent Device from a Windows application?

I am modifying a monitor controller for a prototype. It would be convenient to send commands to the prototype using DDC/CI. In Windows, I can't find an obvious way to send a DDC/CI command to a "display dependent device".
The Monitor Configuration API can send virtual control panel commands, but it does not give access to display dependent devices (which would have an I2C address other than 0x6e).
Nicomsoft's WinI2C/DDC product seems to give access to a display dependent device, but it is end-of-life. I would prefer not to build a dependency on an end-of-life product.
NVIDIA's NVAPI has an I2C API, but I would like a solution that also works with Intel and AMD graphics adaptors.
A solution exists for windows which respect XDDM driver display model. Windows 8 and 10 use WDDM.
In XDDM there is a windows O.S. supplied video port driver, and the hardware vendor supplies a miniport driver. When the miniport driver call's the video port driver's edid helper api (VideoPortDDCMonitorHelper), the miniport must supply 4 i2c function pointers as arguments.
In order to utilize these interfaces however you must be acting as the video port driver. So you have to write a video port lower filter driver which just passes along all the interfaces on from the windows supplied video port driver to the miniport driver. Hook the api's and export them to a usermode driver or ioctl which an application can call.
It may be possible to simply mount an instance of the miniport driver and some how get it to call VideoPortDDCMonitorHelper. But with out the help of the actual video port driver it would be difficult to get guidance on how to do that. Also you would have 2 instances of the driver running which may be against the rules for windows.
It does not appear this solution works for windows 8 and 10 because they use a different display driver model which doesn't appear to expose low level control of i2c. It is internal to the miniport driver.

Resources