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

Revision 12376, 9.4 kB (checked in by BrainSlayer, 5 months ago)

merge partition code

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 static void pagesetup(void)
96 {
97 #if defined(CYGPKG_HAL_MIPS_AR2316)
98 #if FISTYPE == 1
99         *(volatile unsigned *)0xB1000090 |= 1;  /*set GPIO0 to 1 to spi flash CS normal state */
100         *(volatile unsigned *)0xB1000098 |= 1;  /*set GPIO0 to be output */
101         page_programming_supported = 1;
102         page_gpio = 0;
103 #endif
104
105 #if FISTYPE == 2
106         *(volatile unsigned *)0xB1000090 |= 1 << 3;     /*set GPIO0 to 1 to spi flash CS normal state */
107         *(volatile unsigned *)0xB1000098 |= 1 << 3;     /*set GPIO0 to be output */
108         page_programming_supported = 1;
109         page_gpio = 3;
110 #endif
111
112 #if FISTYPE == 0
113         page_programming_supported = 0;
114         page_gpio = 0;
115 #endif
116 #endif
117
118 }
119
120 static void flashresult(int rc)
121 {
122         if (rc)
123                 diag_printf("Flash update failed!\n");
124         else
125                 diag_printf("Flash update complete.\n");
126         /* clean da memory */
127         do_reset(0, NULL);
128
129 }
130
131 void do_flash_update_ddwrt(unsigned long base_addr, unsigned long len)
132 {
133         int rc;
134         pagesetup();
135         /* do_flash = 1, write to flash */
136         rc = fw_check_image_ddwrt((char *)base_addr, len, 1);
137         memset((unsigned char *)base_addr, 0, len);
138         flashresult(rc);
139 }
140
141 void do_flash_update_ubnt(unsigned long base_addr, unsigned long len)
142 {
143         int rc;
144         pagesetup();
145         /* do_flash = 1, write to flash */
146         rc = fw_check_image_ubnt((char *)base_addr, len, 1);
147
148         memset((unsigned char *)base_addr, 0, len);
149         flashresult(rc);
150 }
151
152 void do_flash_update_wili(unsigned long base_addr, unsigned long len)
153 {
154         int rc;
155         pagesetup();
156         /* do_flash = 1, write to flash */
157         rc = fw_check_image_wili((char *)base_addr, len, 1);
158
159         memset((unsigned char *)base_addr, 0, len);
160         flashresult(rc);
161 }
162
163 void do_flash_update_senao(unsigned long base_addr, unsigned long len)
164 {
165         int rc;
166         pagesetup();
167         /* do_flash = 1, write to flash */
168         rc = fw_check_image_senao((char *)base_addr, len, 1);
169
170         memset((unsigned char *)base_addr, 0, len);
171         flashresult(rc);
172 }
173
174 void
175 tftpd_fsm(struct tftphdr *tp, int len, ip_route_t * src_route, word src_port)
176 {
177         char *mode, *password;
178         static unsigned int last_sync_block;
179         unsigned int block;
180         static int bytes_received = 0;
181         static unsigned long ptr = 0L;
182
183 #if 0
184         diag_printf("got packet from %d.%d.%d.%d port %d\n",
185                     src_route->ip_addr[0],
186                     src_route->ip_addr[1],
187                     src_route->ip_addr[2], src_route->ip_addr[3], src_port);
188
189         diag_printf("packet len is %d, TFTP opcode is %d\n",
190                     len, tp->th_opcode);
191 #endif
192
193         switch (tp->th_opcode) {
194         case WRQ:               /* write request */
195                 password = tp->th_stuff;
196                 mode = &password[strlen(password) + 1];
197                 diag_printf("TFTPD: Connect from %d.%d.%d.%d port %d\n",
198                             src_route->ip_addr[0],
199                             src_route->ip_addr[1],
200                             src_route->ip_addr[2],
201                             src_route->ip_addr[3], src_port);
202                 //if (strcmp(password, FIRMWARE_PASSWORD)) {
203                 //      tftpd_error(EACCESS, "Access violation (invalid password)", src_route, src_port);
204                 //      break;
205                 //}
206                 if (strcmp(mode, "octet")) {
207                         tftpd_error(EACCESS,
208                                     "Access violation (use binary mode)",
209                                     src_route, src_port);
210                         break;
211                 }
212
213                 /* we are ready for data */
214                 tftpd_send(ACK, 0, src_route, src_port);
215
216                 last_sync_block = 0;
217                 memmove(&wrq_route.ip_addr, &src_route->ip_addr,
218                         sizeof(ip_addr_t));
219                 wrq_port = src_port;
220
221                 break;
222
223         case DATA:              /* received data */
224                 if (*(int *)(wrq_route.ip_addr) != *(int *)(src_route->ip_addr))
225                         tftpd_error(EACCESS,
226                                     "Access violation (unknown address)",
227                                     src_route, src_port);
228
229                 block = ntohs(tp->th_block);
230                 len -= TFTP_HEADER_SIZE;
231
232                 if (block == 1) {
233                         bytes_received = 0;
234                         ptr = BASE_ADDR;        /* rewind pointer */
235
236                 }
237                 bytes_received += len;
238 #if 0
239                 if (!(bytes_received % (1024 * 16)))
240                         diag_printf("ptr = %08X\n", ptr);
241 #endif
242                 if (bytes_received >= MAX_IMAGE_SIZE) {
243                         tftpd_error(EACCESS, "Image size too big.", src_route,
244                                     src_port);
245                         break;
246                 }
247                 if (block == last_sync_block + 1) {
248                         last_sync_block = block;
249
250                         memmove((char *)ptr, &tp->th_data, len);
251                         ptr += len;
252
253                 } else {
254                         /* out of sync */
255                         diag_printf("Blocks out of sync (prev %d, curr %d)",
256                                     last_sync_block, block);
257                         break;
258                 }
259
260                 if (len < SEGSIZE) {
261                         diag_printf("TFTPD: Upload completed (got %d bytes).\n",
262                                     ptr - BASE_ADDR);
263
264                         // CRC CHECK
265                         diag_printf("Checking uploaded file...\n");
266
267                         int isddwrt = 0;
268                         int isubnt = 0;
269                         int iswili = 0;
270                         int issenao = 0;
271                         isddwrt = fw_check_image_ddwrt((char *)BASE_ADDR,
272                                                        ptr - BASE_ADDR, 0) == 0;
273                         if (!isddwrt)
274                                 isubnt =
275                                     fw_check_image_ubnt((char *)BASE_ADDR,
276                                                         ptr - BASE_ADDR,
277                                                         0) == 0;
278
279                         if (!isubnt && !isddwrt)
280                                 iswili =
281                                     fw_check_image_wili((char *)BASE_ADDR,
282                                                         ptr - BASE_ADDR,
283                                                         0) == 0;
284
285                         if (!isubnt && !isddwrt && !iswili)
286                                 issenao =
287                                     fw_check_image_senao((char *)BASE_ADDR,
288                                                          ptr - BASE_ADDR,
289                                                          0) == 0;
290
291                         if (isddwrt || isubnt || iswili || issenao)     /* third parameter 0 - do not write to flash */
292                                 tftpd_send(ACK, block, src_route, src_port);    // crc ok
293                         else {
294                                 tftpd_error(EACCESS, "CRC error", src_route,
295                                             src_port);
296                                 break;
297                         }
298
299                         // write to flash       
300 #if 1
301                         if (isddwrt) {
302                                 diag_printf
303                                     ("DD-WRT firmware format detected\n");
304                                 do_flash_update_ddwrt(BASE_ADDR,
305                                                       ptr - BASE_ADDR);
306                         }
307                         if (isubnt) {
308                                 diag_printf("UBNT firmware format detected\n");
309                                 do_flash_update_ubnt(BASE_ADDR,
310                                                      ptr - BASE_ADDR);
311                         }
312                         if (iswili) {
313                                 diag_printf
314                                     ("WILIGEAR firmware format detected\n");
315                                 do_flash_update_wili(BASE_ADDR,
316                                                      ptr - BASE_ADDR);
317                         }
318                         if (issenao) {
319                                 diag_printf("SENAO firmware format detected\n");
320                                 do_flash_update_senao(BASE_ADDR,
321                                                       ptr - BASE_ADDR);
322                         }
323 #else
324                         diag_printf("Not writing to flash.\n");
325 #endif
326
327                 } else {
328                         /* send ACK to last block in sequence */
329                         tftpd_send(ACK, block, src_route, src_port);
330                 }
331                 break;
332         default:
333                 tftpd_error(EBADOP, "Illegal TFTP operation", src_route,
334                             src_port);
335                 break;
336         }
337 }
338
339 void
340 tftpd_handler(udp_socket_t * skt, char *buf, int len,
341               ip_route_t * src_route, word src_port)
342 {
343         struct tftphdr *tp;
344
345 #if 0
346         diag_printf("tftpd handler called!\n");
347 #endif
348
349         tp = (struct tftphdr *)buf;
350         tp->th_opcode = ntohs(tp->th_opcode);
351         tftpd_fsm(tp, len, src_route, src_port);
352
353 }
354
355 void do_tftpd(int argc, char *argv[])
356 {
357         udp_socket_t udp_skt;
358
359         /* First, fwupdate.bin will be loaded to BASE_ADDR.
360          * Then before writing to flash each partition (kernel, ramdisk)
361          * will be moved to FW_TEMP_BASE (thus this address will be in FIS mem entry
362          */
363         FW_TEMP_BASE =
364             ((CYG_ADDRWORD) mem_segments[0].start + 0x03ff) & ~0x03ff;
365         /* note: memory addresses from 80700000 are reserved ? anyway, do not use them  */
366 //      BASE_ADDR = ((CYG_ADDRWORD)mem_segments[0].end & ~0x03ff) - MAX_IMAGE_SIZE;
367         BASE_ADDR =
368             (((CYG_ADDRWORD) mem_segments[0].start + 0x03ff) & ~0x03ff) +
369             MAX_PART_SIZE;
370         if ((BASE_ADDR + MAX_IMAGE_SIZE) >= 0x80730000)
371                 diag_printf
372                     ("Warning: memory buffer for uploaded file may be on reserved RAM area.\n");
373
374 #if 1
375         /* hack: on ar531x, elf image should always be at 0x80002000 base, so adjust if possible */
376         if ((FW_TEMP_BASE < 0x80002000)
377             && (FW_TEMP_BASE + MAX_PART_SIZE <= BASE_ADDR))
378                 FW_TEMP_BASE = 0x80002000;
379 #endif
380
381         diag_printf
382             ("TFTPD is running (using memory ranges: %p - %p, %p - %p).\n",
383              FW_TEMP_BASE, BASE_ADDR, BASE_ADDR, BASE_ADDR + MAX_IMAGE_SIZE);
384
385         __udp_install_listener(&udp_skt, IPPORT_TFTPD, tftpd_handler);
386
387         while (!_rb_break(0)) {
388                 __enet_poll();  // wait for packet ?
389         }
390
391         __udp_remove_listener(IPPORT_TFTPD);
392         diag_printf("TFTPD terminated.\n");
393 }
Note: See TracBrowser for help on using the browser.