How do I programatically remove a flash drive based on its device node name? - c++

I have a Linux system with multiple USB flash drives plugged in, as /dev/sda1, /dev/sdb1, etc. I need to eject one of these from within my program -- something like EjectDrive("/dev/sdb1"); I then may need to programmatically re-insert the drive.
I know I can do this from the command line if I know the USB bus, port and device number. e.g. echo '2-1.3' > /sys/bus/usb/drivers/usb/unbind and then echo '2-1.3' > /sys/bus/usb/drivers/usb/bind
I'm not sure how to do this from C++, and be 100% sure I am using the correct bus, port and device for the specified drive.
This is an embedded platform with BusyBox v1.22.1, so udev is not available to me, and lsusb returns minimal information.

Yes it can be done using libusb (follow this link for libusb usage with C++). Now a few things to keep in mind -
1 - What is the device address? (You can get this using libusb API)
libusb_get_device_list (libusb_context *ctx, libusb_device ***list)
libusb_get_device_address (libusb_device *dev)
libusb_get_port_number (libusb_device *dev)
2 - Is the device connected to the root hub port or to a hub port? (This can be done by reading the parent device of the /dev/sdb1 or sda1)
libusb_get_parent (libusb_device *dev)
3 - If its connected to a hub, then do a control transfer to "clear" PORT_POWER feature of that port. That will turn off the port and the device will be disconnected. You can "set" PORT_POWER feature to turn on the port and the device will be connected again. Remember that you will not get any disconnect event which is as per the spec. (EHCI or XHCI)
int libusb_control_transfer ( libusb_device_handle * dev_handle,
uint8_t bmRequestType,
uint8_t bRequest,
uint16_t wValue,
uint16_t wIndex,
unsigned char * data,
uint16_t wLength,
unsigned int timeout
)
4 - If the device is connected to the root hub port directly, then please check if libusb supports clearing root hub port power. I am not sure about this. This also depends on the Host controller driver stack.
Please follow the link I mentioned at the top for example usage of these API's.

Related

DEV_TX_OFFLOAD_VXLAN_TNL_TSO Offload Testing - DPDK

