blob: fdd4562374fe443fd5b5b449c2107e2a7970902e [file] [log] [blame]
b.liue9582032025-04-17 19:18:16 +08001#!/usr/bin/env python3
2#
3# Copyright 2008, 2009 (C) Jose Vasconcellos <jvasco@verizon.net>
4#
5# A script that can communicate with jungo-based routers
6# (such as MI424-WR, USR8200 and WRV54G) to backup the installed
7# firmware and replace the boot loader.
8#
9# Tested with Python 2.5 on Linux and Windows
10#
11"""Usage: %s [options] <IP_address> [image.bin | url]
12Valid options:
13\t-h | --help: usage statement
14\t-d | --dump: create a flash dump
15\t-f | --file: use <filename> to store dump contents
16\t-u | --user: provide username (default admin)
17\t-p | --pass: provide password (default password1)
18\t --port: set port for http (default 8080)
19\t-q | --quiet: don't display unnecessary information
20\t-r | --reboot: reboot target on successful transfer
21\t-V | --version: display version information
22
23If no image (or url) is given, a flash dump is created.
24A built-in http server is used when an image file is provided.
25"""
26
27import os
28import sys
29import getopt
30import getpass
31import telnetlib
32import string
33import binascii
34import socket
35import _thread
36import socketserver
37import http.server
38
39reboot = 0
40HOST = "192.168.1.1"
41PORT = 8080
42user = "admin"
43#password = getpass.getpass()
44password = "password1"
45proto = "http"
46url = ""
47imagefile = ""
48dumpfile = ""
49verbose = 1
50do_dump = 0
51dumplen = 0x10000
52flashsize=4*1024*1024
53#device="br0"
54device="ixp0"
55
56####################
57
58def start_server(server):
59 httpd = socketserver.TCPServer((server,PORT),http.server.SimpleHTTPRequestHandler)
60 _thread.start_new_thread(httpd.serve_forever,())
61
62####################
63
64def get_flash_size():
65 # make sure we don't have an A0 stepping
66 tn.write("cat /proc/cpuinfo\n")
67 buf = tn.read_until("Returned 0", 3)
68 if not buf:
69 print("Unable to obtain CPU information; make sure to not use A0 stepping!")
70 elif buf.find('rev 0') > 0:
71 print("Warning: IXP42x stepping A0 detected!")
72 if imagefile or url:
73 print("Error: No linux support for A0 stepping!")
74 sys.exit(2)
75
76 # now get flash size
77 tn.write("cat /proc/mtd\n")
78 buf = tn.read_until("Returned 0", 3)
79 if buf:
80 i = buf.find('mtd0:')
81 if i > 0:
82 return int(buf[i+6:].split()[0],16)
83 # use different command
84 tn.write("flash_layout\n")
85 buf = tn.read_until("Returned 0", 3)
86 i = buf.rfind('Range ')
87 if i > 0:
88 return int(buf[i+17:].split()[0],16)
89 print("Can't determine flash size!")
90 else:
91 print("Unable to obtain flash size!")
92 sys.exit(2)
93
94def image_dump(tn, dumpfile):
95 if not dumpfile:
96 tn.write("ver\n");
97 buf = tn.read_until("Returned 0",2)
98 i = buf.find("Platform:")
99 if i < 0:
100 platform="jungo"
101 else:
102 line=buf[i+9:]
103 i=line.find('\n')
104 platform=line[:i].split()[-1]
105
106 tn.write("rg_conf_print /dev/%s/mac\n" % device);
107 buf = tn.read_until("Returned 0",3)
108
109 i = buf.find("mac(")
110 if i > 0:
111 i += 4
112 else:
113 print("No MAC address found! (use -f option)")
114 sys.exit(1)
115 dumpfile = "%s-%s.bin" % (platform, buf[i:i+17].replace(':',''))
116 else:
117 tn.write("\n")
118
119 print("Dumping flash contents (%dMB) to %s" % (flashsize/1048576, dumpfile))
120 f = open(dumpfile, "wb")
121
122 t=flashsize/dumplen
123 for addr in range(t):
124 if verbose:
125 sys.stdout.write('\r%d%%'%(100*addr/t))
126 sys.stdout.flush()
127
128 tn.write("flash_dump -r 0x%x -l %d -4\n" % (addr*dumplen, dumplen))
129 tn.read_until("\n")
130
131 count = addr*dumplen
132 while 1:
133 buf = tn.read_until("\n")
134 if buf.strip() == "Returned 0":
135 break
136 s = buf.split()
137 if s and s[0][-1] == ':':
138 a=int(s[0][:-1],16)
139 if a != count:
140 print("Format error: %x != %x"%(a,count))
141 sys.exit(2)
142 count += 16
143 f.write(binascii.a2b_hex(string.join(s[1:],'')))
144 tn.read_until(">",1)
145
146 f.close()
147 if verbose:
148 print("")
149
150def telnet_option(sock,cmd,option):
151 #print "Option: %d %d" % (ord(cmd), ord(option))
152 if cmd == telnetlib.DO:
153 c=telnetlib.WILL
154 elif cmd == telnetlib.WILL:
155 c=telnetlib.DO
156 sock.sendall(telnetlib.IAC + c + option)
157
158def telnet_timeout():
159 print("Fatal error: telnet timeout!")
160 sys.exit(1)
161
162def usage():
163 print(__doc__ % os.path.basename(sys.argv[0]))
164
165####################
166
167try:
168 opts, args = getopt.getopt(sys.argv[1:], "hdf:qp:P:rvV", \
169 ["help", "dump", "file=", "user=", "pass=", "port=",
170 "quiet=", "reboot", "verbose", "version"])
171except getopt.GetoptError:
172 # print help information and exit:
173 usage()
174 sys.exit(1)
175
176for o, a in opts:
177 if o in ("-h", "--help"):
178 usage()
179 sys.exit(1)
180 elif o in ("-V", "--version"):
181 print("%s: 0.11" % sys.argv[0])
182 sys.exit(1)
183 elif o in ("-d", "--no-dump"):
184 do_dump = 1
185 elif o in ("-f", "--file"):
186 dumpfile = a
187 elif o in ("-u", "--user"):
188 user = a
189 elif o in ("-p", "--pass"):
190 password = a
191 elif o == "--port":
192 PORT = int(a)
193 elif o in ("-q", "--quiet"):
194 verbose = 0
195 elif o in ("-r", "--reboot"):
196 reboot = 1
197 elif o in ("-v", "--verbose"):
198 verbose = 1
199
200# make sure we have enough arguments
201if len(args) > 0:
202 HOST = args[0]
203
204if len(args) == 2:
205 if args[1].split(':')[0] in ("tftp", "http", "ftp"):
206 url = args[1]
207 else:
208 imagefile = args[1]
209else:
210 do_dump = 1;
211
212####################
213# create a telnet session to the router
214try:
215 tn = telnetlib.Telnet(HOST)
216except socket.error as msg:
217 print("Unable to establish telnet session to %s: %s" % (HOST, msg))
218 sys.exit(1)
219
220tn.set_option_negotiation_callback(telnet_option)
221
222buf = tn.read_until("Username: ", 3)
223if not buf:
224 telnet_timeout()
225tn.write(user+"\n")
226if password:
227 buf = tn.read_until("Password: ", 3)
228 if not buf:
229 telnet_timeout()
230 tn.write(password+"\n")
231
232# wait for prompt
233buf = tn.read_until("> ", 3)
234if not buf:
235 telnet_timeout()
236
237flashsize = get_flash_size()
238
239if do_dump:
240 image_dump(tn, dumpfile)
241
242if imagefile or url:
243 splitpath = os.path.split(imagefile)
244
245 # create load command
246 if url:
247 cmd = "load -u %s -r 0\n" % (url)
248 else:
249 server = tn.get_socket().getsockname()[0]
250 cmd = "load -u http://%s:%d/%s -r 0\n" % (server, PORT, splitpath[1])
251
252 if not os.access(imagefile, os.R_OK):
253 print("File access error: %s" % (imagefile))
254 sys.exit(3)
255
256 # make sure we're in the directory where the image is located
257 if splitpath[0]:
258 os.chdir(splitpath[0])
259
260 start_server(server)
261
262 if verbose:
263 print("Unlocking flash...")
264 tn.write("unlock 0 0x%x\n" % flashsize)
265 buf = tn.read_until("Returned 0",5)
266
267 if verbose:
268 print("Writing new image...")
269 print(cmd, end=' ')
270 tn.write(cmd)
271 buf = tn.read_until("Returned 0",10)
272
273 # wait till the transfer completed
274 buf = tn.read_until("Download completed successfully",20)
275 if buf:
276 print("Flash update complete!")
277 if reboot:
278 tn.write("reboot\n")
279 print("Rebooting...")
280
281tn.write("exit\n")
282tn.close()
283