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

Revision 12368, 8.9 kB (checked in by BrainSlayer, 5 months ago)

tftp server added, supports wiligear, ubiquiti and dd-wrt webflash format

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
164 tftpd_fsm(struct tftphdr *tp, int len, ip_route_t * src_route, word src_port)
165 {
166         char *mode, *password;
167         static unsigned int last_sync_block;
168         unsigned int block;
169         static int bytes_received = 0;
170         static unsigned long ptr = 0L;
171
172 #if 0
173         diag_printf("got packet from %d.%d.%d.%d port %d\n",
174                     src_route->ip_addr[0],
175                     src_route->ip_addr[1],
176                     src_route->ip_addr[2], src_route->ip_addr[3], src_port);
177
178         diag_printf("packet len is %d, TFTP opcode is %d\n",
179                     len, tp->th_opcode);
180 #endif
181
182         switch (tp->th_opcode) {
183         case WRQ:               /* write request */
184                 password = tp->th_stuff;
185                 mode = &password[strlen(password) + 1];
186                 diag_printf("TFTPD: Connect from %d.%d.%d.%d port %d\n",
187                             src_route->ip_addr[0],
188                             src_route->ip_addr[1],
189                             src_route->ip_addr[2],
190                             src_route->ip_addr[3], src_port);
191                 //if (strcmp(password, FIRMWARE_PASSWORD)) {
192                 //      tftpd_error(EACCESS, "Access violation (invalid password)", src_route, src_port);
193                 //      break;
194                 //}
195                 if (strcmp(mode, "octet")) {
196                         tftpd_error(EACCESS,
197                                     "Access violation (use binary mode)",
198                                     src_route, src_port);
199                         break;
200                 }
201
202                 /* we are ready for data */
203                 tftpd_send(ACK, 0, src_route, src_port);
204
205                 last_sync_block = 0;
206                 memmove(&wrq_route.ip_addr, &src_route->ip_addr,
207                         sizeof(ip_addr_t));
208                 wrq_port = src_port;
209
210                 break;
211
212         case DATA:              /* received data */
213                 if (*(int *)(wrq_route.ip_addr) != *(int *)(src_route->ip_addr))
214                         tftpd_error(EACCESS,
215                                     "Access violation (unknown address)",
216                                     src_route, src_port);
217
218                 block = ntohs(tp->th_block);
219                 len -= TFTP_HEADER_SIZE;
220
221                 if (block == 1) {
222                         bytes_received = 0;
223                         ptr = BASE_ADDR;        /* rewind pointer */
224
225                 }
226                 bytes_received += len;
227 #if 0
228                 if (!(bytes_received % (1024 * 16)))
229                         diag_printf("ptr = %08X\n", ptr);
230 #endif
231                 if (bytes_received >= MAX_IMAGE_SIZE) {
232                         tftpd_error(EACCESS, "Image size too big.", src_route,
233                                     src_port);
234                         break;
235                 }
236                 if (block == last_sync_block + 1) {
237                         last_sync_block = block;
238
239                         memmove((char *)ptr, &tp->th_data, len);
240                         ptr += len;
241
242                 } else {
243                         /* out of sync */
244                         diag_printf("Blocks out of sync (prev %d, curr %d)",
245                                     last_sync_block, block);
246                         break;
247                 }
248
249                 if (len < SEGSIZE) {
250                         diag_printf("TFTPD: Upload completed (got %d bytes).\n",
251                                     ptr - BASE_ADDR);
252
253                         // CRC CHECK
254                         diag_printf("Checking uploaded file...\n");
255
256                         int isddwrt = 0;
257                         int isubnt = 0;
258                         int iswili = 0;
259                         isddwrt = fw_check_image_ddwrt((char *)BASE_ADDR,
260                                                        ptr - BASE_ADDR, 0) == 0;
261                         if (!isddwrt)
262                                 isubnt =
263                                     fw_check_image_ubnt((char *)BASE_ADDR,
264                                                         ptr - BASE_ADDR,
265                                                         0) == 0;
266
267                         if (!isubnt && !isddwrt)
268                                 iswili =
269                                     fw_check_image_wili((char *)BASE_ADDR,
270                                                         ptr - BASE_ADDR,
271                                                         0) == 0;
272
273                         if (isddwrt || isubnt || iswili)        /* third parameter 0 - do not write to flash */
274                                 tftpd_send(ACK, block, src_route, src_port);    // crc ok
275                         else {
276                                 tftpd_error(EACCESS, "CRC error", src_route,
277                                             src_port);
278                                 break;
279                         }
280
281                         // write to flash       
282 #if 1
283                         if (isddwrt) {
284                                 diag_printf
285                                     ("DD-WRT firmware format detected\n");
286                                 do_flash_update_ddwrt(BASE_ADDR,
287                                                       ptr - BASE_ADDR);
288                         }
289                         if (isubnt) {
290                                 diag_printf("UBNT firmware format detected\n");
291                                 do_flash_update_ubnt(BASE_ADDR,
292                                                      ptr - BASE_ADDR);
293                         }
294                         if (iswili) {
295                                 diag_printf
296                                     ("WILIGEAR firmware format detected\n");
297                                 do_flash_update_wili(BASE_ADDR,
298                                                      ptr - BASE_ADDR);
299                         }
300 #else
301                         diag_printf("Not writing to flash.\n");
302 #endif
303
304                 } else {
305                         /* send ACK to last block in sequence */
306                         tftpd_send(ACK, block, src_route, src_port);
307                 }
308                 break;
309         default:
310                 tftpd_error(EBADOP, "Illegal TFTP operation", src_route,
311                             src_port);
312                 break;
313         }
314 }
315
316 void
317 tftpd_handler(udp_socket_t * skt, char *buf, int len,
318               ip_route_t * src_route, word src_port)
319 {
320         struct tftphdr *tp;
321
322 #if 0
323         diag_printf("tftpd handler called!\n");
324 #endif
325
326         tp = (struct tftphdr *)buf;
327         tp->th_opcode = ntohs(tp->th_opcode);
328         tftpd_fsm(tp, len, src_route, src_port);
329
330 }
331
332 void do_tftpd(int argc, char *argv[])
333 {
334         udp_socket_t udp_skt;
335
336         /* First, fwupdate.bin will be loaded to BASE_ADDR.
337          * Then before writing to flash each partition (kernel, ramdisk)
338          * will be moved to FW_TEMP_BASE (thus this address will be in FIS mem entry
339          */
340         FW_TEMP_BASE =
341             ((CYG_ADDRWORD) mem_segments[0].start + 0x03ff) & ~0x03ff;
342         /* note: memory addresses from 80700000 are reserved ? anyway, do not use them  */
343 //      BASE_ADDR = ((CYG_ADDRWORD)mem_segments[0].end & ~0x03ff) - MAX_IMAGE_SIZE;
344         BASE_ADDR =
345             (((CYG_ADDRWORD) mem_segments[0].start + 0x03ff) & ~0x03ff) +
346             MAX_PART_SIZE;
347         if ((BASE_ADDR + MAX_IMAGE_SIZE) >= 0x80730000)
348                 diag_printf
349                     ("Warning: memory buffer for uploaded file may be on reserved RAM area.\n");
350
351 #if 1
352         /* hack: on ar531x, elf image should always be at 0x80002000 base, so adjust if possible */
353         if ((FW_TEMP_BASE < 0x80002000)
354             && (FW_TEMP_BASE + MAX_PART_SIZE <= BASE_ADDR))
355                 FW_TEMP_BASE = 0x80002000;
356 #endif
357
358         diag_printf
359             ("TFTPD is running (using memory ranges: %p - %p, %p - %p).\n",
360              FW_TEMP_BASE, BASE_ADDR, BASE_ADDR, BASE_ADDR + MAX_IMAGE_SIZE);
361
362         __udp_install_listener(&udp_skt, IPPORT_TFTPD, tftpd_handler);
363
364         while (!_rb_break(0)) {
365                 __enet_poll();  // wait for packet ?
366         }
367
368         __udp_remove_listener(IPPORT_TFTPD);
369         diag_printf("TFTPD terminated.\n");
370 }
Note: See TracBrowser for help on using the browser.