I am working on Mellanox ConnectX-5 cards and using DPDK 20.11 with CentOS 8 (4.18.0-147.5.1.el8_1.x86_64).
I wanted to test the DEV_TX_OFFLOAD_VXLAN_TNL_TSO offload and what I want to ask is that what should the packet structure be like (I am using scapy) that I should send to the DPDK application such that this offload will come into action and perform segmentation (since it is a VXLAN_TNL_TSO).
I am modifying the dpdk-ip_fragmentation example and have added: DEV_TX_OFFLOAD_IP_TNL_TSO inside the port_conf
static struct rte_eth_conf port_conf = {
.rxmode = {
.max_rx_pkt_len = JUMBO_FRAME_MAX_SIZE,
.split_hdr_size = 0,
.offloads = (DEV_RX_OFFLOAD_CHECKSUM |
DEV_RX_OFFLOAD_SCATTER |
DEV_RX_OFFLOAD_JUMBO_FRAME),
},
.txmode = {
.mq_mode = ETH_MQ_TX_NONE,
.offloads = (DEV_TX_OFFLOAD_IPV4_CKSUM |
DEV_TX_OFFLOAD_VXLAN_TNL_TSO
),
},
};
And at the ol_flags:
ol_flags |= (PKT_TX_IPV4 | PKT_TX_IP_CKSUM | PKT_TX_TUNNEL_VXLAN );
In short, to test this offload it would be great if someone can help me with 2 things:
What should the packet structure be that I should send (using scapy, such that the offload comes into action)?
Required settings to do in the DPDK example application (It is not necessary to use the ip_fragmentation example, any other example would be fine too).
note: Based on the 3 hours debug session, it is been clarified the title and question shared is incorrect. Hence the question will be re-edited to reflect actual requirement as how enable DPDK port with TCP-TSO offloads for tunnelled VXLAN packets.
Answer to the first question what should be scapy settings for sending a packet to DPDK DUT for TSO and receiving segmented traffic is
Disable all TSO related offload on the SCAPY interface using ethtool -K [scapy interface] rx off tx off tso off gso off gro off lro off
Set MTU to send larger frames like 9000
Ensure to send large frames as payload but less than interface MTU.
Run tcpdump for ingress traffic with the directional flag as tcpdump -eni [scapy interface] -Q in
Answers to the second question Required settings to do in the DPDK example application is as follows
dpdk testpmd application can enable HW and SW TSO offloads based on NIC support.
next best application is tep_termination, but requires vhost interface (VM) or DPDK vhost to achieve the same.
Since the requirement is targeted for any generic application like skeleton, l2fwd, one can enable as follows
Ensure to use DPDK 20.11 LTS (to get the latest and best support for TUNNEL TSO)
In application check for tx_offload capability with dev_get_info API.
Cross-check for HW TSO for tunnelled (VXLAN) packets.
If the TSO needs to done for UDP payload, check for UDP_TSO support in HW.
configure the NIC with no-multisegment, jumbo frame, max frame len > 9000 Bytes.
Receive the packet via rx_burst, and ensure the packet is ipv4, UDP, VXLAN (tunnel) with nb_segs as 1.
modify the mbuf to point to l2_len, l3_len, l4_len.
mark the packets ol_flags as PKT_TX_IPV4 | PKT_TX_TUNNEL_VXLAN | PKT_TX_TUNNEL_IP. For UDP inner payload PKT_TX_TUNNEL_UDP.
then set the segment size as DPDK MTU (1500 as default) - l3_len - l4_len
This will enable the PMD which support HW TSO offload to update appropriate fields in descriptors for the given payload to transmitted as multiple packets. For our test case scapy send packet of 9000 bytes will be converted into 7 * 1500 byte packets. this can be observed as part tcpdump.
Note:
the reference code is present in tep_termination and test_pmd.
If there is no HW offload, SW library of rte gso is available.
For HW offload all PMD as of today require the MBUF is a continuous single non-external buffer. So make sure to create mbufpool or mempool with sufficient size for receiving large packets.

How to use IOServiceOpenAsFileDescriptor?

I have a USB device attached. I decided to try to write some code where I open the USB device as a FileDescriptor like on Linux where I can use ioctl function on the fd to send commands.
I ended up with the following:
CFMutableDictionaryRef matches = IOServiceMatching(kIOUSBDeviceClassName);
if (!matches)
{
std::cerr<<human_error_string(kIOReturnError)<<"\n";
return;
}
io_iterator_t deviceIterator;
kern_return_t kr = IOServiceGetMatchingServices(kIOMasterPortDefault, matches, &deviceIterator);
if (kr != kIOReturnSuccess)
{
std::cerr<<human_error_string(kr)<<"\n";
return;
}
io_service_t service = IO_OBJECT_NULL;
while((service = IOIteratorNext(deviceIterator)))
{
int32_t fd = IOServiceOpenAsFileDescriptor(service, O_RDWR) //doesn't work! Returns: -1
IOObjectRelease(service);
}
IOObjectRelease(deviceIterator);
However, the FD is always -1.. Any ideas why?
As far as I'm aware, there isn't any kind of file descriptor based API for USB on macOS. You need to go through the IOUSB based APIs. There's some example code here.
If you want to share as much code as possible between Linux an macOS, you can use libusb which wraps both Apple's IOKit API and Linux's ioctl based USB API.
I have to admit I'm not exactly sure what IOServiceOpenAsFileDescriptor is intended for. The source code in IOKitLib is not terribly enlightening, as it simply connects to an XPC service and the file descriptor is expected in the XPC reply. I assume the service is implemented in a system daemon that isn't open source or documented.
Perhaps IOServiceOpenAsFileDescriptor is for accessing block devices or serial ports, which have both an IOKit object and a device node file in /dev/. General USB devices do not have a node in the file system.

No DPDK packet fragmentation supported in Mellanox ConnectX-3?

