Thursday, February 17, 2011

Using the Microchip ZENA ZigBee/802.15.4 network analyzer with Linux

Summary: The Microchip Technologies Inc ZENA is a 2.4GHz 802.15.4 (ZigBee, MiWi etc) network analyzer. It comes with free Windows-only software. There is no support for Linux and cannot be used with powerful tools like Wireshark. There is very little documentation available for the device hardware. In this post I've documented reverse engineering efforts by myself and others and present a small C utility for pcap packet capture on the Linux platform. 
Update (23 July 2013): Mr-TI has written an updated version of this tool to work with the latest version of the ZENA hardware: https://github.com/Mr-TI/ZenaNG

Update (3 Mar 2012): This article was originally written in Feb 2011. Microchip have just released a new version of the ZENA which comes in a USB 'thumbdrive' casing. This new version is based on their own MRF24J40 transceiver chip. This article relates to the older model.

The ZENA is a 802.15.4 network analyzer from Microchip Technologies Inc. It costs about $130.  It comes with free (closed source) Windows software. If you need encryption support you'll need to separately purchase an enhanced version of the ZENA software for $5.

The Windows ZENA isn't bad. It displays plackets as horizontal slabs and color codes each part of the packet. There is some basic filtering functions. For more comprehensive reviews see [1] and [2]. If you need to use this with Linux or you need a long packet capture you're out of luck. The export from the Windows software is limited to about 21 kB of data at a time.


