Analisi del Protocollo di Comunicazione USB
Il tipo di periferica
Innanzitutto bisogna capire in che modo la nostra stazione viene riconosciuta dal sistema. Se analizziamo l'elenco periferiche scopriamo che, al momento del collegamento USB una nuova periferica di tipo HID è presente sul sistema. A dirla tutta le periferiche che compaiono sono due ma ciò dipende essenzialmente dal tipo di interfacce che ogni periferica HID espone verso il sistema.
HID è una specifica SW/HW che permette il riconoscimento di periferiche USB senza bisogno di driver aggiuntivi, tipicamente è usata per dispositivi “Human Interface” quali mouse, tastiere, joysticks e similari.
Concentriamoci però su qualche dettaglio: facendo click col tasto destro e selezionando Proprietà, scopriamo qualcosa di più “intimo” della periferica ovvero il VendorID e il ProductID cioè due parametri che individuano univocamente in ogni sistema la periferica. Dalla figura che segue scopriamo essere VID: 1130 e PID: 6880.
A titolo di esempio vediamo anche cosa succede su linux:
comando: tail -f /var/log/messages
notate il riconoscimento di una periferica HID
comando: lsusb
potete verificare che i VID e PID sono gli stessi.
L'arte dello “Sniffing”
Appurato con che tipo di periferica abbiamo a che fare il passo successivo è indagare ulteriormente per scoprire se la periferica supporta un tipo di comunicazione “avanzata” tipica dell'HID protocol. Per chi volesse approfondire questo aspetto consiglio questa lettura: http://www.linuxjournal.com/article/8145 che verte su Linux ma le cui cosiderazioni sul protocollo HID sono di validità generale. La nostra periferica risponde all'indagine in questo modo:
Interface Descriptor:
bLength 9 bDescriptorType 4 bInterfaceNumber 0 bAlternateSetting 0 bNumEndpoints 1 bInterfaceClass 3 Human Interface Device bInterfaceSubClass 0 No Subclass bInterfaceProtocol 0 None iInterface 0 ** UNRECOGNIZED: 09 21 10 01 00 01 22 22 00 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x81 EP 1 IN bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0008 1x 8 bytes bInterval 10
l'UNRECOGNIZED ci dice sostanzialmente che il tipo di comunicazione è “bulk”: Tale tipo di comunicazione è costituito da una richiesta dell'host (il ns PC) e da risposte attraverso richieste di interrupt, ad ogni richiesta la periferica riversa i dati su un buffer corrispondente all'Endpoint (parametro bEndpointAddress) per un max di byte pari a wMaxPacketSize ad intervalli minimi di bInterval ms.
Cerchiamo di verificare quanto dedotto dall' Interface Descriptor. Per far ciò useremo su Windows il programma SnoopyPro(http://sourceforge.net/projects/usbsnoop/files/) che permette di catturare il traffico USB generato tra MeteoLog e la stazione. Utilizziamolo secondo i seguenti passi:
- lanciamo SnoopyPro PRIMA di avviare MeteoLog
- il primo passo fare l'unpack dei drivers e successivamente installarli (operazione che va ripetuta tutte le volte che si lancia il prog, i driver che installa sono infatti temporanei visto che sono attivi solo in memoria)
- aprire la finestra delle periferiche USB premendo F2 oppure il pulsante cerchiato di verde
- selezionare la periferica riconoscibile da VID e PID e, tramite click con il tasto destro, scegliere “Install and Restart”
- a questo punto si apre una finestra di log ed è adesso che va avviato MeteoLog. Noterete che il contatore dei pacchetti inizierà ad aumentare e, nella prima fase di MeteoLog ovvero lo scarico del datalogger, vederemo arrivare il contatore a circa 20000.
- una volta che lo scarico del datalogger è terminato assisteremo a incrementi di 48 pacchetti ogni 5 minuti: è il polling che MeteoLog fa per acquisire i dati realtime. Lasciamo che il polling acquisisca 2-3 campioni e poi premiamo sul pulsante di stop: compare la seguente finestra con l'intero log della comunicazione USB
Analizziamola in dettaglio:
- 1) Meteolog fa richiesta di polling tramite un comando USB di tipo CLASS_INTERFACE inviato all'EndPoint “bulk” 0x00: tale comando è costituito da un pacchetto di 8 byte di cui il primo indica il “payload” del pacchetto stesso ovvero quanti byte vadano considerati come dato vero e proprio. In questo caso, quindi, il comando sono i due byte FF AF.
- 2) Dopo un po' di tempo (inferiore al secondo) la stazione inizia a inviare richieste di interrupt rendendo disponibile all'Endpoint 0x81 pacchetti di 8 byte. Tali richieste si susseguono a intervalli cadenzati di circa 40ms e sono anch'essi caratterizzati da avere il primo byte come indicatore del payload.
- 3) A un certo punto la stazione, non avendo più dati da inviare, si silenzia. Notate infatti che Meteolog invia un successivo comando di polling dopo circa un secondo dall'ultima richiesta di interrupt. Questo comportamento permette una tecnica di lettura del buffer di tipo FIFO tramite un loop infinito che si interrompe quando il buffer viene trovato vuoto. La criticità in questo caso è solo evitare di essere troppo “aggressivi” nella lettura del buffer dando quindi alla stazione il giusto tempo (come abbiamo visto almeno 40ms) tra una lettura e l'altra altrimenti il rischio è uscire dal loop anzitempo.