Proxmark3 developers community

Research, development and trades concerning the powerful Proxmark3 device.

Remember; sharing is caring. Bring something back to the community.


"Learn the tools of the trade the hard way." +Fravia

You are not logged in.

#1 2009-06-22 16:23:09

adam@algroup.co.uk
Contributor
From: UK
Registered: 2009-05-01
Posts: 203
Website

Preventing linux from loading a driver

If I plug in my PM3, I get this in dmesg:

[21057.852202] hiddev96hidraw1: USB HID v1.00 Device [J. Westhues ProxMark-3 RFID Instrument] on usb-0000:00:1d.2-1

Which means that the linux client can't find it as it's already been claimed:

$ ./proxmark3
claim failed: could not claim interface 0: Device or resource busy!
PROXMARK3: NOT FOUND!

However, I can get it released by using libhid:

  TRACE: hid_compare_usb_device(): match on vendor ID: 0x9ac4.
  TRACE: hid_compare_usb_device(): inspecting product ID...
  TRACE: hid_compare_usb_device(): match on product ID: 0x4b8f.
  TRACE: hid_compare_usb_device(): no custom matching function supplied.
NOTICE: hid_find_usb_device(): found a matching USB device 003/017[0].
  TRACE: hid_force_open(): claiming USB device 003/017[0].
  TRACE: hid_os_force_claim(): failed to claim USB device 003/017[0], trying 2 more time(s)...
  TRACE: hid_os_force_claim(): detaching kernel driver from USB device 003/017[0]...
  TRACE: hid_os_force_claim(): trying again to claim USB device 003/017[0]...
NOTICE: hid_force_open(): successfully claimed USB device 003/017[0].
  TRACE: hid_init_parser(): initialising the HID parser for USB Device 003/017[0]...
  TRACE: hid_init_parser(): allocating space for HIDData structure...
  TRACE: hid_init_parser(): successfully allocated memory for HIDData strcture.
  TRACE: hid_init_parser(): allocating space for HIDParser structure...
  TRACE: hid_init_parser(): successfully allocated memory for HIDParser strcture.
NOTICE: hid_init_parser(): successfully initialised the HID parser for USB Device 003/017[0].
  TRACE: hid_prepare_hid_descriptor(): initialising the HID descriptor for USB device 003/017[0]...
  TRACE: hid_prepare_hid_descriptor(): retrieving HID descriptor for USB device 003/017[0]...
WARNING: hid_prepare_hid_descriptor(): failed to get HID descriptor for USB device 003/017[0]
  TRACE: hid_close(): closing USB device 003/017[0]...
  TRACE: hid_close(): closing handle of USB device 003/017[0]...
NOTICE: hid_close(): successfully closed USB device 003/017[0].
  TRACE: hid_reset_parser(): resetting the HID parser for USB device 003/017[0]...
  TRACE: hid_close(): freeing memory allocated for HID parser...
  TRACE: hid_close(): resetting HIDInterface...
hid_force_open failed with return code 13.
  ERROR: hid_write_identification(): cannot write identification of unopened HIDinterface.
hid_write_identification failed with return code 8.
  ERROR: hid_dump_tree(): cannot dump tree of unopened HIDinterface.
hid_dump_tree failed with return code 8.
WARNING: hid_close(): attempt to close unopened USB device .
  TRACE: hid_close(): freeing memory allocated for HID parser...
  TRACE: hid_close(): resetting HIDInterface...
hid_close failed with return code 10.
NOTICE: hid_cleanup(): successfully deinitialised HID library.

and although it then fails to play nicely with the device, it has detached the kernel driver so the client now works:

$ ./proxmark3
proxmark3> tune
> tune
# LF antenna @   0 mA /     0 mV [1273 ohms] 125Khz
# LF antenna @   0 mA /   134 mV [1187 ohms] 134Khz
# HF antenna @  41 mA /  9861 mV [235 ohms] 13.56Mhz

so my question is: does anyone know a simple way to stop linux from claiming it in the first place? I don't want to blacklist the module in modprobe config, unless I can do it just for this vendor/product id...