Documentation on the hardware and USB protocol is scant. Joshua Wright did some reverse engineering work on the ZENA back in 2009 and wrote a Python script that selected a 802.15.4 channel of your choice and dumped raw data from the USB port to the screen. Due to the relatively high cost and limitations (packet injection not possible) of the ZENA his work on this device as shelved in favor of the cheaper and more flexible alternatives (eg Atmel's RZUSBStick)

I've taken Joshua's work and brought it to a point where it can be used to capture long ZigBee packet dumps in pcap format and analyze them with Wireshark.

The ZENA hardware

The ZENA comprises 75mm x 40mm PCB with a PIC 18LF2550 MCU clocked at 16MHz, a MRF24J40   CC2420 2.4GHz 802.15.4 radio transceiver, PCB antenna (with the option of installing a SMA connector for external antenna) and a mini-USB port to communicate with the host computer and provide power for the device.

The PCB seems to have been designed with other applications in mind also, having an unused area for a button cell on the underside and pads for switches on top. For some odd reason the MRF24J20 chip is unmarked.  Update: I've been informed that the ZENA predated Microchip's own MRF24J40 so the Texas Instruments CC2420 chip (originally made by Chipcon before being acquired by TI) was used instead. The markings must have been removed by Microchip for commercial reasons but are still just visible under the right light.


There are 3 green LEDs marked D2, D4 and D3. D2 appears to be a heartbeat which flashes with a one second on / one second off duty cycle while the ZENA is in sniffer mode. The rhythm is disrupted whenever a packet is received. D3 also flashes with network activity but I cannot deduce a pattern. D4 is illuminated only during the powerup test sequence.

ZENA USB Protocol

The ZENA (vendor ID 0x04d8 , product ID 0x000E) presents itself as a Human Interface Device (HID).

"lsusb" is a useful utility to discover metadata about USB devices. The following command will dump information about the ZENA to screen: "lsusb -v -d 04d8:000e". This output looks like this (I've highlighted lines of interest in bold):

Bus 002 Device 003: ID 04d8:000e Microchip Technology, Inc. 
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               2.00
  bDeviceClass            0 (Defined at Interface level)
  bDeviceSubClass         0 
  bDeviceProtocol         0 
  bMaxPacketSize0         8
  idVendor           0x04d8 Microchip Technology, Inc.
  idProduct          0x000e 
  bcdDevice            0.00
  iManufacturer           1 
  iProduct                2 
  iSerial                 0 
  bNumConfigurations      1
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength           41
    bNumInterfaces          1
    bConfigurationValue     1
    iConfiguration          0 
    bmAttributes         0x80
      (Bus Powered)
    MaxPower              100mA
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           2
      bInterfaceClass         3 Human Interface Device
      bInterfaceSubClass      0 No Subclass
      bInterfaceProtocol      0 None
      iInterface              0 
        HID Device Descriptor:
          bLength                 9
          bDescriptorType        33
          bcdHID               1.01
          bCountryCode            0 Not supported
          bNumDescriptors         1
          bDescriptorType        34 Report
          wDescriptorLength      34
         Report Descriptors: 
           ** UNAVAILABLE **
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x81  EP 1 IN
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0040  1x 64 bytes
        bInterval               1
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x01  EP 1 OUT
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0040  1x 64 bytes
        bInterval               1


USBSnoop and usbmon are another useful tools which can be used to eavesdrop on USB traffic when used with the supplied Windows software.

This is what I know about the ZENA USB interface so far (lots gleaned from Joshua Wright's blog post and the Python script linked above):
  • There are two end points: a control channel (0x01) and a packet channel (0x81)
  • There is only one known control function: to select a 802.15.4 channel in the range 11 to 26. This is achieved by allocating a 64 byte buffer, zeroing it and setting the channel number (11 to 26) in byte offset 1 (second byte of the buffer). Send this to the control end point 0x01 using  usb_interrupt_write()
  • To read 802.15.4 packet data allocate a 64 byte buffer and issue a usb_interrupt_read() to end point 0x81. If there are no packets available, usb_interrupt_read() will block until a packet arrives or the timeout period is reached. A timeout can be detected by checking the return status for -110.
  • The first 6 bytes in the buffer are a ZENA header. Byte 0 is always 0x00. 
  • ZENA header bytes 1 - 4 is a packet timestamp. Bytes 1 and 2 is the fraction of a second in 2^-16 second units (first byte is the least significant). Bytes 3 and 4 is the seconds part of the timestamp.
  • ZENA header byte 5 is the number of bytes of data remaining. The remaining data at this point is the 802.15.4 packet data (excluding FCS) plus two reception quality bytes at the end.
  • If the length field is greater than 58 bytes then one or more additional usb_interrupt_read() requests must be issued to retrieve the remaining data. The data will continue at byte offset 1 (for some reason the first byte returned by usb_interrupt_read() to this device is always 0x00)
  • The ZENA does not return the 802.15.4 FCS. You will need to recompute it if you need it. It does however return a single FCS OK bit in the last byte of the data.
  • Instead of the FCS, the last two bytes is reception quality information: I assume the values are as described in the MRF 24J40 datasheet (see sections 3.7 and 3.6) CC2420 datasheet section 16.4: "The first FCS byte is replaced by the 8-bit RSSI value. This RSSI value is measured over the first 8 symbols following the SFD... The 7 least significant bits in the last FCS byte are replaced by the average correlation value of the 8 first symbols of the received PHY header (length field) and PHY Service Data Unit (PSDU). This correlation value may be used as a basis for calculating the LQI."

The LQI and RSSI values from a sample packet capture look like this:


The ZENA command line utility

I've opted to use plain C instead of Python. I'm more familiar (albeit very rusty) with C and it eliminates dependency on Python and PyUSB. You will still require libusb and associated development files which may not be installed by default. I am currently using libusb version 0.1. I plan to move to the more recent version 1.0 for the next release. The file can be downloaded from the download area at http://code.google.com/p/microchip-zena/

To install on Ubuntu make sure libusb (version 0.1) is installed:
sudo apt-get install libusb libusb-dev

To compile just do:
gcc -o zena zena.c -lusb -lrt

(Update 20 Feb 2011:  version 0.2+ of the zena utility has slightly different dependencies and compile instructions. See comments near the top of the C file on how to compile and run.)

To run:

You'll probably need to be logged in as root to do all of these things. On Ubuntu you can do
sudo bash
to avoid prefixing everything with "sudo".

Prior to running you need to make sure the ZENA device is "unbound" from any kernel drivers. If you get a "ERROR: ZENA device not found or not accessible", that is likely your problem.  I would love to be able to check for this and unbind programatically, but I don't know how to go about it. Suggestions welcome. (Update 20 Feb 2011: It is possible to check if a device is bound to a kernel driver and unbind it in libusb 1.0 using libusb_kernel_driver_active() and libusb_detach_kernel_driver() functions. This will be incorporated in the next release – version 0.3).

This is how to "unbind" it: While ZENA is *not* plugged in, look at files in /sys/bus/usb/drivers/usbhid/
There should be files eg "1-3.1:1.0". Now connect the ZENA. You will find a new file in that directory. Make note of it. For this example assume it’s "1-3.3:1.0". Now do:

echo 1-3.3:1.0 > /sys/bus/usb/drivers/usbhid/unbind

(replace the "1-3.3:1.0" with whatever you find for your system)

Once the device is available you can run the zena utility.

zena -c channel [-f format] [-v] [-h] [-d level] [-h]

-c selects 802.15.4 channel and is mandatory. A number between 11 and 26 is expected.

-f selects packet dump format. Two output formats are supported:
  • pcap (default):  packet capture file which can then be imported into Wireshark and other tools
  • usbhex: this dumps the raw 64 byte chunks of data obtained from the USB port in hex. One line per 64 byte chunk. Each chunk is prefixed with a timestamp obtained from the host computer
-v will display version information and quit.
-h will display usage information and quit.
-d will display debugging information to stderr. A level of 0 implies no debugging (default), 9 maximum verbosity.

The packet capture output is sent to standard output.



Important note: I have observed kernel crashes running this utility on a fully updated (15 Feb 2011) Ubuntu 10.4 (kernel 2.6.32-28-generic).  A fresh Ubuntu 10.10 (kernel 2.6.35-22-generic) installed from CD image seems not to be affected by this problem.  I can only assume it's a bug in the USB part of the kernel. I suggest bringing the computer to single user mode when you try this the first time (or just be prepared to power cycle if you have to). Alternatively install Linux in a VM, attach the ZENA device to the VM and run from there: the kernel crash is contained within the VM. The Python script which this utility is based on also causes a similar crash -- so it's not specific to my implementation. (Update 22 Feb 2011: this seems not to happen any more since the move to libusb 1.0)

No binary is provided at this time. But it's trivial to build if you have gcc and libusb installed.

Corrections or additional information would be greatly appreciated. I'd be glad to expand this utility to use the ZENA to it's full potential. Let me know what you need.

Project files are hosted at Google:
http://code.google.com/p/microchip-zena/

I can be contacted at jdesbonnet (at) gmail (dot) com

References:
[1]
http://homewireless.org/wp/2010/05/a-tale-of-two-packet-sniffers-microchip-zena-and-avr-rz-usbstick/
[2]
http://www.willhackforsushi.com/?p=198

ZENA is a trademark of Microchip Technologies Inc.

4 comments:

Joshua Wright said...

Awesome work and thanks for making your tool available as open-source. As Joe points out, the Zena hardware is very cool for its ability to easily add an RP-SMA external antenna connector (DigiKey part #CONREVSMA001-SMD-ND, $3.81/USD).

Nice work John!

-Josh

Joshua Wright said...

:%s/John/Joe/g

Sorry Joe.

-Josh

Mr-TI said...

Great work!

I have updated this tool to manage the new hardware version based on the MRF24J40 chip.

https://github.com/Mr-TI/ZenaNG

Joe Desbonnet said...

Thanks Mr-TI: I've updated the text to point to your Github location.