Hello Stackoverflow Experts,
I am using DPDK on Mellanox NIC, but am struggling with applying the packet
fragmentation in DPDK application.
sungho#c3n24:~$ lspci | grep Mellanox
81:00.0 Ethernet controller: Mellanox Technologies MT27500 Family
[ConnectX-3]
the dpdk application(l3fwd, ip-fragmentation, ip-assemble) did not
recognized the received packet as the ipv4 header.
At first, I have crafted my own packets when sending ipv4 headers so I
assumed that I was crafting the packets in a wrong way.
So I have used DPDK-pktgen but dpdk-application (l3fwd, ip-fragmentation,
ip-assemble) did not recognized the ipv4 header.
As the last resort, I have tested the dpdk-testpmd, and found out this in
the status info.
********************* Infos for port 1 *********************
MAC address: E4:1D:2D:D9:CB:81
Driver name: net_mlx4
Connect to socket: 1
memory allocation on the socket: 1
Link status: up
Link speed: 10000 Mbps
Link duplex: full-duplex
MTU: 1500
Promiscuous mode: enabled
Allmulticast mode: disabled
Maximum number of MAC addresses: 127
Maximum number of MAC addresses of hash filtering: 0
VLAN offload:
strip on
filter on
qinq(extend) off
No flow type is supported.
Max possible RX queues: 65408
Max possible number of RXDs per queue: 65535
Min possible number of RXDs per queue: 0
RXDs number alignment: 1
Max possible TX queues: 65408
Max possible number of TXDs per queue: 65535
Min possible number of TXDs per queue: 0
TXDs number alignment: 1
testpmd> show port
According to DPDK documentation.
in the flow type of the info status of port 1 should show, but mine shows
that no flow type is supported.
The below example should be the one that needs to be displayed in flow types:
Supported flow types:
ipv4-frag
ipv4-tcp
ipv4-udp
ipv4-sctp
ipv4-other
ipv6-frag
ipv6-tcp
ipv6-udp
ipv6-sctp
ipv6-other
l2_payload
port
vxlan
geneve
nvgre
So Is my NIC, Mellanox Connect X-3 does not support DPDK IP fragmentation? Or is
there additional configuration that needs to be done before trying out the packet fragmentation?
-- [EDIT]
So I have checked the packets from DPDK-PKTGEN and the packets received by DPDK application.
The packets that I receive is the exact one that I have sent from the application. (I get the correct data)
The problem begins at the code
struct rte_mbuf *pkt
RTE_ETH_IS_IPV4_HDR(pkt->packet_type)
This determines the whether the packet is ipv4 or not.
and the value of pkt->packet_type is both zero from DPDK-PKTGEN and DPDK application. and if the pkt-packet_type is zero then the DPDK application reviews this packet as NOT IPV4 header.
This basic type checker is wrong from the start.
So what I believe is that either the DPDK sample is wrong or the NIC cannot support ipv4 for some reason.
The data I received have some pattern at the beginning I receive the correct message but after that sequence of packets have different data between the MAC address and the data offset
So what I assume is they are interpreting the data differently, and getting the wrong result.
I am pretty sure any NIC, including Mellanox ConnectX-3 MUST support ip fragments.
The flow type you are referring is for the Flow Director, i.e. mapping specific flows to specific RX queues. Even if your NIC does not support flow director, it does not matter for the IP fragmentation.
I guess there is an error in the setup or in the app. You wrote:
the dpdk application did not recognized the received packet as the ipv4 header.
I would look into this more closely. Try to dump those packets with dpdk-pdump or even by simply dumping the receiving packet on the console with rte_pktmbuf_dump()
If you still suspect the NIC, the best option would be to temporary substitute it with another brand or a virtual device. Just to confirm it is the NIC indeed.
EDIT:
Have a look at mlx4_ptype_table for fragmented IPv4 packets it should return packet_type set to RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | RTE_PTYPE_L4_FRAG
Please note the functionality was added in DPDK 17.11.
I suggest you to dump pkt->packet_type on console to make sure it is zero indeed. Also make sure you have the latest libmlx4 installed.