Offline

#2 2009-06-23 13:33:55

rule
Moderator
Registered: 2008-05-21
Posts: 416

Re: Preventing linux from loading a driver

Well you can not avoid linux claiming the device. It seems that it will always claim HID devices automatically.
A solution to this is to change the HID device into a BULK IO device, so we can use libusb to communicate with it.
This is on my mind for some time, but I never really worked it out. The usb communication framework is quite ugly hacked together and could use some structure in it.

Besides this, you can use a quickfix, but this is more like a workaround than a real solution.
You can run in your code some linux hardware operations to request releasing of the hardware peace. I've done this using libusb, but I see it seems also be possible to do this using libhid.

I think it slowly becomes time to really start on that new communication framework since the intuitive control is missing at the moment wink

Let me know if should lookup the code I used to release the proxmark from the linux-kernel.

Offline

#3 2009-06-23 19:43:54

adam@algroup.co.uk
Contributor
From: UK
Registered: 2009-05-01
Posts: 203
Website

Re: Preventing linux from loading a driver

I've just sent you a patch that fixes it. You simply call usb_detach_kernel_driver_np. for the impatient, here's the patch:

--- ../proxmark3-read-only/linux/usb.c    2009-06-23 19:30:02.000000000 +0100
+++ linux/usb.c    2009-06-23 19:32:33.000000000 +0100
@@ -153,6 +153,10 @@
    if (!handle)
        return NULL;

