root/ar5315_microredboot/microredboot/ecos/packages/redboot/current/src/net/tftp_server.c

Revision 12388, 8.3 kB (checked in by BrainSlayer, 5 months ago)

check target platform to prevent wrong firmware flashes

Line 
1 //==========================================================================
2 //
3 //      net/tftp_server.c
4 //
5 //      Stand-alone TFTP server support for RedBoot
6 //
7
8 #include <redboot.h>            // have_net
9 #include <net/net.h>
10 #include <net/tftp.h>
11 #include <net/tftp_support.h>
12 #include <cyg/io/flash.h>
13 #include "fwupgrade.h"
14
15 #define IPPORT_TFTPD            69
16 #define FIRMWARE_PASSWORD       "flash_update"
17
18 #define TFTP_HEADER_SIZE        4
19 #define SEGSIZE                 512
20
21 /* from main.c */
22 extern void do_reset(int argc, char *argv[]);
23
24 /* global variables for tftpd */
25 static ip_route_t wrq_route = { ip_addr:{0, 0, 0, 0} };
26
27 static word wrq_port = 0;
28 static char tftpd_buffer[SEGSIZE + TFTP_HEADER_SIZE];
29
30 unsigned long tftpd_base = 0;
31
32 static char usage[] = "";
33
34 // Exported CLI function
35 RedBoot_cmd("tftpd",
36             "Start tftp server and wait for firmware update", usage, do_tftpd);
37
38 static void
39 tftpd_error(int error_code, char *error_msg, ip_route_t * src_route,
40             word src_port)
41 {
42         struct tftphdr *tp;
43         int len;
44
45         diag_printf("TFTPD: Error %d: %s\n", error_code, error_msg);
46
47         tp = (struct tftphdr *)tftpd_buffer;
48         tp->th_opcode = htons((unsigned short)ERROR);
49         tp->th_code = htons((unsigned short)error_code);
50         strcpy(tp->th_msg, error_msg);
51         len = strlen(error_msg);
52         tp->th_msg[len] = '\0';
53         len += (TFTP_HEADER_SIZE + 1);
54
55         __udp_send((char *)tftpd_buffer, len, src_route, src_port,
56                    IPPORT_TFTPD);
57 }
58
59 static void
60 tftpd_send(int opcode, int block, ip_route_t * src_route, word src_port)
61 {
62         struct tftphdr *tp;
63
64 #if 0
65         diag_printf("tftpd_send\n");
66 #endif
67
68         tp = (struct tftphdr *)tftpd_buffer;
69         tp->th_opcode = htons((unsigned short)opcode);
70         tp->th_block = htons((unsigned short)block);
71
72         __udp_send((char *)tftpd_buffer, TFTP_HEADER_SIZE, src_route, src_port,
73                    IPPORT_TFTPD);
74 }
75
76 #if 0
77 /* jM -- set status led green or red */
78 #define STATUS_LED_GPIO 2
79 static void set_status_led(int status)
80 {
81         HAL_GPIO_OUTPUT_ENABLE(STATUS_LED_GPIO);
82
83         if (status == 0)
84                 HAL_GPIO_OUTPUT_CLEAR(STATUS_LED_GPIO);
85         else
86                 HAL_GPIO_OUTPUT_SET(STATUS_LED_GPIO);
87 }
88 #endif
89
90 #include "../ramconfig.h"
91
92 extern int page_programming_supported;
93 extern int page_gpio;
94
95 struct firmware_formats {
96         char *name;
97         int (*fw_check_image) (unsigned char *, unsigned long, int);
98 };
99
100 static const struct firmware_formats fw_formats[] = {
101         {.name = "DD-WRT",.fw_check_image = fw_check_image_ddwrt},
102         {.name = "UBIQUITI",.fw_check_image = fw_check_image_ubnt},
103         {.name = "WILIGEAR",.fw_check_image = fw_check_image_wili},
104         {.name = "SENAO",.fw_check_image = fw_check_image_senao},
105 };
106
107 static void do_flash_update(unsigned long base_addr, unsigned long len,
108                             int index)
109 {
110         int rc;
111 #if defined(CYGPKG_HAL_MIPS_AR2316)
112 #if FISTYPE == 1
113         *(volatile unsigned *)0xB1000090 |= 1;  /*set GPIO0 to 1 to spi flash CS normal state */
114         *(volatile unsigned *)0xB1000098 |= 1;  /*set GPIO0 to be output */
115         page_programming_supported = 1;
116         page_gpio = 0;
117 #endif
118
119 #if FISTYPE == 2
120         *(volatile unsigned *)0xB1000090 |= 1 << 3;     /*set GPIO0 to 1 to spi flash CS normal state */
121         *(volatile unsigned *)0xB1000098 |= 1 << 3;     /*set GPIO0 to be output */
122         page_programming_supported = 1;
123         page_gpio = 3;
124 #endif
125
126 #if FISTYPE == 0
127         page_programming_supported = 0;
128         page_gpio = 0;
129 #endif
130 #endif
131         /* do_flash = 1, write to flash */
132         rc = fw_formats[index].fw_check_image((char *)base_addr, len, 1);
133         if (rc)
134                 diag_printf("Flash update failed!\n");
135         else
136                 diag_printf("Flash update complete.\n");
137         /* clean da memory */
138         memset((unsigned char *)base_addr, 0, len);
139         do_reset(0, NULL);
140 }
141
142 void
143 tftpd_fsm(struct tftphdr *tp, int len, ip_route_t * src_route, word src_port)
144 {
145         char *mode, *password;
146         static unsigned int last_sync_block;
147         unsigned int block;
148         static int bytes_received = 0;
149         static unsigned long ptr = 0L;
150
151 #if 0
152         diag_printf("got packet from %d.%d.%d.%d port %d\n",
153                     src_route->ip_addr[0],
154                     src_route->ip_addr[1],
155                     src_route->ip_addr[2], src_route->ip_addr[3], src_port);
156
157         diag_printf("packet len is %d, TFTP opcode is %d\n",
158                     len, tp->th_opcode);
159 #endif
160
161         switch (tp->th_opcode) {
162         case WRQ:               /* write request */
163                 password = tp->th_stuff;
164                 mode = &password[strlen(password) + 1];
165                 diag_printf("TFTPD: Connect from %d.%d.%d.%d port %d\n",
166                             src_route->ip_addr[0],
167                             src_route->ip_addr[1],
168                             src_route->ip_addr[2],
169                             src_route->ip_addr[3], src_port);
170                 //if (strcmp(password, FIRMWARE_PASSWORD)) {
171                 //      tftpd_error(EACCESS, "Access violation (invalid password)", src_route, src_port);
172                 //      break;
173                 //}
174                 if (strcmp(mode, "octet")) {
175                         tftpd_error(EACCESS,
176                                     "Access violation (use binary mode)",
177                                     src_route, src_port);
178                         break;
179                 }
180
181                 /* we are ready for data */
182                 tftpd_send(ACK, 0, src_route, src_port);
183
184                 last_sync_block = 0;
185                 memmove(&wrq_route.ip_addr, &src_route->ip_addr,
186                         sizeof(ip_addr_t));
187                 wrq_port = src_port;
188
189                 break;
190
191         case DATA:              /* received data */
192                 if (*(int *)(wrq_route.ip_addr) != *(int *)(src_route->ip_addr))
193                         tftpd_error(EACCESS,
194                                     "Access violation (unknown address)",
195                                     src_route, src_port);
196
197                 block = ntohs(tp->th_block);
198                 len -= TFTP_HEADER_SIZE;
199
200                 if (block == 1) {
201                         bytes_received = 0;
202                         ptr = BASE_ADDR;        /* rewind pointer */
203
204                 }
205                 bytes_received += len;
206 #if 0
207                 if (!(bytes_received % (1024 * 16)))
208                         diag_printf("ptr = %08X\n", ptr);
209 #endif
210                 if (bytes_received >= MAX_IMAGE_SIZE) {
211                         tftpd_error(EACCESS, "Image size too big.", src_route,
212                                     src_port);
213                         break;
214                 }
215                 if (block == last_sync_block + 1) {
216                         last_sync_block = block;
217
218                         memmove((char *)ptr, &tp->th_data, len);
219                         ptr += len;
220
221                 } else {
222                         /* out of sync */
223                         diag_printf("Blocks out of sync (prev %d, curr %d)",
224                                     last_sync_block, block);
225                         break;
226                 }
227
228                 if (len < SEGSIZE) {
229                         diag_printf("TFTPD: Upload completed (got %d bytes).\n",
230                                     ptr - BASE_ADDR);
231
232                         // CRC CHECK
233                         diag_printf("Checking uploaded file...\n");
234
235                         int detect = 0;
236                         int i;
237                         for (i = 0;
238                              i <
239                              sizeof(fw_formats) /
240                              sizeof(struct firmware_formats); i++) {
241                                 int v =
242                                     fw_formats[i].fw_check_image((char *)
243                                                                  BASE_ADDR,
244                                                                  ptr -
245                                                                  BASE_ADDR,
246                                                                  0) == 0;
247                                 if (v) {
248                                         detect = i;
249                                         break;
250                                 }
251                         }
252
253                         if (detect)     /* third parameter 0 - do not write to flash */
254                                 tftpd_send(ACK, block, src_route, src_port);    // crc ok
255                         else {
256                                 tftpd_error(EACCESS, "CRC error", src_route,
257                                             src_port);
258                                 break;
259                         }
260
261                         // write to flash       
262 #if 1
263                         diag_printf("%s: firmware format detected\n",
264                                     fw_formats[detect].name);
265                         do_flash_update(BASE_ADDR, ptr - BASE_ADDR, detect);
266 #else
267                         diag_printf("Not writing to flash.\n");
268 #endif
269
270                 } else {
271                         /* send ACK to last block in sequence */
272                         tftpd_send(ACK, block, src_route, src_port);
273                 }
274                 break;
275         default:
276                 tftpd_error(EBADOP, "Illegal TFTP operation", src_route,
277                             src_port);
278                 break;
279         }
280 }
281
282 void
283 tftpd_handler(udp_socket_t * skt, char *buf, int len,
284               ip_route_t * src_route, word src_port)
285 {
286         struct tftphdr *tp;
287
288 #if 0
289         diag_printf("tftpd handler called!\n");
290 #endif
291
292         tp = (struct tftphdr *)buf;
293         tp->th_opcode = ntohs(tp->th_opcode);
294         tftpd_fsm(tp, len, src_route, src_port);
295
296 }
297
298 void do_tftpd(int argc, char *argv[])
299 {
300         udp_socket_t udp_skt;
301
302         /* First, fwupdate.bin will be loaded to BASE_ADDR.
303          * Then before writing to flash each partition (kernel, ramdisk)
304          * will be moved to FW_TEMP_BASE (thus this address will be in FIS mem entry
305          */
306         FW_TEMP_BASE =
307             ((CYG_ADDRWORD) mem_segments[0].start + 0x03ff) & ~0x03ff;
308         /* note: memory addresses from 80700000 are reserved ? anyway, do not use them  */
309 //      BASE_ADDR = ((CYG_ADDRWORD)mem_segments[0].end & ~0x03ff) - MAX_IMAGE_SIZE;
310         BASE_ADDR =
311             (((CYG_ADDRWORD) mem_segments[0].start + 0x03ff) & ~0x03ff) +
312             MAX_PART_SIZE;
313         if ((BASE_ADDR + MAX_IMAGE_SIZE) >= 0x80730000)
314                 diag_printf
315                     ("Warning: memory buffer for uploaded file may be on reserved RAM area.\n");
316
317 #if 1
318         /* hack: on ar531x, elf image should always be at 0x80002000 base, so adjust if possible */
319         if ((FW_TEMP_BASE < 0x80002000)
320             && (FW_TEMP_BASE + MAX_PART_SIZE <= BASE_ADDR))
321                 FW_TEMP_BASE = 0x80002000;
322 #endif
323
324         diag_printf
325             ("TFTPD is running (using memory ranges: %p - %p, %p - %p).\n",
326              FW_TEMP_BASE, BASE_ADDR, BASE_ADDR, BASE_ADDR + MAX_IMAGE_SIZE);
327
328         __udp_install_listener(&udp_skt, IPPORT_TFTPD, tftpd_handler);
329
330         while (!_rb_break(0)) {
331                 __enet_poll();  // wait for packet ?
332         }
333
334         __udp_remove_listener(IPPORT_TFTPD);
335         diag_printf("TFTPD terminated.\n");
336 }
Note: See TracBrowser for help on using the browser.