How to enumerate an USB hub that is attached to the first port of root hub on Windows Embedded 7

I am posting here for the first time, I hope this will be clear and readable.
I am currently trying to test the presence of usb devices on an embedded system using a specific HCD and port path programmatically using C++ and Visual Studio 2008.
The idea is to pass in the port number and the hcd value as the parameters of the function, and the function will return a true or false that indicates the connection status.
I have written some code to populate the root hub and prove that the device attached to port 1 of the root hub is a hub using bool DeviceIsHub from usbioctl.h.
However, when I attempt to enumerate the usb hub attached to port 1 of root so that I may test for the connection status of the downstream ports for the presence of device(ports 1 and 2 of this usb hub). It does not seem to know how many downstream ports the usb hub has.
I checked USBVIEW/TreeView, both application tells me that devices are there
but I am not sure what ioctl command code to use such that I can enumerate the downstream ports so I can check the connection status.
The structure of the device based on USB view and USB tree provides the following.
Root hub - it has 7 ports, only the first port is being used.
A USB hub (it has four available ports) is attached to the first port of the root hub.
Two USB devices (USB mouse and USB keyboard) are attached to port 1 and port 2 of the USB hub.
I have tried IOCTL_USB_GET_CONNECTION_INFORMATION, IOCTL_USB_GET_CONNECTION_NAME,
IOCTL_USB_GET_CONNECTION_INFORMATION_EX, IOCTL_USB_PORT_CONNECTOR_PROPERTIES
(which is not supported, it can only be used in windows 8, this is the exact ioctl call they used to enumerate the ports).
Please ignore the MessageBoxes, those are for me to check the control path status and determine which route it was following.
Please find the code that I wrote as I attempt to enumerate/populate the usb hub. I did not include the Root hub code because it would make this snippet too big.
My questions mainly resides in the enumeration process of the secondary USB hub I believe.
I just checked the registry key of the device. it appears that the USB hub is enumerated and present on the device since the information is shown under regedit HKLM->System->CurrentControlSet->Enum->USB. I believe I am not enumerating it correctly within my test application.
Any help would be greatly appreciated.
Update
The part that I am most concerned about is the DeviceIoControl Calls that attempts to get the size and the actual name of that USB hub.
It currently only takes in USB_GET_NODE_INFORMATION. Any other ioctl calls that are intended to retrieve the name of the hub will fail at the first DeviceIoControl where it attempts to get the size of the hub name so that it know how much memory to allocate
for it.
Update Part 2
From observing the usbview open source code, I believe I need to enumerate the host controller and all the devices first before checking for the presence of device. I drew a conclusion such that without doing the enumeration of controller, it only goes so far down the tree (at best second layer, which is where the external hub is attached to in my case).
I am currently attempting to enumerate the other devices and controllers in hope that I can get to the third layer of device. I will keep on updating this thread until either I figure out the problem myself or someone is capable of answering my questions.
//we are connected to the external hub, now we can begin the configuration and enumeration of the external hub.
ULONG kBytes = 0;
USB_HUB_NAME SubHubName;
//Create a Handle for the external hub driver
char Name[16];
wsprintf(Name, "\\\\.\\HCD%d", HcdSub);
HANDLE SubHub = CreateFile(Name,
GENERIC_WRITE,
FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
0,
NULL);
//Check to see if the handle was created successfully
if (SubHub == INVALID_HANDLE_VALUE)
{
MessageBox(NULL,"SubHandle Fail ","TEST",MB_OK);
return false;
}
//Query the SUBHUB/External Hub for the structure, this will tell us the number of down stream ports we need to enumerate
ioctlSuccess = DeviceIoControl(SubHub,
IOCTL_USB_GET_NODE_INFORMATION,
0,
0,
&SubHubName,
sizeof(SubHubName),
&kBytes,
NULL);
//If the command failed, close the handle and return false.
if(!ioctlSuccess)
{
CloseHandle(SubHub);
MessageBox(NULL," sub hub size fail ","TEST",MB_OK);
return false;
}
//Prepare to receive the SubHubName
kBytes = SubHubName.ActualLength;
USB_HUB_NAME *subHubNameW = (USB_HUB_NAME *) malloc(sizeof(USB_HUB_NAME) * kBytes);
//Check if the allocation failed, if it did, free the memory allocated and return false.
if (subHubNameW == NULL)
{
free(subHubNameW);
CloseHandle(SubHub);
MessageBox(NULL,"SUBHubNameW=NULL ","TEST",MB_OK);
return false;
}
//Send the command to retrieve the name
ioctlSuccess = DeviceIoControl(SubHub,
IOCTL_USB_GET_NODE_INFORMATION,
NULL,
0,
subHubNameW,
kBytes,
&kBytes,
NULL);
//We no longer need this handle.
CloseHandle(SubHub);
if(!ioctlSuccess)
{
if(subHubNameW !=NULL)
{
free(subHubNameW);
}
MessageBox(NULL,"GET NODE INFO FAIL ","TEST",MB_OK);
return false;
}
//Converts the SubHubNAme from widechar to a cahr.
MessageBox(NULL,"BEGIN CONVERTION","TEST",MB_OK);
kBytes = wcslen(subHubNameW->HubName) + 1;
char *subhubname = (char *) malloc(sizeof(char)*kBytes);
wcstombs(subhubname,subHubNameW->HubName, kBytes);
//we no longer need subHubNameW the information is now in subhubname.
if(subHubNameW !=NULL)
{
free(subHubNameW);
}
//Attempt to open a handle to driver for sub hub.
int SubhdnSize = strlen(subhubname) + sizeof("\\\\.\\");
char *subhubnamelength = (char *) malloc(sizeof(char) * SubhdnSize);
sprintf(subhubnamelength, "\\\\.\\%s", subhubname);
//We no longer need subhubname, so free it.
if(subhubname !=NULL) free(subhubname);
//Attempt to open a handle for enumerating ports on this hub.
HANDLE ExternalHub = CreateFile(subhubnamelength,
GENERIC_WRITE,
FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
0,
NULL);
//we no longer need subhubnamelength, so free it if it is not NULL
if(subhubnamelength != NULL) free(subhubnamelength);
//Check and see if the handle was created successfully, if not, return false.
if(ExternalHub == INVALID_HANDLE_VALUE)
{
CloseHandle(ExternalHub);
MessageBox(NULL,"EXT handle fail ","TEST",MB_OK);
return false;
}
}
USB_NODE_CONNECTION_ATTRIBUTES *PortConnection =
(USB_NODE_CONNECTION_ATTRIBUTES *) malloc(sizeof(USB_NODE_CONNECTION_ATTRIBUTES));
PortConnection ->ConnectionIndex = Port;
ioctlSuccess = DeviceIoControl(ExternalHub,
IOCTL_USB_GET_NODE_CONNECTION_ATTRIBUTES,
PortConnection,
sizeof(USB_NODE_CONNECTION_ATTRIBUTES),
PortConnection,
sizeof(USB_NODE_CONNECTION_ATTRIBUTES),
&kBytes,
NULL);
if(!ioctlSuccess)
{
MessageBox(NULL,"DEVICE CONNECTION FAIL ","TEST",MB_OK);
return false;
}
if(PortConnection->ConnectionStatus !=DeviceConnected)
{
printf("The Connection Status Returns: %d",PortConnection->ConnectionStatus);
printf("\n");
return false;
}
Enumerating USB on Windows 7 will fail if UAC is enabled and application doesn't have enough privilege. Windows Embedded 7 may fail also on similar task.
There is also a possibility to enumerate through registry.
You can not enumerate anything possibly. Normally the usb device is either a bus device or a child of a bus device. Sense the bus device is not removable, it is automatically enumerated by acpi.sys the root device during boot, or if a bus device for some other device attached to the root node, then that device has to undergo some event that means it detects the device and then enumerates it, plug and play will automatically look for it's device type's driver and if installed will load it. If the usb say has 4 actual usb connectors, that are controlled from a central device, there could be a usb driver/mini driver pair. In that case the miniport driver is a child of the usb driver and is enumerated by it and attached to it. The miniport's job is to know the actual hardware, and irp's and all other io will come from it's parent. If there are several physical connections there may be additional child drivers. They all operate the hardware and there is a hot plug. When the firmware detects the installation of a usb device it communicates this to the miniport driver and on down the stack to the bus and ultimately it is processed by plug and play. Plug and play will then have the miniport driver enumerate it's device, but it needs to get a hardware id. Then it can find it's driver and load that, then the device is installed and ready for operation.
With out knowing the device stack it is not clear what device it is referring to. Keep in mind the driver stack may not reflect the actual hardware topology. There are also things called logical devices which do not represent any piece of hardware. Any of these would have to be taken into account and you need to know which device corresponds to the end of the node.
Also one little detail. I'm not as familiar with user mode api's and drivers as I am kernel, but it seems wsprintf second argument controls format of the output buffer from the input. It should be %[]%[] were [] is a symbol that represents the format. It would format the first character according to the first symbol then the second character with teh second symbol. Seems you are doing something different.
A final note, it appears the use of wsprintf() is now deprecated instead for other api's.

