-
Notifications
You must be signed in to change notification settings - Fork 2
/
flashimage.py
325 lines (243 loc) · 9.19 KB
/
flashimage.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
#!/usr/bin/env python
# may 2009 (c) avd <[email protected]>
"""
flashimage for nb4
Easily flash an nb4 with an full image of 8MB
and a network connection.
Usage:
./flashimage.py <network interface> <full image>
The nb4 need to be in download mode (press service button
approximately 5 seconds when box booting until it is
blinking blue).
This program uses the download mode of the CFE soft
for the NB4 box. This program send request for flashing
all the flash AFTER the CFE part.
Obviously, you can use it without risking to destroy your
nb4 box because there will be the CFE to recover.
this program remove all the things after CFE. Think to save your config before use it.
This program expect a full image of 8MB (CFE + MAIN + JFFS2 + RESCUE + DSL + NV) but the CFE soft on the nb4 in download mode and without EALL request jump the first 64KB of the image (CFE part) thus does not write the CFE part on the flash.
So, if you don't have the CFE part and you want build a full image, you can remplace the 64KB of the beginning of the full image by any data.
"""
import sys
import string
import struct
import socket
import time
import os
# defs
ETH_ADDR_BROADCAST = '\xff\xff\xff\xff\xff\xff'
CMD_VERSION = 0x0000
CMD_REQUEST = 0x0001
CMD_DATA = 0x0002
CMD_RESET = 0x0003
CMD_VERIFY = 0x0004
# based on http://dev.efixo.net/browser/trunk/openwrt/target/linux/brcm63xx/files-2.6.21/include/asm-mips/mach-bcm63xx/nb4/box/partition.h
# mapping for 2.x (not used for now)
NB_CFE_OFFSET = 0x0
NB_CFE_SIZE = 65536
NB_MAIN_OFFSET = NB_CFE_OFFSET + NB_CFE_SIZE
NB_MAIN_SIZE = 5570560
NB_JFFS2_OFFSET = NB_MAIN_OFFSET + NB_MAIN_SIZE
NB_JFFS2_SIZE = 655360
NB_RESCUE_OFFSET = NB_JFFS2_OFFSET + NB_JFFS2_SIZE
NB_RESCUE_SIZE = 1572864
NB_DSL_OFFSET = NB_RESCUE_OFFSET + NB_RESCUE_SIZE
NB_DSL_SIZE = 458752
NB_NV_OFFSET = NB_DSL_OFFSET + NB_DSL_SIZE
NB_NV_SIZE = 65535
NB_TOTAL_SIZE = 8388608
counter_wsequence = 0x2300
class Dlcpkt:
'''dlc packet - stock values in network order'''
dstaddr = None
srcaddr = None
sap = None
wcmd = None
wsequence = None
woffset = None
wsegment = None
wlen = None
bdata = None
hdr_len = 24
data_len = 24
def __init__(self):
self.bzero()
def __str__(self):
return self.dstaddr + self.srcaddr + self.sap + self.wcmd + self.wsequence + self.woffset + self.wsegment + self.wlen + self.bdata
def bzero(self):
self.dstaddr = '\x00\x00\x00\x00\x00\x00'
self.srcaddr = '\x00\x00\x00\x00\x00\x00'
self.sap = '\x88\x88'
self.wcmd = '\x00\x00'
self.wsequence = '\x00\x00'
self.woffset = '\x00\x00'
self.wsegment = '\x00\x00'
self.wlen = '\x00\x00'
self.bdata = '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
def pack(self):
return self.str()
def unpack(self, data):
self.dstaddr = data[:6]
self.srcaddr = data[6:12]
self.sap = data[12:14]
self.wcmd = data[14:16]
self.wsequence = data[16:18]
self.woffset = data[18:20]
self.wsegment = data[20:22]
self.wlen = data[22:24]
self.bdata = data[24:]
def eth_ntoa(raw):
# Convert binary data into a string.
return ":".join(["%02X" % (ord(ch),) for ch in raw])
def eth_aton(buffer):
addr =''
temp = string.split(buffer,':')
buffer = string.join(temp,'')
# Split up the hex values and pack.
for i in range(0, len(buffer), 2):
addr = ''.join([addr,struct.pack('>B', int(buffer[i: i + 2], 16))],)
return addr
def i16ton(i16):
''' Convert 16 bit integer to network '''
raw = struct.pack('H', i16)
return raw
def hex2dec(hex):
return int(hex, 16)
def dec2hex(dec):
return "%X" % n
def request(s, dlcpkt):
s.send(str(dlcpkt))
resp = s.recv(48);
return resp
def send_file(s, dlcpkt_w, file):
global counter_wsequence
progress_list = [ '|', '/', '-', '\\' ]
progress_index = 0
wsegment_h = 0x0000
woffset_h = 0x0000
counter = 1
dlcpkt_r = Dlcpkt()
dlcpkt_w.wcmd = i16ton(CMD_DATA)
buf_len = 0x0200
filesize = os.path.getsize(file)
f = open(file, "r")
print ' > send %s (size=%d)' % (file, filesize)
print ' (please wait while the box erasing the flash from 0x00010000 to 0x007fffff before flashing ...)'
block = f.read(buf_len)
while block != '':
dlcpkt_w.bdata = block
dlcpkt_w.wsequence = i16ton(counter_wsequence)
dlcpkt_w.wlen = i16ton(len(block))
dlcpkt_w.wsegment = i16ton(wsegment_h)
dlcpkt_w.woffset = i16ton(woffset_h)
s.send(str(dlcpkt_w))
# check
resp = s.recv(48);
dlcpkt_r.unpack(resp)
if dlcpkt_r.wsequence != dlcpkt_w.wsequence:
print 'FAILED.'
break
else:
sys.stdout.write('\r' + progress_list[progress_index] + " %02.f%%" % ( ((counter * len(block)) / (filesize * 1.0)) * 100 ))
sys.stdout.flush()
progress_index = (progress_index + 1) % len(progress_list)
### INCR ###
# final address = segment<<4 + offset
wsegment_h = (wsegment_h + (len(block)/0x10)) % (0x10000)
woffset_h = (wsegment_h & 0x000f)
counter_wsequence = (counter_wsequence + 1) % (0x10000)
counter = counter + 1
# new read
block = f.read(buf_len)
# don't be too speedy
time.sleep(0.002)
print ' '
f.close()
###### MAIN ######
if len(sys.argv) < 3:
print 'Usage: %s <network interface> <full image>' % (sys.argv[0])
sys.exit(0)
# stock args
dev = sys.argv[1]
firm = sys.argv[2]
# check firmware first
try:
firmsize = os.path.getsize(firm)
except Exception, e:
sys.stderr.write("%s\n" % (str(e)));
sys.exit(1)
if firmsize > NB_TOTAL_SIZE:
sys.stderr.write("Error, The size of the firmware should not exceed %d bytes otherwise the CFE might be compromised (%s - %d bytes)\n" % (NB_TOTAL_SIZE, firm, firmsize));
sys.exit(1)
if firmsize != NB_TOTAL_SIZE:
print 'This program expects a full image of %d bytes (CFE + MAIN + JFFS2 + RESCUE + DSL + NV)' % (NB_TOTAL_SIZE,)
print 'Your image has a size of %d bytes' % (firmsize)
ch = raw_input('Continue anyway ? (if you do not know what you do, do not continue !) (y|N) ')
if ch != 'y':
sys.exit(0)
print '+++++++++++++++++++++++++++++++++++++++++++++++'
print ' Image: %s' % (firm)
print ' > Size: %d bytes' % (firmsize,)
print '+++++++++++++++++++++++++++++++++++++++++++++++'
# open socket RAW
try:
s = socket.socket(socket.PF_PACKET, socket.SOCK_RAW)
except Exception, e:
sys.stderr.write("Error while creating socket: %s\n" % str(e))
sys.exit(1)
# bind on device
s.bind((dev,0x8888))
# get the mac addr
my_eth_addr_r = s.getsockname()[-1]
print "%s ethernet address: %s" % (dev, eth_ntoa(my_eth_addr_r))
# write and read packet
dlcpkt_w = Dlcpkt()
dlcpkt_r = Dlcpkt()
# first send discover to get MAC ADDR
# and VERSION_INFO of the box
print " > Info request on broadcast"
dlcpkt_w.dstaddr = ETH_ADDR_BROADCAST
dlcpkt_w.srcaddr = my_eth_addr_r
dlcpkt_w.wcmd = i16ton(CMD_VERSION)
resp = request(s, dlcpkt_w)
dlcpkt_r.unpack(resp)
print " < Receive response from %s - %s" % (eth_ntoa(dlcpkt_r.srcaddr), dlcpkt_r.bdata[4:])
box_eth_addr_r = dlcpkt_r.srcaddr
ch = raw_input('Continue ? (y|N) ')
if ch != 'y':
print "Ok, exit !"
s.close()
sys.exit(0)
# ask we want to put a firmware
print " > Flash request to %s" % (eth_ntoa(box_eth_addr_r))
dlcpkt_w.dstaddr = box_eth_addr_r
dlcpkt_w.wcmd = i16ton(CMD_REQUEST)
dlcpkt_w.wsequence = i16ton(counter_wsequence)
resp = request(s, dlcpkt_w)
dlcpkt_r.unpack(resp)
if dlcpkt_r.wcmd == i16ton(CMD_REQUEST) \
and dlcpkt_r.wsequence == dlcpkt_w.wsequence :
print " < Ok, box wait flashing"
else:
print " < Error on flash request ..."
s.close()
sys.exit(0)
counter_wsequence = (counter_wsequence + 1) % (0x10000)
# send the firmware
send_file(s, dlcpkt_w, firm);
dlcpkt_w.bzero()
dlcpkt_w.dstaddr = box_eth_addr_r
dlcpkt_w.srcaddr = my_eth_addr_r
# verify ?
# reboot the box ?
ch = raw_input('Press Enter to reboot the box')
print " > Send reboot request"
dlcpkt_w.wcmd = i16ton(CMD_RESET)
resp = request(s, dlcpkt_w);
dlcpkt_r.unpack(resp)
if dlcpkt_r.wcmd == i16ton(CMD_RESET):
print " < Ok, rebooting the box"
else:
print " > Error on rebooting command"
print "End."
s.close()