+    /* detatch kernel driver first */
+    ret = usb_detach_kernel_driver_np(handle, iface);
+    if (ret<0 && verbose)
+        fprintf(stderr, "detach kernel driver failed: %s!\n", usb_strerror());
    ret = usb_claim_interface(handle, iface);
    if (ret<0) {
        if (verbose)

Offline

#4 2009-07-29 23:57:30

henryk
Contributor
Registered: 2009-07-27
Posts: 99

Re: Preventing linux from loading a driver

On this subject: Why does the current firmware claim to be a HID device in the first place? The device is completely handled through a proprietary protocol in userspace over libusb. There's no HID protocol anywhere to be seen. It would be best to change the device class to 0xff (proprietary) and be done with it. I haven't done a complete test yet, but it seemed to just work when changing the descriptor in common/usb.c, recompiling and reflashing the os. Bonus: this will save 1s when plugging into Linux since the HID driver doesn't have to spend time determining that it's not going to handle the proxmark.

(Of course, enumeration still takes 15s, which is about 12s too much, haven't yet determined where that time is spent.)

Offline

#5 2009-08-04 05:38:33

ryan
Contributor
Registered: 2009-06-17
Posts: 36

Re: Preventing linux from loading a driver

Henryk, which lines/values did you change?  Seems there are a lot of class/subclass values there.

Last edited by ryan (2009-08-04 05:38:43)

Offline

#6 2009-08-04 07:20:20

henryk
Contributor
Registered: 2009-07-27
Posts: 99

Re: Preventing linux from loading a driver

The most important one is "0x03, // Class code (HID)" near line 113 in common/usb.c
Here is a complete patch which removes all references to HID from the descriptor:

Index: common/usb.c
===================================================================
--- common/usb.c  (revision 144)
+++ common/usb.c  (working copy)
@@ -42,41 +42,6 @@
 
 #define USB_DEVICE_CLASS_HID          0x03
 
-static const BYTE HidReportDescriptor[] = {
-  0x06,0xA0,0xFF,  // Usage Page (vendor defined) FFA0
-  0x09,0x01,    // Usage (vendor defined)
-  0xA1,0x01,     // Collection (Application)
-  0x09,0x02,     // Usage (vendor defined)
-  0xA1,0x00,     // Collection (Physical)
-  0x06,0xA1,0xFF,  // Usage Page (vendor defined)
-
-  //The,input report
-  0x09,0x03,     // usage - vendor defined
-  0x09,0x04,     // usage - vendor defined
-  0x15,0x80,     // Logical Minimum (-128)
-  0x25,0x7F,     // Logical Maximum (127)
-  0x35,0x00,     // Physical Minimum (0)
-  0x45,0xFF,     // Physical Maximum (255)
-  0x75,0x08,     // Report Size (8)  (bits)
-  0x95,0x40,     // Report Count (64)  (fields)
-  0x81,0x02,     // Input (Data,Variable,Absolute)
-
-  //The,output report
-  0x09,0x05,     // usage - vendor defined
-  0x09,0x06,     // usage - vendor defined
-  0x15,0x80,     // Logical Minimum (-128)
-  0x25,0x7F,     // Logical Maximum (127)
-  0x35,0x00,     // Physical Minimum (0)
-  0x45,0xFF,     // Physical Maximum (255)
-  0x75,0x08,     // Report Size (8)  (bits)
-  0x95,0x40,     // Report Count (64)  (fields)
-  0x91,0x02,     // Output (Data,Variable,Absolute)
-
-  0xC0,      // End Collection
-
-  0xC0,      // End Collection
-};
-
 static const BYTE DeviceDescriptor[] = {
   0x12,      // Descriptor length (18 bytes)
   0x01,      // Descriptor type (Device)
@@ -97,7 +62,7 @@
 static const BYTE ConfigurationDescriptor[] = {
   0x09,      // Descriptor length (9 bytes)
   0x02,      // Descriptor type (Configuration)
-  0x29,0x00,    // Total data length (41 bytes)
+  0x20,0x00,    // Total data length (32 bytes)
   0x01,      // Interface supported (1)
   0x01,      // Configuration value (1)
   0x00,      // Index of string descriptor (None)
@@ -110,21 +75,11 @@
   0x00,      // Number of interface (0)
   0x00,      // Alternate setting (0)
   0x02,      // Number of interface endpoint (2)
-  0x03,      // Class code (HID)
+  0xff,      // Class code (vendor specific)
   0x00,      // Subclass code ()
   0x00,      // Protocol code ()
   0x00,      // Index of string()
 
-  // class
-  0x09,      // Descriptor length (9 bytes)
-  0x21,      // Descriptor type (HID)
-  0x00,0x01,    // HID class release number (1.00)
-  0x00,      // Localized country code (None)
-  0x01,      // # of HID class dscrptr to follow (1)
-  0x22,      // Report descriptor type (HID)
-  // Total length of report descriptor
-  sizeof(HidReportDescriptor),0x00,
-
   // endpoint 1
   0x07,      // Descriptor length (7 bytes)
   0x05,      // Descriptor type (Endpoint)
@@ -289,9 +244,6 @@
       } else if((usd.wValue >> 8) == USB_DESCRIPTOR_TYPE_STRING) {
         const BYTE *s = StringDescriptors[usd.wValue & 0xff];
         UsbSendEp0(s, min(s[0], usd.wLength));
-      } else if((usd.wValue >> 8) == USB_DESCRIPTOR_TYPE_HID_REPORT) {
-        UsbSendEp0((BYTE *)&HidReportDescriptor,
-          min(sizeof(HidReportDescriptor), usd.wLength));
       } else {
         *((DWORD *)0x00200000) = usd.wValue;
       }

Bonus: Enumeration now only takes 5 to 7 seconds, almost as it should be.

Offline

#7 2009-08-04 22:50:37

d18c7db
Contributor
Registered: 2008-08-19
Posts: 292

Re: Preventing linux from loading a driver

Henry just an FYI, the above patch breaks windows as it fails to detect the device. I think the reason why it claims to be an HID is because JW coded it for the windows platform in the first place and wanted an easy "no driver required" setup.

As Roel said, it would make sense to recode the usb to use bulk transfers, this should speed up the buffer downloads somewhat and allow streaming of LF samples from the ADC as well.

Offline

#8 2009-08-04 23:36:36

henryk
Contributor
Registered: 2009-07-27
Posts: 99

Re: Preventing linux from loading a driver

Ah, I see. I have no clue whatsoever about windows programming, so I just imagined the windows source would use libusb, same as the linux source. Looking into it, the winsrc seems to use "hid.dll" so it actually needs the HID class.

Options:

  • Use libusb (as currently used on linux) for Windows too. This would make it possible to consolidate the USB communications code, leading to fewer "Windows OK, Linux broken"/"Windows broken, Linux OK" situations. It would also free us to use any endpoint and transport type and protocol we choose (not only bulk, but also isochronous ...) Additional bonus: libusb works on MacOS too. Drawback: Needs libusb installation on Windows, have never used that.

  • Choose CDC ACM as a communications interface, supported through the standard serial port API on both Linux and Windows. Pro: Uses bulk transfers, I've achieved approx 3 MBit/s with the ATM91SAM7 in the past (no more 10s wait for a "losamples" command). Con: Lose the current somewhat convenient packet based command format and get a little more complicated line based one. Windows support needs a custom .inf file, however this is well understood (see OpenPICC project).

  • Choose CDC Ethernet as a communications interface: you don't actually need to run IP over that, instead you'll get a packet based device for almost arbitrary data (AFAIK only the first two byte need to specify the protocol). Pro: Standard support on linux and (presumably) windows. Pro: Bulk transfers, but in keeping with the current packet based interface. Con: I've never tried that and don't know of a project using that approach to steal ideas from.

Offline

#9 2009-08-05 01:08:50

d18c7db
Contributor
Registered: 2008-08-19
Posts: 292

Re: Preventing linux from loading a driver

I can easily create a libusb "driver" package for Windows. I've done this before to access proprietary USB devices. I really like the idea of this working on OSX and Linux even though I don't use these OSes.

Offline

#10 2009-08-05 02:03:51

henryk
Contributor
Registered: 2009-07-27
Posts: 99

Re: Preventing linux from loading a driver

In the mean time, here's a patch that should fix Linux hopefully without breaking Windows:

Index: common/usb.c
===================================================================
--- common/usb.c  (revision 150)
+++ common/usb.c  (working copy)
@@ -259,6 +259,19 @@
     ;
 }
 
+static void UsbSendStall(void)
+{
+  UDP_ENDPOINT_CSR(0) |= UDP_CSR_FORCE_STALL;
+
+  while(!(UDP_ENDPOINT_CSR(0) & UDP_CSR_STALL_SENT))
+    ;
+
+  UDP_ENDPOINT_CSR(0) &= ~UDP_CSR_STALL_SENT;
+
+  while(UDP_ENDPOINT_CSR(0) & UDP_CSR_STALL_SENT)
+    ;
+}
+
 static void HandleRxdSetupData(void)
 {
   int i;
@@ -346,6 +359,8 @@
 
     case USB_REQUEST_CLEAR_FEATURE:
     case USB_REQUEST_SET_FEATURE:
+      UsbSendStall();
+      break;
     case USB_REQUEST_SET_DESCRIPTOR:
     case USB_REQUEST_SYNC_FRAME:
     default:

The Linux HID code sends a CLEAR FEATURE request which the current firmware ignores, leading to a timeout in the HID driver. Now, I've only skimmed the specs, but as far as I can see the correct way to handle GET/SET FEATURE of a type you don't want to handle seems to be to send a STALL, that's what the patch does.

Using this patch the linux enumeration goes from this:

Aug  5 00:33:35 dawn [2254020.970053] usb 2-1: new full speed USB device using uhci_hcd and address 61
Aug  5 00:33:36 dawn [2254021.160125] usb 2-1: device descriptor read/64, error -71
Aug  5 00:33:36 dawn [2254021.400063] usb 2-1: device descriptor read/64, error -71
Aug  5 00:33:36 dawn [2254021.630075] usb 2-1: new full speed USB device using uhci_hcd and address 62
Aug  5 00:33:36 dawn [2254021.760080] usb 2-1: device descriptor read/64, error -71
Aug  5 00:33:36 dawn [2254022.000083] usb 2-1: device descriptor read/64, error -71
Aug  5 00:33:37 dawn [2254022.170073] hub 2-0:1.0: unable to enumerate USB device on port 1
Aug  5 00:33:38 dawn [2254023.080078] usb 2-1: new full speed USB device using uhci_hcd and address 64
Aug  5 00:33:43 dawn [2254028.271441] usb 2-1: New USB device found, idVendor=9ac4, idProduct=4b8f
Aug  5 00:33:43 dawn [2254028.271449] usb 2-1: New USB device strings: Mfr=1, Product=2, SerialNumber=0
Aug  5 00:33:43 dawn [2254028.271454] usb 2-1: Product: ProxMark-3 RFID Instrument
Aug  5 00:33:43 dawn [2254028.271459] usb 2-1: Manufacturer: J. Westhues
Aug  5 00:33:43 dawn [2254028.271667] usb 2-1: configuration #1 chosen from 1 choice
Aug  5 00:33:53 dawn [2254038.271536] generic-usb 0003:9AC4:4B8F.0078: timeout initializing reports
Aug  5 00:33:53 dawn [2254038.271745] generic-usb 0003:9AC4:4B8F.0078: hiddev96,hidraw11: USB HID v1.00 Device [J. Westhues ProxMark-3 RFID Instrument] on usb-0000:00:1d.0-1/input0

(18 seconds) to this:

Aug  5 02:41:04 dawn [2261669.840086] usb 2-1: new full speed USB device using uhci_hcd and address 24
Aug  5 02:41:04 dawn [2261669.970079] usb 2-1: device descriptor read/64, error -71
Aug  5 02:41:05 dawn [2261670.210081] usb 2-1: device descriptor read/64, error -71
Aug  5 02:41:05 dawn [2261670.440103] usb 2-1: new full speed USB device using uhci_hcd and address 25
Aug  5 02:41:05 dawn [2261670.570063] usb 2-1: device descriptor read/64, error -71
Aug  5 02:41:05 dawn [2261670.800463] usb 2-1: device descriptor read/64, error -71
Aug  5 02:41:05 dawn [2261671.030086] usb 2-1: new full speed USB device using uhci_hcd and address 26
Aug  5 02:41:06 dawn [2261671.450055] usb 2-1: device not accepting address 26, error -71
Aug  5 02:41:06 dawn [2261671.510102] hub 2-0:1.0: unable to enumerate USB device on port 1
Aug  5 02:41:06 dawn [2261672.070062] usb 2-1: new full speed USB device using uhci_hcd and address 28
Aug  5 02:41:12 dawn [2261677.251527] usb 2-1: New USB device found, idVendor=9ac4, idProduct=4b8f
Aug  5 02:41:12 dawn [2261677.251534] usb 2-1: New USB device strings: Mfr=1, Product=2, SerialNumber=0
Aug  5 02:41:12 dawn [2261677.251540] usb 2-1: Product: ProxMark-3 RFID Instrument
Aug  5 02:41:12 dawn [2261677.251544] usb 2-1: Manufacturer: J. Westhues
Aug  5 02:41:12 dawn [2261677.252441] usb 2-1: configuration #1 chosen from 1 choice
Aug  5 02:41:12 dawn [2261677.257692] generic-usb 0003:9AC4:4B8F.00AF: hiddev96,hidraw11: USB HID v1.00 Device [J. Westhues ProxMark-3 RFID Instrument] on usb-0000:00:1d.0-1/input0

(8 seconds)

Note: The patch changes the USB code which is also used by the bootloader. If you're unsure and don't have JTAG setup handy, try with the osimage first and verify that your can still talk to the proxmark3.

The multiple read errors and resets are most likely due to the toggling of the USB pullup during the boot sequence: All I/O pins have an internal pull-up after reset. Then BootROM() disables the pullup, and jumps to AppMain() which calls UsbStart() which disables and after a slight delay re-enables the pullup. The only way around that would be by changing the hardware and inverting the output signal controlling the pullup.

P.S.: The Clear Feature that the Linux HID code send looks fishy, any thoughts on this:

(gdb) print usd
$1 = {bmRequestType = 161 '�', bRequest = 1 '\001', wValue = 256, wIndex = 0, wLength = 64}

Offline

Board footer

Powered by FluxBB