Use Arduino signals as input for PC?

I recently got my hands on an Arduino (Uno), and I was wondering something.
I've got no external volume changer for my speakers, so I thought, maybe hook up a potentiometer to the Arduino, and then use that to control the volume (in Windows). But is that possible?
To read a value of an Arduino pin using maybe Visual C, C++ (or some more 'multi-platform' language)? And then using that to set the volume level in Windows (and if it's possible also in Linux).
I thought it might be possible, because if you use:
Serial.println(analogRead([pin with potentiometer]));
You can get the values of the potentiometer to the pc (via USB). So is there any way to read those values in C or C++?
I know how to set the volume in Windows via C or C++, I only need to know if there is a way to read out the values of a potentiometer in a (Visual) C or C++ script.
Definitely. And using exactly the same method: serial communication. Since I'm not a great Windows expert, I can't write you a complete Windows example, but here are some snippets that may get you started on a Unix (Linux, OS X, etc.):
Code on the Arduino:
#define POT_PIN 1
void setup()
{
Serial.begin(9600); // 9600 baud is more than enough
}
void loop()
{
int pot = analogRead(POT_PIN);
unsigned char byte = (pot + 2) >> 2; // round and divide by 4
Serial.write(pot);
delay(100); // or do something useful
}
Code on the computer:
#include <termios.h>
struct termios tio;
memset(&tio, 0, sizeof(tio));
// Open serial port in mode `8N1', non-blocking
tio.c_cflag = CS8 | CREAD | CLOCAL;
tio.c_cc[VMIN] = 1;
tio.c_cc[VTIME] = 5;
int fd = open(device, O_RDONLY);
cfsetospeed(&tio, B9600);
cfsetispeed(&tio, B9600);
tcsetattr(fd, TCSANOW, &tio);
while (1) {
unsigned char byte;
read(fd, &byte, 1);
use_some_library_to_set_volume(byte);
}
There are some things to consider.
You want the PC to listen to your "potentiometer Arduino" only. You don't want it to listen to any random USB data coming at any port. There is a need to create a data protocol which is somewhat unique to your device. If you just spam analog readings you'll get some raw data like "123 128 133 145", which could mean anything and come from any kind of device.
When you type Serial.whatever, the Arduino is likely spitting out an UART signal. I don't know a thing about Arduino, but hopefully it has either RS-232 or USB circuitry on board. You will need a matching port on the PC, the traditional RS-232 9 pin d-sub connector is getting increasingly rare on modern computers. You might need a RS-232 to USB converter.
You need a mean to determine which COM port the device is connected to. USB ports and traditional RS-232 ports work the same, as far as the PC is concerned. Either let the user pick the port manually, or design a more intelligent algorithm to find the port where your device is connected.
Study the Windows API for all the serial port routines. Documentation and examples at MSDN.