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

Revision 12429, 8.0 kB (checked in by BrainSlayer, 5 months ago)

compressed ELF support is required for ubnt images

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         set_gpio(0,1);
114         page_programming_supported = 1;
115         page_gpio = 0;
116 #endif
117
118 #if FISTYPE == 2
119         set_gpio(3,1);
120         page_programming_supported = 1;
121         page_gpio = 3;
122 #endif
123
124 #if FISTYPE == 0
125         page_programming_supported = 0;
126         page_gpio = 0;
127 #endif
128 #endif
129         /* do_flash = 1, write to flash */
130         rc = fw_formats[index].fw_check_image((char *)base_addr, len, 1);
131         if (rc)
132                 diag_printf("Flash update failed!\n");
133         else
134                 diag_printf("Flash update complete.\n");
135         /* clean da memory */
136         memset((unsigned char *)base_addr, 0, len);
137         do_reset(0, NULL);
138 }
139
140 void
141 tftpd_fsm(struct tftphdr *tp, int len, ip_route_t * src_route, word src_port)
142 {
143         char *mode, *password;
144         static unsigned int last_sync_block;
145         unsigned int block;
146         static int bytes_received = 0;
147         static unsigned long ptr = 0L;
148
149 #if 0
150         diag_printf("got packet from %d.%d.%d.%d port %d\n",
151                     src_route->ip_addr[0],
152                     src_route->ip_addr[1],
153                     src_route->ip_addr[2], src_route->ip_addr[3], src_port);
154
155         diag_printf("packet len is %d, TFTP opcode is %d\n",
156                     len, tp->th_opcode);
157 #endif
158
159         switch (tp->th_opcode) {
160         case WRQ:               /* write request */
161                 password = tp->th_stuff;
162                 mode = &password[strlen(password) + 1];
163                 diag_printf("TFTPD: Connect from %d.%d.%d.%d port %d\n",
164                             src_route->ip_addr[0],
165                             src_route->ip_addr[1],
166                             src_route->ip_addr[2],
167                             src_route->ip_addr[3], src_port);
168                 //if (strcmp(password, FIRMWARE_PASSWORD)) {
169                 //      tftpd_error(EACCESS, "Access violation (invalid password)", src_route, src_port);
170                 //      break;
171                 //}
172                 if (strcmp(mode, "octet")) {
173                         tftpd_error(EACCESS,
174                                     "Access violation (use binary mode)",
175                                     src_route, src_port);
176                         break;
177                 }
178
179                 /* we are ready for data */
180                 tftpd_send(ACK, 0, src_route, src_port);
181
182                 last_sync_block = 0;
183                 memmove(&wrq_route.ip_addr, &src_route->ip_addr,
184                         sizeof(ip_addr_t));
185                 wrq_port = src_port;
186
187                 break;
188
189         case DATA:              /* received data */
190                 if (*(int *)(wrq_route.ip_addr) != *(int *)(src_route->ip_addr))
191                         tftpd_error(EACCESS,
192                                     "Access violation (unknown address)",
193                                     src_route, src_port);
194
195                 block = ntohs(tp->th_block);
196                 len -= TFTP_HEADER_SIZE;
197
198                 if (block == 1) {
199                         bytes_received = 0;
200                         ptr = BASE_ADDR;        /* rewind pointer */
201
202                 }
203                 bytes_received += len;
204 #if 0
205                 if (!(bytes_received % (1024 * 16)))
206                         diag_printf("ptr = %08X\n", ptr);
207 #endif
208                 if (bytes_received >= MAX_IMAGE_SIZE) {
209                         tftpd_error(EACCESS, "Image size too big.", src_route,
210                                     src_port);
211                         break;
212                 }
213                 if (block == last_sync_block + 1) {
214                         last_sync_block = block;
215
216                         memmove((char *)ptr, &tp->th_data, len);
217                         ptr += len;
218
219                 } else {
220                         /* out of sync */
221                         diag_printf("Blocks out of sync (prev %d, curr %d)",
222                                     last_sync_block, block);
223                         break;
224                 }
225
226                 if (len < SEGSIZE) {
227                         diag_printf("TFTPD: Upload completed (got %d bytes).\n",
228                                     ptr - BASE_ADDR);
229
230                         // CRC CHECK
231                         diag_printf("Checking uploaded file...\n");
232
233                         int detect = -1;
234                         int i;
235                         for (i = 0;
236                              i <
237                              sizeof(fw_formats) /
238                              sizeof(struct firmware_formats); i++) {
239                                 int v = fw_formats[i].fw_check_image((char *)BASE_ADDR,ptr - BASE_ADDR,0);
240 //                              diag_printf("%s returns %d\n",fw_formats[i].name,v);
241                                 if (!v) {
242                                         detect = i;
243                                         break;
244                                 }
245                         }
246
247                         if (detect!=-1) /* third parameter 0 - do not write to flash */
248                                 tftpd_send(ACK, block, src_route, src_port);    // crc ok
249                         else {
250                                 tftpd_error(EACCESS, "CRC error", src_route,
251                                             src_port);
252                                 break;
253                         }
254
255                         // write to flash       
256 #if 1
257                         diag_printf("%s: firmware format detected\n",
258                                     fw_formats[detect].name);
259                         do_flash_update(BASE_ADDR, ptr - BASE_ADDR, detect);
260 #else
261                         diag_printf("Not writing to flash.\n");
262 #endif
263
264                 } else {
265                         /* send ACK to last block in sequence */
266                         tftpd_send(ACK, block, src_route, src_port);
267                 }
268                 break;
269         default:
270                 tftpd_error(EBADOP, "Illegal TFTP operation", src_route,
271                             src_port);
272                 break;
273         }
274 }
275
276 void
277 tftpd_handler(udp_socket_t * skt, char *buf, int len,
278               ip_route_t * src_route, word src_port)
279 {
280         struct tftphdr *tp;
281
282 #if 0
283         diag_printf("tftpd handler called!\n");
284 #endif
285
286         tp = (struct tftphdr *)buf;
287         tp->th_opcode = ntohs(tp->th_opcode);
288         tftpd_fsm(tp, len, src_route, src_port);
289
290 }
291
292 void do_tftpd(int argc, char *argv[])
293 {
294         udp_socket_t udp_skt;
295
296         /* First, fwupdate.bin will be loaded to BASE_ADDR.
297          * Then before writing to flash each partition (kernel, ramdisk)
298          * will be moved to FW_TEMP_BASE (thus this address will be in FIS mem entry
299          */
300         FW_TEMP_BASE =
301             ((CYG_ADDRWORD) mem_segments[0].start + 0x03ff) & ~0x03ff;
302         /* note: memory addresses from 80700000 are reserved ? anyway, do not use them  */
303 //      BASE_ADDR = ((CYG_ADDRWORD)mem_segments[0].end & ~0x03ff) - MAX_IMAGE_SIZE;
304         BASE_ADDR =
305             (((CYG_ADDRWORD) mem_segments[0].start + 0x03ff) & ~0x03ff) +
306             MAX_PART_SIZE;
307         if ((BASE_ADDR + MAX_IMAGE_SIZE) >= 0x80730000)
308                 diag_printf
309                     ("Warning: memory buffer for uploaded file may be on reserved RAM area.\n");
310
311 #if 1
312         /* hack: on ar531x, elf image should always be at 0x80002000 base, so adjust if possible */
313         if ((FW_TEMP_BASE < 0x80002000)
314             && (FW_TEMP_BASE + MAX_PART_SIZE <= BASE_ADDR))
315                 FW_TEMP_BASE = 0x80002000;
316 #endif
317
318         diag_printf
319             ("TFTPD is running (using memory ranges: %p - %p, %p - %p).\n",
320              FW_TEMP_BASE, BASE_ADDR, BASE_ADDR, BASE_ADDR + MAX_IMAGE_SIZE);
321
322         __udp_install_listener(&udp_skt, IPPORT_TFTPD, tftpd_handler);
323
324         while (!_rb_break(0)) {
325                 __enet_poll();  // wait for packet ?
326         }
327
328         __udp_remove_listener(IPPORT_TFTPD);
329         diag_printf("TFTPD terminated.\n");
330 }
Note: See TracBrowser for help on using the browser.