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

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

check target platform to prevent wrong firmware flashes

Line 
1 /*
2 firmware upgrade code for UBNT images
3 huge parts are taken from ubnt fwsplit utility
4
5 2009, Sebastian Gottschall
6 */
7
8 #include <redboot.h>
9 #include <cyg/io/flash.h>
10 #include <fis.h>
11 #include <flash_config.h>
12 #include "fwupgrade_ubnt.h"
13
14 /* some variables from flash.c */
15 extern void *flash_start, *flash_end;
16 extern int flash_block_size, flash_num_blocks;
17 #ifdef CYGOPT_REDBOOT_FIS
18 extern void *fis_work_block;
19 extern void *fis_addr;
20 extern int fisdir_size;         // Size of FIS directory.
21 #endif
22 //extern void _show_invalid_flash_address(CYG_ADDRESS flash_addr, int stat);
23 extern void fis_update_directory(void);
24
25 //#define TRACE diag_printf("DBG: %s:%d\n", __FUNCTION__, __LINE__)
26
27 #define TRACE
28
29 #define MAX_PARTS 8
30
31 typedef struct fw_part {
32         part_t *header;
33         unsigned char *data;
34         u_int32_t data_size;
35         part_crc_t *signature;
36 } fw_part_t;
37
38 typedef struct fw {
39         u_int32_t size;
40         char version[256];
41         fw_part_t parts[MAX_PARTS];
42         int part_count;
43 } fw_t;
44
45 extern void addPartition(char *name, unsigned int flashbase,
46                          unsigned int memaddr, unsigned int entryaddr,
47                          unsigned int partsize, unsigned int datasize);
48
49 #define crc32 cyg_ether_crc32_accumulate
50
51 extern void fis_init(int argc, char *argv[], int force);
52
53 int fw_check_image_ubnt(unsigned char *addr, unsigned long maxlen, int do_flash)
54 {
55         header_t *header = (header_t *) addr;
56         fw_t fw;
57         int len = sizeof(header_t) - (2 * sizeof(u_int32_t));
58         unsigned int crc = crc32(0L, (unsigned char *)header, len);
59         signature_t *sig;
60         fw.size = maxlen;
61         if (!strncmp(header->magic, "OPEN", 4)
62             && !strncmp(header->magic, "UBNT", 4)) {
63                 return -1;      //not ubnt firmware
64         }
65 #if defined(CYGPKG_HAL_MIPS_AR2316)
66         if (strncmp((unsigned char *)&header->version[4], "ar2316", 6)) {
67                 diag_printf
68                     ("UBNT_FW: cannot upgrade, wrong target platform. only ar2316 is valid");
69                 return -1;
70         }
71 #endif
72 #if defined(CYGPKG_HAL_MIPS_AR5312)
73         if (strncmp((unsigned char *)&header->version[4], "ar2313", 6)) {
74                 diag_printf
75                     ("UBNT_FW: cannot upgrade, wrong target platform. only ar2313 is valid");
76                 return -1;
77         }
78 #endif
79         if (htonl(crc) != header->crc) {
80                 diag_printf("UBNT_FW: header crc failed\n");
81                 return -1;
82         }
83         memcpy(fw.version, header->version, sizeof(fw.version));
84         if (do_flash)
85                 diag_printf("UBNT_FW: Firmware version: '%s'\n",
86                             header->version);
87         part_t *p;
88         p = (part_t *) (addr + sizeof(header_t));
89         int i = 0;
90         while (strncmp(p->magic, MAGIC_END, MAGIC_LENGTH) != 0) {
91                 if (do_flash) {
92                         diag_printf("Partition: %s [%u]\n", p->name,
93                                     ntohl(p->index));
94                         diag_printf("Partition size: 0x%X\n",
95                                     ntohl(p->part_size));
96                         diag_printf("Data size: %u\n", ntohl(p->data_size));
97                 }
98                 if ((strncmp(p->magic, MAGIC_PART, MAGIC_LENGTH) == 0)
99                     && (i < MAX_PARTS)) {
100                         fw_part_t *fwp = &fw.parts[i];
101
102                         fwp->header = p;
103                         fwp->data = (unsigned char *)p + sizeof(part_t);
104                         fwp->data_size = ntohl(p->data_size);
105                         fwp->signature =
106                             (part_crc_t *) (fwp->data + fwp->data_size);
107                         crc =
108                             htonl(crc32
109                                   (0L, (unsigned char *)p,
110                                    fwp->data_size + sizeof(part_t)));
111                         if (crc != fwp->signature->crc) {
112                                 diag_printf
113                                     ("UBNT_FW: Invalid '%s' CRC (claims: %u, but is %u)\n",
114                                      fwp->header->name, fwp->signature->crc,
115                                      crc);
116                                 return -1;
117                         }
118                         ++i;
119                 }
120
121                 p = (part_t *) ((unsigned char *)p + sizeof(part_t) +
122                                 ntohl(p->data_size) + sizeof(part_crc_t));
123
124                 /* check bounds */
125                 if (((unsigned char *)p - addr) >= maxlen) {
126                         return -3;
127                 }
128         }
129
130         fw.part_count = i;
131
132         sig = (signature_t *) p;
133         if (strncmp(sig->magic, MAGIC_END, MAGIC_LENGTH) != 0) {
134                 diag_printf("UBNT_FW: Bad firmware signature\n");
135                 return -4;
136         }
137
138         crc = htonl(crc32(0L, addr, (unsigned char *)sig - addr));
139         if (crc != sig->crc) {
140                 diag_printf
141                     ("UBNT_FW: Invalid signature CRC (claims: %u, but is %u)\n",
142                      sig->crc, crc);
143                 return -5;
144         }
145
146         if (do_flash) {
147                 char *arg[] = { "fis", "init" };
148                 fis_init(2, arg, 1);
149                 void *err_addr;
150                 flash_read(fis_addr, fis_work_block, fisdir_size,
151                            (void **)&err_addr);
152                 for (i = 0; i < fw.part_count; ++i) {
153                         fw_part_t *fwp = &fw.parts[i];
154                         /* do not flash bootloaders bigger than 64kb, since it makes no sense to step back */
155                         if (!strncmp(fwp->header->name, "RedBoot", 7)
156                             && ntohl(fwp->header->part_size) > 0x10000) {
157                                 diag_printf("ignore %s\n", fwp->header->name);
158                                 continue;
159                         }
160                         diag_printf("UBNT_FW: Flashing: %s\n",
161                                     fwp->header->name);
162                         int stat;
163
164                         unsigned int base = ntohl(fwp->header->baseaddr);
165                         /* convert flash mappings to fit to the current bootloader flash mapping which might be incompatible */
166                         if ((base & 0xbfc00000) == 0xbfc00000) {
167                                 base ^= 0xbfc00000;
168                         } else if ((base & 0xbe00000) == 0xbe00000) {
169                                 base ^= 0xbe00000;
170                         } else if ((base & 0xa800000) == 0xa800000) {
171                                 base ^= 0xa800000;
172                         }
173                         base |= CYGNUM_FLASH_BASE;
174                         if ((stat =
175                              flash_erase((void *)base,
176                                          ntohl(fwp->header->part_size),
177                                          (void **)&err_addr)) != 0) {
178                                 diag_printf
179                                     ("UBNT_FW: Can't erase region at %p: %s\n",
180                                      err_addr, flash_errmsg(stat));
181                                 return -1;
182                         }
183                         if ((stat =
184                              flash_program((void *)base,
185                                            (void *)fwp->data,
186                                            ntohl(fwp->data_size),
187                                            (void **)&err_addr)) != 0) {
188                                 diag_printf
189                                     ("UBNT_FW: Can't program region at %p: %s\n",
190                                      err_addr, flash_errmsg(stat));
191                                 return -1;
192                         }
193                         addPartition(fwp->header->name, base,
194                                      ntohl(fwp->header->memaddr),
195                                      ntohl(fwp->header->entryaddr),
196                                      ntohl(fwp->header->part_size),
197                                      ntohl(fwp->header->data_size));
198                 }
199                 addPartition("cfg",
200                              ((unsigned int)flash_end + 1) -
201                              (flash_block_size * 3), 0, 0, 0x10000, 0x10000);
202
203                 fis_update_directory();
204                 diag_printf("UBNT_FW: flashing done\n");
205         }
206
207         return 0;
208 }
Note: See TracBrowser for help on using the browser.