-
Notifications
You must be signed in to change notification settings - Fork 62
/
Copy pathGoodFETMAXUSB.py
1786 lines (1608 loc) · 62.3 KB
/
GoodFETMAXUSB.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#!/usr/bin/env python
# GoodFET Client Library for Maxim USB Chips.
#
# (C) 2012 Travis Goodspeed <travis at radiantmachines.com>
#
# This code is being rewritten and refactored. You've been warned!
#
# Code modified as part of BadUSB 2.0 Project
# by DK 2016 (@withdk)
import sys, time, string, cStringIO, struct, glob, os;
import warnings
from GoodFET import GoodFET;
#Handy registers.
rEP0FIFO=0
rEP1OUTFIFO=1
rEP2INFIFO=2
rEP3INFIFO=3
rSUDFIFO=4
rEP0BC=5
rEP1OUTBC=6
rEP2INBC=7
rEP3INBC=8
rEPSTALLS=9
rCLRTOGS=10
rEPIRQ=11
rEPIEN=12
rUSBIRQ=13
rUSBIEN=14
rUSBCTL=15
rCPUCTL=16
rPINCTL=17
rREVISION=18
rFNADDR=19
rIOPINS=20
rIOPINS1=20 #Same as rIOPINS
rIOPINS2=21
rHIRQ=25
rHIEN=26
rMODE=27
rPERADDR=28
rHCTL=29
rHXFR=30
rHRSL=31
#Host mode registers.
rRCVFIFO =1
rSNDFIFO =2
rRCVBC =6
rSNDBC =7
rHIRQ =25
# R11 EPIRQ register bits
bmSUDAVIRQ =0x20
bmIN3BAVIRQ =0x10
bmIN2BAVIRQ =0x08
bmOUT1DAVIRQ= 0x04
bmOUT0DAVIRQ= 0x02
bmIN0BAVIRQ =0x01
# R12 EPIEN register bits
bmSUDAVIE =0x20
bmIN3BAVIE =0x10
bmIN2BAVIE =0x08
bmOUT1DAVIE =0x04
bmOUT0DAVIE =0x02
bmIN0BAVIE =0x01
# ************************
# Standard USB Requests
SR_GET_STATUS =0x00 # Get Status
SR_CLEAR_FEATURE =0x01 # Clear Feature
SR_RESERVED =0x02 # Reserved
SR_SET_FEATURE =0x03 # Set Feature
SR_SET_ADDRESS =0x05 # Set Address
SR_GET_DESCRIPTOR =0x06 # Get Descriptor
SR_SET_DESCRIPTOR =0x07 # Set Descriptor
SR_GET_CONFIGURATION =0x08 # Get Configuration
SR_SET_CONFIGURATION =0x09 # Set Configuration
SR_GET_INTERFACE =0x0a # Get Interface
SR_SET_INTERFACE =0x0b # Set Interface
# Get Descriptor codes
GD_DEVICE =0x01 # Get device descriptor: Device
GD_CONFIGURATION =0x02 # Get device descriptor: Configuration
GD_STRING =0x03 # Get device descriptor: String
GD_HID =0x21 # Get descriptor: HID
GD_REPORT =0x22 # Get descriptor: Report
HID_REPORT =0x01 # HID Report (Get Report)
# SETUP packet header offsets
bmRequestType =0
bRequest =1
wValueL =2
wValueH =3
wIndexL =4
wIndexH =5
wLengthL =6
wLengthH =7
# HID bRequest values
GET_REPORT =1
GET_IDLE =2
GET_PROTOCOL =3
SET_REPORT =9
SET_IDLE =0x0A
SET_PROTOCOL =0x0B
INPUT_REPORT =1
# PINCTL bits
bmEP3INAK =0x80
bmEP2INAK =0x40
bmEP1INAK =0x20
bmFDUPSPI =0x10
bmINTLEVEL =0x08
bmPOSINT =0x04
bmGPXB =0x02
bmGPXA =0x01
# rUSBCTL bits
bmHOSCSTEN =0x80
bmVBGATE =0x40
bmCHIPRES =0x20
bmPWRDOWN =0x10
bmCONNECT =0x08
bmSIGRWU =0x04
# USBIRQ bits
bmURESDNIRQ =0x80
bmVBUSIRQ =0x40
bmNOVBUSIRQ =0x20
bmSUSPIRQ =0x10
bmURESIRQ =0x08
bmBUSACTIRQ =0x04
bmRWUDNIRQ =0x02
bmOSCOKIRQ =0x01
# MODE bits
bmHOST =0x01
bmLOWSPEED =0x02
bmHUBPRE =0x04
bmSOFKAENAB =0x08
bmSEPIRQ =0x10
bmDELAYISO =0x20
bmDMPULLDN =0x40
bmDPPULLDN =0x80
# PERADDR/HCTL bits
bmBUSRST =0x01
bmFRMRST =0x02
bmSAMPLEBUS =0x04
bmSIGRSM =0x08
bmRCVTOG0 =0x10
bmRCVTOG1 =0x20
bmSNDTOG0 =0x40
bmSNDTOG1 =0x80
# rHXFR bits
# Host XFR token values for writing the HXFR register (R30).
# OR this bit field with the endpoint number in bits 3:0
tokSETUP =0x10 # HS=0, ISO=0, OUTNIN=0, SETUP=1
tokIN =0x00 # HS=0, ISO=0, OUTNIN=0, SETUP=0
tokOUT =0x20 # HS=0, ISO=0, OUTNIN=1, SETUP=0
tokINHS =0x80 # HS=1, ISO=0, OUTNIN=0, SETUP=0
tokOUTHS =0xA0 # HS=1, ISO=0, OUTNIN=1, SETUP=0
tokISOIN =0x40 # HS=0, ISO=1, OUTNIN=0, SETUP=0
tokISOOUT =0x60 # HS=0, ISO=1, OUTNIN=1, SETUP=0
# rRSL bits
bmRCVTOGRD =0x10
bmSNDTOGRD =0x20
bmKSTATUS =0x40
bmJSTATUS =0x80
# Host error result codes, the 4 LSB's in the HRSL register.
hrSUCCESS =0x00
hrBUSY =0x01
hrBADREQ =0x02
hrUNDEF =0x03
hrNAK =0x04
hrSTALL =0x05
hrTOGERR =0x06
hrWRONGPID =0x07
hrBADBC =0x08
hrPIDERR =0x09
hrPKTERR =0x0A
hrCRCERR =0x0B
hrKERR =0x0C
hrJERR =0x0D
hrTIMEOUT =0x0E
hrBABBLE =0x0F
# HIRQ bits
bmBUSEVENTIRQ =0x01 # indicates BUS Reset Done or BUS Resume
bmRWUIRQ =0x02
bmRCVDAVIRQ =0x04
bmSNDBAVIRQ =0x08
bmSUSDNIRQ =0x10
bmCONDETIRQ =0x20
bmFRAMEIRQ =0x40
bmHXFRDNIRQ =0x80
class GoodFETMAXUSB(GoodFET):
MAXUSBAPP=0x40;
CAPSLOCK=2;
SCROLLLOCK=4;
NUMLOCK=1;
usbverbose=False;
ep0_p2hdata=[]; # Data sent from peripheral to host (EP0)
ep0_h2pdata=[]; # Data sent from host to peripheral (EP0)
ep3_p2hdata=[]; # Data sent from peripheral to host (EP3)
ep3_h2pdata=[]; # Data sent from host to peripheral (EP3)
rpipe_complete=0;
int_ready=0;
recdata=[];
recstatus=False;
lastreport=0;
ledpress=0;
ledstarted=0;
exfildata='';
exfiltmp='';
lastled=0;
curled=0;
def service_irqs(self):
"""Handle USB interrupt events."""
epirq=self.rreg(rEPIRQ);
usbirq=self.rreg(rUSBIRQ);
write_h2p_ep0 = "/tmp/write_h2p_ep0"
read_p2h_ep3 = "/tmp/write_p2h_ep3";
# We don't use IRQs as it causes headaches with pipes
#self.m2h();
#self.do_IN3();
#Are we being asked for setup data?
if(epirq&bmSUDAVIRQ): #Setup Data Requested
self.wreg(rEPIRQ,bmSUDAVIRQ); #Clear the bit
#self.do_SETUP();
# DK Note: Function that does setup.
#print("setup now");
self.m2h();
else:
# HACK TODO: Prevent non-blocking of pipes
wd = open(write_h2p_ep0, "w");
no_h2pdatastr="00000000";
#print("writing %d" % len(no_h2pdatastr));
wd.write(no_h2pdatastr); # prevent blocking
wd.flush();
wd.close();
if(epirq&bmOUT1DAVIRQ): #OUT1-OUT packet
#print("OUT now");
#self.do_OUT1();
self.wreg(rEPIRQ,bmOUT1DAVIRQ); #Clear the bit *AFTER* servicing.
if(epirq&bmIN3BAVIRQ): #IN3-IN packet
self.wreg(rEPIRQ,bmIN3BAVIRQ); #Clear the bit
# DK Note: Function that performs INTs (typing)
#print("IN3 now");
self.do_IN3();
else:
# Prevent blocking of pipes
self.do_IN3();
if(epirq&bmIN2BAVIRQ): #IN2 packet
self.do_IN2();
#self.wreg(rEPIRQ,bmIN2BAVIRQ); #Clear the bit
#else:
# print "No idea how to service this IRQ: %02x" % epirq;
def do_IN2(self):
"""Overload this."""
#print("We got an event on EP2");
#def do_IN3(self):
"""Overload this."""
#self.type_IN3();
#some_var=self.readbytes(rEP3INBC,8);
#if(len(some_var)>6):
#print("We got an event on EP3");
def do_OUT1(self):
"""Overload this."""
if self.usbverbose: print "Ignoring an OUT1 interrupt.";
def setup2str(self,SUD):
"""Converts the header of a setup packet to a string."""
return "bmRequestType=0x%02x, bRequest=0x%02x, wValue=0x%04x, wIndex=0x%04x, wLength=0x%04x" % (
ord(SUD[0]), ord(SUD[1]),
ord(SUD[2])+(ord(SUD[3])<<8),
ord(SUD[4])+(ord(SUD[5])<<8),
ord(SUD[6])+(ord(SUD[7])<<8)
);
def MAXUSBsetup(self):
"""Move the FET into the MAXUSB application."""
self.writecmd(self.MAXUSBAPP,0x10,0,self.data); #MAXUSB/SETUP
self.writecmd(self.MAXUSBAPP,0x10,0,self.data); #MAXUSB/SETUP
self.writecmd(self.MAXUSBAPP,0x10,0,self.data); #MAXUSB/SETUP
print "Connected to MAX342x Rev. %x" % (self.rreg(rREVISION));
self.wreg(rPINCTL,0x18); #Set duplex and negative INT level.
def MAXUSBtrans8(self,byte):
"""Read and write 8 bits by MAXUSB."""
data=self.MAXUSBtrans([byte]);
return ord(data[0]);
def MAXUSBtrans(self,data):
"""Exchange data by MAXUSB."""
self.data=data;
self.writecmd(self.MAXUSBAPP,0x00,len(data),data);
return self.data;
def rreg(self,reg):
"""Peek 8 bits from a register."""
data=[reg<<3,0];
self.writecmd(self.MAXUSBAPP,0x00,len(data),data);
return ord(self.data[1]);
def rregAS(self,reg):
"""Peek 8 bits from a register, setting AS."""
data=[(reg<<3)|1,0];
self.writecmd(self.MAXUSBAPP,0x00,len(data),data);
return ord(self.data[1]);
def wreg(self,reg,value):
"""Poke 8 bits into a register."""
data=[(reg<<3)|2,value];
self.writecmd(self.MAXUSBAPP,0x00,len(data),data);
return value;
def wregAS(self,reg,value):
"""Poke 8 bits into a register, setting AS."""
data=[(reg<<3)|3,value];
self.writecmd(self.MAXUSBAPP,0x00,len(data),data);
return value;
def readbytes(self,reg,length):
"""Peek some bytes from a register."""
data=[(reg<<3)]+range(0,length);
self.writecmd(self.MAXUSBAPP,0x00,len(data),data);
toret=self.data[1:len(self.data)];
ashex="";
for foo in toret:
ashex=ashex+(" %02x"%ord(foo));
if self.usbverbose: print "GET %02x==%s" % (reg,ashex);
return toret;
def readbytesAS(self,reg,length):
"""Peek some bytes from a register, acking prior transfer."""
data=[(reg<<3)|1]+range(0,length);
self.writecmd(self.MAXUSBAPP,0x00,len(data),data);
toret=self.data[1:len(self.data)];
ashex="";
for foo in toret:
ashex=ashex+(" %02x"%ord(foo));
if self.usbverbose: print "GETAS %02x==%s" % (reg,ashex);
return toret;
def fifo_ep3in_tx(self,data):
"""Sends the data out of EP3 in 64-byte chunks."""
#Wait for the buffer to be free before starting.
while not(self.rreg(rEPIRQ)&bmIN3BAVIRQ): pass;
count=len(data);
pos=0;
while count>0:
#Send 64-byte chunks or the remainder.
c=min(count,64);
self.writebytes(rEP3INFIFO,
data[pos:pos+c]);
self.wregAS(rEP3INBC,c);
count=count-c;
pos=pos+c;
#Wait for the buffer to be free before continuing.
while not(self.rreg(rEPIRQ)&bmIN3BAVIRQ): pass;
return;
def ctl_write_nd(self,request):
"""Control Write with no data stage. Assumes PERADDR is set
and the SUDFIFO contains the 8 setup bytes. Returns with
result code = HRSLT[3:0] (HRSL register). If there is an
error, the 4MSBits of the returned value indicate the stage 1
or 2."""
# 1. Send the SETUP token and 8 setup bytes.
# Should ACK immediately.
self.writebytes(rSUDFIFO,request);
resultcode=self.send_packet(tokSETUP,0); #SETUP packet to EP0.
if resultcode: return resultcode;
# 2. No data stage, so the last operation is to send an IN
# token to the peripheral as the STATUS (handhsake) stage of
# this control transfer. We should get NAK or the DATA1 PID.
# When we get back to the DATA1 PID the 3421 automatically
# sends the closing NAK.
resultcode=self.send_packet(tokINHS,0); #Function takes care of retries.
if resultcode: return resultcode;
return 0;
def ctl_read_ep0(self, request):
"""Control read transfer, used in Host mode."""
resultcode=0;
if(len(request)==8):
bytes_to_read=request[6]+256*request[7];
else:
print("Unhandled in ctl_read");
bytes_to_read=0;
#bytes_to_read=request[6]+256*request[7]
##SETUP packet
self.writebytes(rSUDFIFO,request); #Load the FIFO
resultcode=self.send_packet(tokSETUP,0); #SETUP packet to EP0
if resultcode:
print "Failed to get ACK on SETUP request in ctl_read()."
return resultcode;
self.wreg(rHCTL,bmRCVTOG1); #FIRST data packet in CTL transfer uses DATA1 toggle.
resultcode=self.IN_Transfer(0,bytes_to_read);
if resultcode:
print "Failed on IN Transfer in ctl_read()";
return resultcode;
self.IN_nak_count=self.nak_count;
#The OUT status stage.
resultcode=self.send_packet(0x00,0);
if resultcode:
print "Failed on OUT Status stage in ctl_read()";
return resultcode;
return 0; #Success
#The OUT status stage.
resultcode=self.send_packet(0x00,0);
if resultcode:
print "Failed on OUT Status stage in ctl_read()";
return resultcode;
return 0; #Success
def ctl_read(self,request):
"""Control read transfer, used in Host mode."""
resultcode=0;
if(len(request)==8):
bytes_to_read=request[6]+256*request[7];
else:
print("Unhandled in ctl_read");
bytes_to_read=0;
#bytes_to_read=request[6]+256*request[7];
##SETUP packet
self.writebytes(rSUDFIFO,request); #Load the FIFO
resultcode=self.send_packet(tokSETUP,0); #SETUP packet to EP0
if resultcode:
print "Failed to get ACK on SETUP request in ctl_read()."
return resultcode;
self.wreg(rHCTL,bmRCVTOG1); #FIRST data packet in CTL transfer uses DATA1 toggle.
resultcode=self.IN_Transfer(0,bytes_to_read);
if resultcode:
print "Failed on IN Transfer in ctl_read()";
return resultcode;
self.IN_nak_count=self.nak_count;
#The OUT status stage.
resultcode=self.send_packet(tokOUTHS,0);
if resultcode:
print "Failed on OUT Status stage in ctl_read()";
return resultcode;
return 0; #Success
# endpoint will be the requested one, in this case 2 by kingston
def OUT_Transfer(self,endpoint,data):
# check length, etc
count = len(data)
pos = 0
while count > 0:
while not (self.rreg(rHIRQ) & bmSNDBAVIRQ):
print("waiting for SND buffer")
# wait for SND irq to be ready
pass
c = min(count,64)
self.writebytes(rSNDFIFO,data[pos:pos+c]); #Load the FIFO
self.writebytes(rSNDBC, [c])
count = count - c
print("Hitting tokOUT to endpoint %d" % endpoint) # TODO add verbose
#resultcode = self.send_packet(tokOUT,endpoint) # will take care of NAKs and retries
resultcode = self.send_packet(tokOUT,endpoint) # will take care of NAKs and retries
if resultcode: print("Error in OUT transfer: %d" % resultcode)
RETRY_LIMIT=1; #normally 3
NAK_LIMIT=1; #normally 300
def IN_Transfer_Int(self,endpoint,INbytes):
"""Does an IN transfer to an endpoint, used for Host mode."""
xfrsize=INbytes;
xfrlen=0;
self.ep3_p2hdata=[];
while 1:
resultcode=self.send_packet(tokIN,endpoint); #IN packet to EP. NAKS taken care of.
if resultcode: return resultcode;
pktsize=self.rreg(rRCVBC); #Numer of RXed bytes.
#Very innefficient, move this to C if performance is needed.
for j in range(0,pktsize):
self.ep3_p2hdata=self.ep3_p2hdata+[self.rreg(rRCVFIFO)];
#xfrsize=self.p2hdata[0];
self.wreg(rHIRQ,bmRCVDAVIRQ); #Clear IRQ
xfrlen=xfrlen+pktsize; #Add byte count to total transfer length.
#print "%i / %i" % (xfrlen,xfrsize)
#print("getting here %d" % xfrlen)
#Packet is complete if:
# 1. The device sent a short packet, <maxPacketSize
# 2. INbytes have been transfered.
if (pktsize<self.maxPacketSize) or (xfrlen>=xfrsize):
self.last_transfer_size=xfrlen;
ashex="";
for foo in self.ep3_p2hdata:
ashex=ashex+(" %02x"%foo);
#print "INPACKET EP%i==%s (0x%02x bytes remain)" % (endpoint,ashex,xfrsize);
return resultcode;
RETRY_LIMIT=3;
NAK_LIMIT=300;
def IN_Transfer(self,endpoint,INbytes):
"""Does an IN transfer to an endpoint, used for Host mode."""
xfrsize=INbytes;
xfrlen=0;
self.ep0_p2hdata=[];
while 1:
resultcode=self.send_packet(tokIN,endpoint); #IN packet to EP. NAKS taken care of.
if resultcode: return resultcode;
pktsize=self.rreg(rRCVBC); #Numer of RXed bytes.
#Very innefficient, move this to C if performance is needed.
for j in range(0,pktsize):
self.ep0_p2hdata=self.ep0_p2hdata+[self.rreg(rRCVFIFO)];
#xfrsize=self.p2hdata[0];
self.wreg(rHIRQ,bmRCVDAVIRQ); #Clear IRQ
xfrlen=xfrlen+pktsize; #Add byte count to total transfer length.
#print "%i / %i" % (xfrlen,xfrsize)
#print("getting here %d" % xfrlen)
#Packet is complete if:
# 1. The device sent a short packet, <maxPacketSize
# 2. INbytes have been transfered.
if (pktsize<self.maxPacketSize) or (xfrlen>=xfrsize):
self.last_transfer_size=xfrlen;
ashex="";
for foo in self.ep0_p2hdata:
ashex=ashex+(" %02x"%foo);
#print "INPACKET EP%i==%s (0x%02x bytes remain)" % (endpoint,ashex,xfrsize);
return resultcode;
RETRY_LIMIT=3;
NAK_LIMIT=300;
def send_packet(self,token,endpoint):
"""Send a packet to an endpoint as the Host, taking care of NAKs.
Don't use this for device code."""
self.retry_count=0;
self.nak_count=0;
#Repeat until NAK_LIMIT or RETRY_LIMIT is reached.
while self.nak_count<self.NAK_LIMIT and self.retry_count<self.RETRY_LIMIT:
self.wreg(rHXFR,(token|endpoint)); #launch the transfer
while not (self.rreg(rHIRQ) & bmHXFRDNIRQ):
# wait for the completion IRQ
pass;
self.wreg(rHIRQ,bmHXFRDNIRQ); #Clear IRQ
resultcode = (self.rreg(rHRSL) & 0x0F); # get the result
if (resultcode==hrNAK):
self.nak_count=self.nak_count+1;
elif (resultcode==hrTIMEOUT):
self.retry_count=self.retry_count+1;
else:
#Success!
return resultcode;
return resultcode;
def writebytes(self,reg,tosend):
"""Poke some bytes into a register."""
data="";
if type(tosend)==str:
data=chr((reg<<3)|3)+tosend;
if self.usbverbose: print "PUT %02x:=%s (0x%02x bytes)" % (reg,tosend,len(data))
else:
data=[(reg<<3)|3]+tosend;
ashex="";
for foo in tosend:
ashex=ashex+(" %02x"%foo);
if self.usbverbose: print "PUT %02x:=%s (0x%02x bytes)" % (reg,ashex,len(data))
self.writecmd(self.MAXUSBAPP,0x00,len(data),data);
def usb_connect(self):
"""Connect the USB port."""
#disconnect D+ pullup if host turns off VBUS
self.wreg(rUSBCTL,bmVBGATE|bmCONNECT);
def usb_disconnect(self):
"""Disconnect the USB port."""
self.wreg(rUSBCTL,bmVBGATE);
def STALL_EP0(self,SUD=None):
"""Stall for an unknown SETUP event."""
if SUD==None:
print "Stalling EP0.";
else:
print "Stalling EPO for %s" % self.setup2str(SUD);
# No lets ignore this!! :)
# self.wreg(rEPSTALLS,0x23); #All three stall bits.
def SETBIT(self,reg,val):
"""Set a bit in a register."""
self.wreg(reg,self.rreg(reg)|val);
def vbus_on(self):
"""Turn on the target device."""
self.wreg(rIOPINS2,(self.rreg(rIOPINS2)|0x08));
def vbus_off(self):
"""Turn off the target device's power."""
self.wreg(rIOPINS2,0x00);
def reset_host(self):
"""Resets the chip into host mode."""
self.wreg(rUSBCTL,bmCHIPRES); #Stop the oscillator.
self.wreg(rUSBCTL,0x00); #restart it.
#FIXME: Why does the OSC line never settle?
#Code works without it.
#print "Waiting for PLL to sabilize.";
#while self.rreg(rUSBIRQ)&bmOSCOKIRQ:
# #Hang until the PLL stabilizes.
# pass;
#print "Stable.";
class GoodFETMAXUSBHost(GoodFETMAXUSB):
"""This is a class for implemented a minimal USB host.
It's intended for fuzzing, rather than for daily use."""
#
# Return request type after using h2p_host_request_type() function.
#
h2p_msg_types={
-1:"Error, Invalid Length",
0:"No Match",
1:"Get Descriptor Device",
2:"Get Descriptor Configuration",
3:"Get Descriptor String",
4:"Get Descriptor Device Qualifier",
5:"Get Status",
6:"Get Descriptor RPIPE",
7:"Get Report",
8:"Set Address",
9:"Set Configuration Address",
10:"Set Feature (Port Reset)",
11:"Clear Feature (Port Reset)",
12:"Set Idle",
13:"Set Report",
}
def hostinit(self):
"""Initialize the MAX3421 as a USB Host."""
self.usb_connect();
print "Enabling host mode.";
self.wreg(rPINCTL,(bmFDUPSPI|bmPOSINT));
print "Resetting host.";
self.reset_host();
self.vbus_off();
time.sleep(0.2);
print "Powering host.";
self.vbus_on();
#self.hostrun();
def hostrun(self):
"""Run as a minimal host and dump the config tables."""
while True:
self.detect_device();
time.sleep(0.2);
self.m2p();
self.wait_for_disconnect();
def detect_device(self):
"""Waits for a device to be inserted and then returns."""
busstate=0;
#Activate host mode and turn on 15K pulldown resistors on D+ and D-.
self.wreg(rMODE,(bmDPPULLDN|bmDMPULLDN|bmHOST));
#Clear connection detect IRQ.
self.wreg(rHIRQ,bmCONDETIRQ);
print "Waiting for a device connection.";
while busstate==0:
self.wreg(rHCTL,bmSAMPLEBUS); #Update JSTATUS and KSTATUS bits.
busstate=self.rreg(rHRSL) & (bmJSTATUS|bmKSTATUS);
if busstate==bmJSTATUS:
print "Detected Full-Speed Device.";
self.wreg(rMODE,(bmDPPULLDN|bmDMPULLDN|bmHOST|bmSOFKAENAB));
elif busstate==bmKSTATUS:
print "Detected Low-Speed Device.";
self.wreg(rMODE,(bmDPPULLDN|bmDMPULLDN|bmHOST|bmLOWSPEED|bmSOFKAENAB));
else:
print "Not sure whether this is Full-Speed or Low-Speed. Please investigate.";
def wait_for_disconnect(self):
"""Wait for a device to be disconnected."""
print "Waiting for a device disconnect.";
self.wreg(rHIRQ,bmCONDETIRQ); #Clear disconnect IRQ
while not (self.rreg(rHIRQ) & bmCONDETIRQ):
#Wait for IRQ to change.
pass;
#Turn off markers.
self.wreg(rMODE,bmDPPULLDN|bmDMPULLDN|bmHOST);
print "Device disconnected.";
self.wreg(rIOPINS2,(self.rreg(rIOPINS2) & ~0x04)); #HL1_OFF
self.wreg(rIOPINS1,(self.rreg(rIOPINS1) & ~0x02)); #HL4_OFF
#
# These values were taken from a Wireshark packet capture
#
def h2p_host_request_type(self, msg):
"""Return the type of usb request sent from the host to the peripheral."""
msg_type=0
#print(msg)
# Get Descriptor Device
if(msg[0]==0x80 and msg[3]==0x01):
msg_type=1
# Get Descriptor Configuration
if(msg[0]==0x80 and msg[3]==0x02):
msg_type=2
# Get Descriptor String
if(msg[0]==0x80 and msg[3]==0x03):
msg_type=3
# Get Descriptor Device Qualifier
if(msg[0]==0x80 and msg[3]==0x06):
msg_type=4
# Get Status
if(msg[0]==0xa3 and msg[1]==0x00):
msg_type=5
# Get Descriptor RPIPE
if(msg[0]==0x81 and msg[3]==0x22):
msg_type=6
# Get Report
if(msg[0]==0xa1 and msg[1]==0x01):
msg_type=7
# Set Address
if(msg[0]==0x00 and msg[1]==0x05):
msg_type=8
# Set Configuration Address
if(msg[0]==0x00 and msg[1]==0x09):
msg_type=9
# Set Feature (Port Reset)
if(msg[0]==0x23 and msg[1]==0x03):
msg_type=10
# Clear Feature (Port Reset)
if(msg[0]==0x23 and msg[1]==0x01):
msg_type=11
# Set Idle
if(msg[0]==0x21 and msg[1]==0x0a):
msg_type=12
# Set Report
if(msg[0]==0x21 and msg[1]==0x09):
msg_type=13
return(msg_type)
def m2p(self):
"""Enumerates a device on the present port."""
read_h2p_ep0 = "/tmp/write_h2p_ep0"
write_p2h_ep0 = "/tmp/write_p2h_ep0"
gd_counter=0;
while True:
#Get data from host to send to peripheral
#rd = open(read_h2p_ep0, "r");
#self.h2pdata=rd.readline();
#rd.close();
self.p2hdata=[];
self.ep0_h2pdata=[];
rd = open(read_h2p_ep0, "r");
self.ep0_h2pdata=rd.read(8);
rd.flush();
rd.close();
# DK get the message type
msg_type=0;
if(len(self.ep0_h2pdata)>2):
msg_data=self.ep0_h2pdata;
msg_data=[ord(self.ep0_h2pdata[0]), ord(self.ep0_h2pdata[1]), ord(self.ep0_h2pdata[2]), ord(self.ep0_h2pdata[3])]
msg_type=self.h2p_host_request_type(msg_data);
#if(msg_type!="No Match"): # HACK for less debug info
print("H2P Message Type: %s" % self.h2p_msg_types[msg_type]);
msg_to_str=', '.join(str(ord(c)) for c in self.ep0_h2pdata)
# Uncomment for debugging
if(msg_to_str!="48, 48, 48, 48, 48, 48, 48, 48"): # HACK for less debug info.
print("H2P: %s" % msg_to_str);
# DK If a setup packet we reset the bus
if(msg_type==0): # No match
self.m2p_int();
#wd = open(write_p2h_ep0, "w");
#wd.write(str(list(self.p2hdata))+'\n');
#wd.write('');
#wd.flush();
#wd.close();
continue;
if(msg_type==1): # Get_Descriptor
if gd_counter==0:
print "Issuing USB bus reset.";
self.wreg(rHCTL,bmBUSRST);
while self.rreg(rHCTL) & bmBUSRST:
#Wait for reset to complete.
pass;
time.sleep(0.2);
self.wreg(rPERADDR,0); #First request to address 0.
self.maxPacketSize=8; #Only safe value for first check.
print "Fetching 8 bytes of Device Descriptor.";
self.ctl_read(self.ep0_h2pdata); # Get device descriptor into self.p2hdata
#print "EP0 maxPacketSize is %02i bytes." % self.maxPacketSize;
# Send p2hdata to host
# uncomment for debugging
# print("P2H: %s" % self.ep0_p2hdata);
wd = open(write_p2h_ep0, "w");
wd.write(str(list(self.ep0_p2hdata))+'\n');
wd.close();
#req_type=self.h2p_host_request_type(self.ep0_p2hdata);
# Issue another USB bus reset
if gd_counter==0:
print "Resetting the bus again."
self.wreg(rHCTL,bmBUSRST);
while self.rreg(rHCTL) & bmBUSRST:
#Wait for reset to complete.
pass;
time.sleep(0.2);
if gd_counter==1:
self.descriptor=self.ep0_p2hdata;
self.VID = self.ep0_p2hdata[8] + 256*self.ep0_p2hdata[9];
self.PID = self.ep0_p2hdata[10]+ 256*self.ep0_p2hdata[11];
iMFG = self.ep0_p2hdata[14];
iPROD = self.ep0_p2hdata[15];
iSERIAL = self.ep0_p2hdata[16];
self.manufacturer=self.getDescriptorString(iMFG);
self.product=self.getDescriptorString(iPROD);
self.serial=self.getDescriptorString(iSERIAL);
self.printstrings();
gd_counter=gd_counter+1;
elif(msg_type==8): # Set Address
#HR = self.ctl_write_nd(Set_Address_to_13); # CTL-Write, no data stage
HR=self.ctl_write_nd(self.ep0_h2pdata);
time.sleep(0.002); # Device gets 2 msec recovery time
print(ord(self.ep0_h2pdata[2]));
self.wreg(rPERADDR,ord(self.ep0_h2pdata[2])); # now all transfers go to addr 7
wd = open(write_p2h_ep0, "w");
#wd.write(str(list(self.p2hdata))+'\n');
wd.write('');
wd.close();
#req_type=self.h2p_host_request_type(self.ep0_p2hdata);
elif(msg_type==9 or msg_type==12): # Set Configuration && Set Address
#self.ctl_read(self.h2pdata); # Get device descriptor into self.p2hdata
HR = self.ctl_write_nd(self.ep0_h2pdata);
time.sleep(0.002); # Device gets 2 msec recovery time
# Send p2hdata to host
self.ep0_p2hdata=[];
print("P2H: %s" % self.ep0_p2hdata);
wd = open(write_p2h_ep0, "w");
wd.write('');
wd.close();
if(msg_type==9):
print("Device now CONFIGURED");
#while True:
#self.IN_Transfer_Int(1,8);
#print("Got INT data: %s" % self.intdata);
# Send EP0 Complete Message
#wd = open(write_p2h_ep0, "w"); # Need a new endpoint.
#wd.write(1337 + '\n');
#wd.close();
#while True:
#self.service_irqs();
#print("Sending numlock test");
#numlock_int=[0x00,0x00,0x53,0x00,0x00,0x00,0x00,0x00];
#self.ctl_read(numlock_int);
#numlock_set_report=[0x21,0x09,0x00,0x02,0x00,0x00,0x01,0x00]
#HR=self.ctl_write_nd(numlock_set_report);
#print(HR);
elif(msg_type==13): # Set Report
# Only do this once till we figure it OUT, means no LEDs on keyboard, even though it activates.
# DK: Disabled as it would stall EP0 TODO
# We also need it working so we can transfer OUT data.
# HR=self.ctl_write_nd(self.ep0_h2pdata);
wd = open(write_p2h_ep0, "w");
wd.write('');
wd.flush();
wd.close();
#req_type=self.h2p_host_request_type(self.ep0_p2hdata);
#time.sleep(0.002); # Device gets 2 msec recovery time
elif(msg_type==6): # RPIPE
self.ctl_read(self.ep0_h2pdata); # Get device descriptor into self.p2hdata
#time.sleep(0.002); # Device gets 2 msec recovery time
# Send p2hdata to host
print("P2H: %s" % self.ep0_p2hdata);
wd = open(write_p2h_ep0, "w");
if(len(self.ep0_p2hdata)>0):
wd.write(str(list(self.ep0_p2hdata))+'\n');
else:
wd.write('');
wd.flush();
wd.close();
elif(msg_type==7): # Get Report
self.ctl_read(self.ep0_h2pdata);
print("P2H: %s" % self.ep0_p2hdata);
wd = open(write_p2h_ep0, "w");
if(len(self.ep0_p2hdata)>0):
wd.write(str(list(self.ep0_p2hdata))+'\n');
else:
wd.write('');
wd.flush();
wd.close();
else: #For everything else
self.ctl_read(self.ep0_h2pdata); # Get device descriptor into self.p2hdata
#time.sleep(0.002); # Device gets 2 msec recovery time
# Send p2hdata to host
print("P2H: %s" % self.ep0_p2hdata);
wd = open(write_p2h_ep0, "w");
if(len(self.ep0_p2hdata)>0):
wd.write(str(list(self.ep0_p2hdata))+'\n');
else:
wd.write('');
wd.flush();
wd.close();
self.m2p_int();
#return(p2h_resp_data)
def m2p_int(self):
''' Fetches data from real peripheral interrupt '''
self.ep3_p2hdata='';
self.IN_Transfer_Int(1,8); # DK: HACK TODO set speed automatically or via argument.
write_p2h_ep3 = "/tmp/write_p2h_ep3"
wd = open(write_p2h_ep3, "w");
if(len(self.ep3_p2hdata)>0):
print("Got some INT data sending %s" % self.ep3_p2hdata);
wd.write(str(list(self.ep3_p2hdata))+'\n');
else:
wd.write('');
wd.flush();
wd.close();
def printstrings(self):
print "Vendor ID is %04x." % self.VID;
print "Product ID is %04x." % self.PID;
print "Manufacturer: %s" % self.manufacturer;
print "Product: %s" % self.product;
print "Serial: %s" % self.serial;
def getDescriptorString(self, index):
"""Grabs a string from the descriptor string table."""
# Get_Descriptor-String template. Code fills in idx at str[2].
Get_Descriptor_String = [0x80,0x06,index,0x03,0x00,0x00,0x40,0x00];
if index==0: return "MISSING STRING";
status=self.ctl_read(Get_Descriptor_String);
if status: return None;
#Since we've got a string
toret="";
for c in self.ep0_p2hdata[2:len(self.ep0_p2hdata)]:
if c>0: toret=toret+chr(c);
return toret;
class GoodFETMAXUSBDevice(GoodFETMAXUSB):
def hijack_ep(self, rcv):
'''
Take the descriptor, and modify the endpoints
Taken from Von Tonder's TTWE code, however, it's hardcoded it doesn't work, TODO.
'''
self.verbose=True;
rest = rcv[rcv[0]:] # start at interface
if len(rest) > 0: #there's more
rest = rest[rest[0]:] # trim interface, start at endpoint a
endpoint_a = rest[:rest[0]] # save endpoint a
rest = rest[rest[0]:] # set start to endpoint b
offset_a = 0x9 + 0x9 + 0x3 - 1
endpoint_a_address = endpoint_a[2]