RT-AC66 3.0.0.4.374.130 core
[tomato.git] / release / src-rt-6.x / cfe / cfe / net / net_http.c
bloba7b639b5e5951756251d7ef0a3e288e5149ca846
1 /* *********************************************************************
2 * Broadcom Common Firmware Environment (CFE)
3 *
4 * HTTP Protocol File: net_http.c
5 *
6 * This file contains a very simple TCP and HTTP. The basic goals of this
7 * tcp are to be "good enough for firmware." We try to be
8 * correct in our protocol implementation, but not very fancy.
9 * In particular, we don't deal with out-of-order segments,
10 * we don't hesitate to copy data more then necessary, etc.
11 * We strive to implement important protocol features
12 * like slow start, nagle, etc., but even these things are
13 * subsetted and simplified as much as possible.
15 * Author:
17 *********************************************************************
19 * Copyright 2000,2001,2002,2003
20 * Broadcom Corporation. All rights reserved.
22 * This software is furnished under license and may be used and
23 * copied only in accordance with the following terms and
24 * conditions. Subject to these conditions, you may download,
25 * copy, install, use, modify and distribute modified or unmodified
26 * copies of this software in source and/or binary form. No title
27 * or ownership is transferred hereby.
29 * 1) Any source code used, modified or distributed must reproduce
30 * and retain this copyright notice and list of conditions
31 * as they appear in the source file.
33 * 2) No right is granted to use any trade name, trademark, or
34 * logo of Broadcom Corporation. The "Broadcom Corporation"
35 * name may not be used to endorse or promote products derived
36 * from this software without the prior written permission of
37 * Broadcom Corporation.
39 * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
40 * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
41 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
42 * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
43 * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
44 * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
45 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
46 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
47 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
48 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
49 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
50 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
51 * THE POSSIBILITY OF SUCH DAMAGE.
52 ********************************************************************* */
54 #include "lib_types.h"
55 #include "lib_string.h"
56 #include "lib_queue.h"
57 #include "lib_malloc.h"
58 #include "lib_printf.h"
59 #include "lib_scanf.h"
60 #include <bcmendian.h>
61 #include "net_ebuf.h"
62 #include "net_ether.h"
64 #include "net_ip.h"
65 #include "net_ip_internal.h"
67 #include "cfe_iocb.h"
68 #include "cfe_devfuncs.h"
69 #include "cfe_ioctl.h"
70 #include "cfe_timer.h"
71 #include "cfe_error.h"
72 #include "cfe.h"
73 #include "cfe_flashimage.h"
75 #include "net_http.h"
76 #include <trxhdr.h>
78 #ifndef NULL
79 #define NULL (void *)0
80 #endif
82 /* The HTTP server states: */
83 #define HTTP_NOT_READY 0
84 #define HTTP_NOGET 1
85 #define HTTP_FILE 2
86 #define HTTP_TEXT 3
87 #define HTTP_FUNC 4
88 #define HTTP_END 5
89 #define HTTP_UPLOAD_BOOT 6
90 #define HTTP_UPLOAD_EXE 7
92 #ifdef DEBUG
93 #define PRINT(x) printf("%s", x)
94 #define PRINTLN(x) printf("%s\n", x)
95 #else
96 #define PRINT(x)
97 #define PRINTLN(x)
98 #endif /* DEBUG */
101 struct http_info_s {
102 void *ti_ref; /* ref data for IP layer */
103 ip_info_t *ti_ipinfo; /* IP layer handle */
104 tcb_t tcb; /* TCB */
105 uint32_t ti_iss; /* initial sequence number */
108 #define UL_HEADER 0
109 #define UL_MULTIPART 1
110 #define UL_UPDATE 2
111 struct httpd_state {
112 unsigned char state;
113 unsigned char ul_state;
114 struct http_info_s *ti;
115 tcb_t *tcb;
116 char eval[256];
117 char *uip_appdata;
118 int uip_len;
119 char page_buf[1024];
120 int page_len;
121 char *load_addr;
122 int load_limit;
123 int ul_len;
124 int ul_cnt;
125 int ul_offset;
128 static struct httpd_state httpd_state;
131 #define ISO_G 0x47
132 #define ISO_E 0x45
133 #define ISO_T 0x54
134 #define ISO_slash 0x2f
135 #define ISO_c 0x63
136 #define ISO_g 0x67
137 #define ISO_i 0x69
138 #define ISO_space 0x20
139 #define ISO_nl 0x0a
140 #define ISO_cr 0x0d
141 #define ISO_a 0x61
142 #define ISO_t 0x74
143 #define ISO_hash 0x23
144 #define ISO_period 0x2e
146 /* Forward Declarations */
147 static int _tcphttp_rx_callback(void *ref, ebuf_t *buf, uint8_t *destaddr, uint8_t *srcaddr);
148 static void _tcphttp_protosend(http_info_t *ti, tcb_t *tcb);
150 static int httpd_accept(struct httpd_state *hs, http_info_t *ti, tcb_t *tcb);
151 static int httpd_appcall(struct httpd_state *hs);
152 static void httpd_defercall(struct httpd_state *hs);
153 static void httpd_page_init(struct httpd_state *hs);
154 static void httpd_page_end(struct httpd_state *hs, int rc, int f);
155 static int httpd_do_cmd(struct httpd_state *hs);
156 static int httpd_load_program(struct httpd_state *hs);
157 static int httpd_do_ul(struct httpd_state *hs);
158 static void httpd_printf(struct httpd_state *hs, char *templat, ...);
159 static int trx_validate(uint8_t *ptr, int *insize);
160 static int httpd_write_flash(char *flashdev, uint8 *load_addr, int len);
162 extern int ui_docommands(char *buf);
163 extern int flash_validate(uint8_t *ptr, int bufsize, int insize, uint8_t **outptr, int *outsize);
164 extern void ui_get_flash_buf(uint8_t **bufptr, int *bufsize);
165 extern unsigned int flash_crc32(const unsigned char *databuf, unsigned int datalen);
167 #ifdef _TCP_DEBUG_
168 int _tcp_dumpflags = 1;
169 #else
170 int _tcp_dumpflags = 0;
171 #endif /* _TCP_DEBUG */
174 * _tcp_init(ipi,ref)
176 * Initialize the TCP module. We set up our data structures
177 * and register ourselves with the IP layer.
179 * Input parameters:
180 * ipi - IP information
181 * ref - will be passed back to IP as needed
183 * Return value:
184 * http_info_t structure, or NULL if problems
186 http_info_t *
187 _tcphttp_init(ip_info_t *ipi, void *ref)
189 extern int32_t _getticks(void); /* return value of CP0 COUNT */
190 http_info_t *ti = NULL;
191 tcb_t *tcb = NULL;
193 ti = (http_info_t *)KMALLOC(sizeof(http_info_t), 0);
194 if (!ti)
195 return NULL;
197 ti->ti_ref = ref;
198 ti->ti_ipinfo = ipi;
201 * Initialize the TCB
203 tcb = &ti->tcb;
204 memset(tcb, 0, sizeof(tcb_t));
207 * Set up initial state.
209 _tcp_setstate(tcb, TCPSTATE_CLOSED);
212 * Set up the initial sequence number
214 ti->ti_iss = (uint32_t)_getticks();
217 * Register our protocol with IP
220 _ip_register(ipi, IPPROTO_TCP, _tcphttp_rx_callback, ti);
222 httpd_state.state = HTTP_NOGET;
223 return ti;
227 * _tcp_uninit(info)
229 * De-initialize the TCP layer, unregistering from the IP layer.
231 * Input parameters:
232 * info - our http_info_t, from _tcp_init()
234 * Return value:
235 * nothing
237 void
238 _tcphttp_uninit(http_info_t *info)
241 * Deregister with IP
243 _ip_deregister(info->ti_ipinfo, IPPROTO_TCP);
246 * Free up the info structure
248 KFREE(info);
250 /* Clear protocol */
251 memset(&httpd_state, 0, sizeof(httpd_state));
256 * _tcp_protosend(ti,tcb)
258 * Transmit "protocol messages" on the tcb. This is used for
259 * sending SYN, FIN, ACK, and other control packets.
261 * Input parameters:
262 * ti - tcp infomration
263 * tcb - tcb we're interested in
265 * Return value:
266 * nothing
268 static void
269 _tcphttp_protosend(http_info_t *ti, tcb_t *tcb)
271 ebuf_t *b;
272 uint16_t flags;
273 uint8_t *cksumptr;
274 uint8_t *tcphdr;
275 uint16_t cksum;
276 int hdrlen;
277 uint8_t pseudoheader[12];
278 int tcplen = 0;
281 * Allocate a buffer and remember the pointer to where
282 * the header starts.
284 b = _ip_alloc(ti->ti_ipinfo);
285 if (!b)
286 return;
288 tcphdr = ebuf_ptr(b) + ebuf_length(b);
291 * Build the TCP header
293 flags = tcb->tcb_txflags | (TCPHDRFLG(TCP_HDR_LENGTH));
294 hdrlen = TCP_HDR_LENGTH;
297 * Fill in the fields according to the RFC.
299 ebuf_append_u16_be(b, tcb->tcb_lclport); /* Local and remote ports */
300 ebuf_append_u16_be(b, tcb->tcb_peerport);
301 ebuf_append_u32_be(b, tcb->tcb_sendnext); /* sequence and ack numbers */
302 ebuf_append_u32_be(b, tcb->tcb_rcvnext);
303 ebuf_append_u16_be(b, flags); /* Flags */
304 ebuf_append_u16_be(b, tcb->tcb_sendwindow); /* Window size */
305 cksumptr = ebuf_ptr(b) + ebuf_length(b);
306 ebuf_append_u16_be(b, 0); /* dummy checksum for calculation */
307 ebuf_append_u16_be(b, 0); /* Urgent Pointer (not used) */
309 tcplen = tcb->txlen;
310 if (tcb->txlen > 0) {
311 memcpy(b->eb_ptr + b->eb_length, tcb->tcb_txbuf, tcb->txlen);
312 b->eb_length += tcb->txlen;
313 tcb->tcb_txbuf = NULL;
314 tcb->txlen = 0;
318 * Build the pseudoheader, which is part of the checksum calculation
320 _ip_getaddr(ti->ti_ipinfo, &pseudoheader[0]);
321 memcpy(&pseudoheader[4], tcb->tcb_peeraddr, IP_ADDR_LEN);
322 pseudoheader[8] = 0;
323 pseudoheader[9] = IPPROTO_TCP;
324 pseudoheader[10] = ((tcplen+hdrlen) >> 8) & 0xFF;
325 pseudoheader[11] = ((tcplen+hdrlen) & 0xFF);
328 * Checksum the packet and insert the checksum into the header
330 cksum = ip_chksum(0, pseudoheader, sizeof(pseudoheader));
331 cksum = ip_chksum(cksum, tcphdr, tcplen + hdrlen);
332 cksum = ~cksum;
333 cksumptr[0] = (cksum >> 8) & 0xFF;
334 cksumptr[1] = (cksum & 0xFF);
337 * Transmit the packet. The layer below us will free it.
339 _ip_send(ti->ti_ipinfo, b, tcb->tcb_peeraddr, IPPROTO_TCP);
343 * _tcphttp_rx_callback(ref,buf,destaddr,srcaddr)
345 * The IP layer calls this routine when a TCP packet is received.
346 * We dispatch the packet to appropriate handlers from here.
348 * Input parameters:
349 * ref - our tcp information (held by the ip stack for us)
350 * buf - the ebuf that we received
351 * destaddr,srcaddr - destination and source IP addresses
353 * Return value:
354 * ETH_DROP or ETH_KEEP, depending if we keep the packet or not
356 static int
357 _tcphttp_rx_callback(void *ref, ebuf_t *buf, uint8_t *destaddr, uint8_t *srcaddr)
359 uint8_t pseudoheader[12];
360 int tcplen;
361 uint16_t calccksum;
362 uint16_t origcksum;
363 uint8_t *tcphdr;
364 uint16_t srcport;
365 uint16_t dstport;
366 uint32_t seqnum;
367 uint32_t acknum;
368 uint16_t window;
369 uint16_t flags;
370 http_info_t *ti = (http_info_t *)ref;
371 tcb_t *tcb = &ti->tcb;
372 uint32_t tt;
373 uint8_t *bp;
374 int t = -1;
375 int plen = 0;
377 if (httpd_state.state == HTTP_NOT_READY)
378 return ETH_DROP;
380 * get a pointer to the TCP header
382 tcplen = ebuf_length(buf);
383 tcphdr = ebuf_ptr(buf);
386 * construct the pseudoheader for the cksum calculation
388 memcpy(&pseudoheader[0], srcaddr, IP_ADDR_LEN);
389 memcpy(&pseudoheader[4], destaddr, IP_ADDR_LEN);
390 pseudoheader[8] = 0;
391 pseudoheader[9] = IPPROTO_TCP;
392 pseudoheader[10] = (tcplen >> 8) & 0xFF;
393 pseudoheader[11] = (tcplen & 0xFF);
395 origcksum = ((uint16_t)tcphdr[16] << 8) | (uint16_t)tcphdr[17];
396 tcphdr[16] = tcphdr[17] = 0;
398 calccksum = ip_chksum(0, pseudoheader, sizeof(pseudoheader));
399 calccksum = ip_chksum(calccksum, tcphdr, tcplen);
400 calccksum = ~calccksum;
401 if (calccksum != origcksum)
402 return ETH_DROP;
404 /* Read the other TCP header fields from the packet */
405 ebuf_get_u16_be(buf, srcport);
406 ebuf_get_u16_be(buf, dstport);
407 if (dstport != 80) {
408 DEBUGMSG(("TCP dport is not 80\n"));
409 return ETH_DROP;
412 ebuf_get_u32_be(buf, seqnum);
413 ebuf_get_u32_be(buf, acknum);
414 ebuf_get_u16_be(buf, flags);
415 ebuf_get_u16_be(buf, window);
417 /* skip checksum and urgent pointer */
418 ebuf_skip(buf, 4);
420 /* Skip options in header */
421 if (TCPHDRSIZE(flags) < TCP_HDR_LENGTH)
422 return ETH_DROP;
424 ebuf_skip(buf, (TCPHDRSIZE(flags) - TCP_HDR_LENGTH));
426 switch (tcb->tcb_state) {
427 case TCPSTATE_CLOSED:
428 if (flags & TCPFLG_SYN) {
429 rec_syn:
430 if (tcb->tcb_txbuf) {
431 tcb->tcb_txbuf = NULL;
432 tcb->txlen = 0;
434 if (tcb->tcb_rxbuf) {
435 KFREE(tcb->tcb_rxbuf);
436 tcb->tcb_rxbuf = NULL;
437 tcb->rxlen = 0;
439 tcb->tcb_txflags = TCPFLG_SYN | TCPFLG_ACK;
440 tcb->tcb_rcvnext = seqnum + 1;
441 tcb->tcb_sendnext = ti->ti_iss;
442 tcb->tcb_lclport = dstport;
443 tcb->tcb_peerport = srcport;
444 _tcp_setstate(tcb, TCPSTATE_SYN_SENT);
445 tcb->wait_ack = 1;
447 memcpy(tcb->tcb_peeraddr, srcaddr, IP_ADDR_LEN);
449 tcb->tcb_sendwindow = 1500;
450 _tcphttp_protosend(ti, tcb);
452 break;
454 case TCPSTATE_SYN_SENT:
455 if (flags & TCPFLG_ACK) {
456 if (tcb->tcb_rcvnext != seqnum)
457 goto send_ack_nodata;
459 tt = tcb->tcb_sendnext;
460 tt += tcb->wait_ack;
461 if (acknum == tt) {
462 tcb->tcb_sendnext = tt;
463 tcb->wait_ack = 0;
464 httpd_accept(&httpd_state, ti, tcb);
465 _tcp_setstate(tcb, TCPSTATE_ESTABLISHED);
468 else if (flags & TCPFLG_SYN)
469 goto rec_syn;
470 break;
472 case TCPSTATE_ESTABLISHED:
473 /* swap src,dst port */
474 if (srcport != tcb->tcb_peerport) {
475 break;
477 if (tcb->tcb_rcvnext != seqnum) {
478 printf("tcb->tcb_rcvnext=%08x seqnum=%08x\n", tcb->tcb_rcvnext, seqnum);
479 goto send_ack_nodata;
482 tt = tcb->tcb_sendnext;
483 tt += tcb->wait_ack;
484 if (acknum != tt) {
485 printf("acknum=%x expect=%08x\n", acknum, tt);
486 break;
488 else {
489 tcb->tcb_sendnext = tt;
490 tcb->rxflag = flags;
493 * Figure out how much we're going to take. This should not
494 * exceed our buffer size because we advertised a window
495 * only big enough to fill our buffer.
497 bp = ebuf_ptr(buf); /* pointer to TCP data */
498 tt = ebuf_remlen(buf); /* Size of TCP data */
499 tcb->rxlen = tt;
501 tcb->tcb_rcvnext += tt;
502 tcb->tcb_rxbuf = KMALLOC(tt, 0);
503 memcpy(tcb->tcb_rxbuf, bp, tt);
505 t = httpd_appcall(&httpd_state);
506 if (t != 0) {
507 tcb->tcb_txflags = TCPFLG_ACK|TCPFLG_FIN;
508 tcb->wait_ack = 1;
509 _tcp_setstate(tcb, TCPSTATE_FINWAIT_1);
510 goto send_ack_nodata;
513 plen = tcb->txlen;
514 tcb->wait_ack = plen;
515 tcb->tcb_txflags = TCPFLG_ACK;
517 if (tcb->tcb_state == TCPSTATE_FINWAIT_1) {
518 tcb->tcb_txflags |= TCPFLG_FIN;
520 goto send_ack;
522 break;
524 case TCPSTATE_FINWAIT_1:
525 default:
526 _tcp_setstate(tcb, TCPSTATE_CLOSED);
527 tcb->tcb_sendnext = acknum;
528 tcb->tcb_txflags = TCPFLG_RST;
529 goto send_ack_nodata;
532 if (tcb->tcb_rxbuf)
534 KFREE(tcb->tcb_rxbuf);
535 tcb->tcb_rxbuf = NULL;
536 tcb->rxlen = 0;
539 return ETH_DROP;
541 send_ack_nodata:
542 plen = 0;
544 send_ack:
545 if (plen)
546 tcb->tcb_sendwindow = 0;
547 else
548 tcb->tcb_sendwindow = 1500;
550 _tcphttp_protosend(ti, tcb);
552 if (tcb->tcb_rxbuf) {
553 KFREE(tcb->tcb_rxbuf);
554 tcb->tcb_rxbuf = NULL;
555 tcb->rxlen = 0;
558 httpd_defercall(&httpd_state);
559 return ETH_DROP;
562 static int
563 httpd_accept(struct httpd_state *hs, http_info_t *ti, tcb_t *tcb)
565 memset(hs, 0, sizeof(*hs));
567 hs->state = HTTP_NOGET;
568 hs->ti = ti;
569 hs->tcb = tcb;
570 return 0;
573 static inline void
574 httpd_flush(struct httpd_state *hs)
576 tcb_t *tcb = hs->tcb;
578 tcb->tcb_txbuf = hs->page_buf;
579 tcb->txlen = hs->page_len;
580 _tcp_setstate(tcb, TCPSTATE_FINWAIT_1);
583 static int
584 httpd_appcall(struct httpd_state *hs)
586 /* Save receive buffer and length */
587 hs->uip_appdata = hs->tcb->tcb_rxbuf;
588 hs->uip_len = hs->tcb->rxlen;
589 if (hs->uip_len <= 0)
590 return 0;
592 switch (hs->state) {
593 case HTTP_UPLOAD_EXE:
594 return httpd_do_ul(hs);
596 case HTTP_NOGET:
597 if (strncmp("POST ", hs->uip_appdata, 5) == 0) {
598 /* 'POST */
599 if (strncmp("f2", hs->uip_appdata+6, 2) == 0) {
600 hs->state = HTTP_UPLOAD_EXE;
601 httpd_page_init(hs);
603 /* Do http upload */
604 return httpd_do_ul(hs);
607 else if (strncmp("GET ", hs->uip_appdata, 4) == 0) {
608 if (!strncmp("do", hs->uip_appdata+5, 2)) {
609 hs->state = HTTP_FUNC;
610 httpd_page_init(hs);
612 /* Do commands */
613 return httpd_do_cmd(hs);
616 else {
617 /* If it isn't a GET, we abort the connection. */
618 return -1;
621 /* Send mini-web index page out */
622 httpd_page_init(hs);
623 httpd_printf(hs,
624 "<table border=0 cellpadding=0 cellspacing=0 bgcolor=#306498>\r\n"
625 "<tr><td height=57 width=600>\r\n"
626 "<font face=Arial size=6 color=#ffffff>ASUSTeK - CFE miniWeb Server</font>\r\n"
627 "</td></tr>\r\n"
628 "</table><br>\r\n"
629 "<form action=f2.htm method=post encType=multipart/form-data>\r\n"
630 "Firmware File&nbsp\r\n"
631 "<input type=file size=35 name=files>\r\n"
632 "<input type=submit value=Upload><br>\r\n"
633 "</form>\r\n"
634 "<form action=do.htm method=get>\r\n"
635 "<br>Command:<br><a href=do.htm?cmd=reboot>Reboot.</a>\r\n"
636 "<br><a href=do.htm?cmd=nvram+erase>Restore default NVRAM values.</a>\r\n"
637 "</form>\r\n");
638 httpd_page_end(hs, 0, 0);
639 return 0;
641 default:
642 break;
645 return 0;
648 static void
649 httpd_defercall(struct httpd_state *hs)
651 http_info_t *ti = hs->ti;
652 tcb_t *tcb = hs->tcb;
653 #ifdef CFG_NFLASH
654 char flashdev[12];
655 #else
656 char *flashdev = "flash1.trx";
657 #endif
659 if (hs->state == HTTP_UPLOAD_EXE) {
660 if (hs->ul_state == UL_UPDATE) {
661 /* Send reset */
662 tcb->tcb_sendwindow = 0;
663 _tcp_setstate(tcb, TCPSTATE_CLOSED);
664 tcb->tcb_txflags = TCPFLG_RST;
665 _tcphttp_protosend(ti, tcb);
667 #ifdef CFG_NFLASH
668 ui_get_trx_flashdev(flashdev);
669 #endif
670 /* Write to flash */
671 httpd_write_flash(flashdev, (uint8 *)hs->load_addr, hs->ul_offset);
672 hs->ul_state = 0;
673 ui_docommands("reboot");
676 else if (hs->state == HTTP_FUNC) {
677 if (hs->eval[0]) {
678 xprintf("%s command executed\n", hs->eval);
679 ui_docommands(hs->eval);
681 /* End of doing command */
682 hs->eval[0] = 0;
688 * ul_index[0] : http header end
689 * ul_index[1] : multipart[0] header end
691 static int ul_index[2];
693 static int
694 read_ul_headers(struct httpd_state *hs)
696 int i, j;
697 char *ul_header = hs->load_addr;
698 char *end;
701 * Gather packets together to overcome the problem
702 * when headers crosses packet boundary.
704 if ((hs->ul_offset + hs->uip_len) >= 4096)
705 return -1;
707 memcpy(&ul_header[hs->ul_offset], hs->uip_appdata, hs->uip_len);
708 hs->ul_offset += hs->uip_len;
709 ul_header[hs->ul_offset] = 0;
711 /* Search for two <CR><LF><CR><LF> */
712 j = 0;
713 ul_index[0] = ul_index[1] = 0;
714 for (i = 0; i < hs->ul_offset; i++) {
715 end = &ul_header[i];
717 /* Search end of headers */
718 if (*(end+0) == ISO_cr && *(end+1) == ISO_nl &&
719 *(end+2) == ISO_cr && *(end+3) == ISO_nl) {
720 i += 4;
721 ul_index[j] = i;
722 if (++j == 2)
723 break;
726 if (ul_index[1] == 0)
727 return 0;
729 return 1;
732 static int
733 parse_ul_headers(struct httpd_state *hs)
735 int i;
736 char *ul_header = hs->load_addr;
737 char *line;
739 for (i = 0; i < ul_index[1]; i++) {
740 line = &ul_header[i];
742 if (*line == ISO_cr || *line == ISO_nl) {
743 /* Null end this line */
744 *line = 0;
746 else {
747 /* to upper */
748 *line = *line | 0x20;
752 /* Get necessary name:value */
753 for (i = 0; i < ul_index[0]; i++) {
754 line = &ul_header[i];
756 if (*line == 0)
757 continue;
759 if (!strncmp("content-length:", line, 15)) {
760 sscanf(line+15, "%d", &hs->ul_len);
764 return 0;
768 * Reads one line and decides what to do next.
770 static int
771 httpd_load_program(struct httpd_state *hs)
773 int rc;
774 int i, j;
776 /* Process headers for content-length, and content-type */
777 if (hs->ul_state == 0) {
779 * Read http headers and
780 * multipart headers
782 rc = read_ul_headers(hs);
783 if (rc <= 0)
784 return rc;
787 * Parse http headers to get
788 * content_length and content_type.
790 parse_ul_headers(hs);
793 /* Copy remaining data to load_addr */
794 hs->ul_cnt = hs->ul_offset - ul_index[0];
795 hs->ul_offset -= ul_index[1];
798 * Do memmove from load_addr[i],
799 * where i is the beginning of
800 * upload file.
802 i = ul_index[1];
803 for (j = 0; j < hs->ul_offset; j++)
804 hs->load_addr[j] = hs->load_addr[i+j];
806 hs->ul_state++;
808 else if (hs->ul_state == UL_MULTIPART) {
809 if ((hs->ul_offset + hs->uip_len) > hs->load_limit ||
810 hs->ul_cnt >= hs->ul_len) {
811 return -1;
814 /* Copy data */
815 memcpy(hs->load_addr + hs->ul_offset, hs->uip_appdata, hs->uip_len);
816 hs->ul_offset += hs->uip_len;
817 hs->load_addr[hs->ul_offset] = 0;
819 hs->ul_cnt += hs->uip_len;
820 if (hs->ul_cnt < hs->ul_len)
821 return 0;
823 /* Let trx_validate() handle image size */
824 hs->ul_state++;
827 if (hs->ul_state == UL_UPDATE) {
828 char *resp;
830 httpd_printf(hs,
831 "<pre>Receive file size=%d<br><font face=Arial size=5>",
832 hs->ul_offset);
834 * Do trx header check.
836 rc = trx_validate((uint8_t *)hs->load_addr, &hs->ul_offset);
837 switch (rc) {
838 case 0:
839 resp = "Upload completed. System is going to reboot.<br>Please wait a few moments.";
840 break;
842 case CFE_ERR_DEVNOTFOUND:
843 resp = "Could not open flash device.";
844 hs->ul_state = 0;
845 break;
847 default:
848 resp = "The file transferred is not a valid firmware image.";
849 hs->ul_state = 0;
850 break;
853 httpd_printf(hs, "%s</font></pre>", resp);
854 httpd_page_end(hs, 0, 1);
856 return (rc == 0 ? 0 : -1);
859 return 0;
863 * Parse the command issued by the mini Web
865 static char *
866 httpd_cmd_parse(struct httpd_state *hs)
868 char buf[256];
869 int len;
870 char *cmd;
871 char *p;
872 int c;
874 /* Work on temp buffer */
875 len = hs->uip_len > sizeof(buf)-1 ? sizeof(buf)-1 : hs->uip_len;
876 memcpy(buf, hs->uip_appdata, len);
877 buf[len] = 0;
879 /* process GET do.htm?cmd= */
880 p = buf;
881 while (*p != '=')
882 p++;
884 if (*p == '=')
885 p++;
887 /* Parse command */
888 cmd = p;
889 while ((c = *p & 0xff) != 0 ) {
890 switch (c) {
891 case ' ':
892 *p = 0;
893 return cmd;
894 case '%':
895 sscanf(p+1, "%02x", &c);
896 *p++ = c;
899 * Replace with white space
901 *p++ = ' ';
902 *p++ = ' ';
903 break;
904 case '+':
905 *p = ' ';
906 /* fall through */
907 default:
908 p++;
909 break;
913 /* Return null command */
914 return p;
917 static void
918 httpd_printf(struct httpd_state *hs, char *templat, ...)
920 va_list marker;
922 /* Copy to page */
923 if (hs->page_len > sizeof(hs->page_buf) - 32)
924 return;
926 va_start(marker, templat);
927 hs->page_len += xvsprintf(hs->page_buf + hs->page_len, templat, marker);
928 va_end(marker);
931 static void
932 httpd_page_init(struct httpd_state *hs)
934 hs->page_len = 0;
935 httpd_printf(hs,
936 "HTTP/1.1 200 OK\r\n"
937 "Pragma: no-cache\r\nCache-Control: no-cache\r\n"
938 "Connection: close\r\n\r\n"
939 "<HTML><BODY>\r\n");
942 static void
943 httpd_page_end(struct httpd_state *hs, int rc, int f)
945 httpd_printf(hs,
946 "<!-- Recive file size=%d bytes-->%s</BODY></HTML>\r\n",
947 rc, f ? "<a href=""/"">Continue</a>" : "");
949 /* Flush out */
950 httpd_flush(hs);
953 static int
954 httpd_do_cmd(struct httpd_state *hs)
956 char *cmd;
957 int rc = 0;
959 cmd = httpd_cmd_parse(hs);
960 if (strcmp(cmd, "reboot") == 0 ||
961 strcmp(cmd, "nvram erase") == 0) {
963 * Defer these two comands,
964 * until sending response out.
966 strcpy(hs->eval, cmd);
968 else {
969 rc = ui_docommands(cmd);
972 /* Send response out */
973 httpd_printf(hs,
974 "<pre><font face=Arial size=5>Command %s completed.</font></pre>",
975 cmd);
977 httpd_page_end(hs, rc, 1);
978 return 0;
981 static int
982 httpd_do_ul(struct httpd_state *hs)
984 uint8_t *load_addr = NULL;
986 if (hs->load_addr == NULL) {
987 hs->load_limit = 0;
988 ui_get_flash_buf(&load_addr, &hs->load_limit);
989 hs->load_addr = (char *)load_addr;
991 hs->ul_cnt = 0;
992 hs->ul_offset = 0;
995 if (httpd_load_program(hs) == -1)
996 return -1;
998 return 0;
1001 static int
1002 httpd_write_flash(char *flashdev, uint8 *load_addr, int len)
1004 int devtype;
1005 int copysize;
1006 flash_info_t flashinfo;
1007 int res;
1008 int fh;
1009 int retlen;
1010 int offset = 0;
1011 int noerase = 0;
1012 int amtcopy;
1015 * Make sure it's a flash device.
1017 res = cfe_getdevinfo(flashdev);
1018 if (res < 0) {
1019 xprintf("Could not find flash device '%s'\n", flashdev);
1020 return -1;
1023 devtype = res & CFE_DEV_MASK;
1025 copysize = len;
1026 if (copysize == 0)
1027 return 0; /* 0 bytes, don't flash */
1030 * Open the destination flash device.
1032 fh = cfe_open(flashdev);
1033 if (fh < 0) {
1034 xprintf("Could not open device '%s'\n", flashdev);
1035 return CFE_ERR_DEVNOTFOUND;
1038 if (cfe_ioctl(fh, IOCTL_FLASH_GETINFO, (unsigned char *)&flashinfo,
1039 sizeof(flash_info_t), &res, 0) == 0) {
1040 /* Truncate write if source size is greater than flash size */
1041 if ((copysize + offset) > flashinfo.flash_size)
1042 copysize = flashinfo.flash_size - offset;
1046 * If overwriting the boot flash, we need to use the special IOCTL
1047 * that will force a reboot after writing the flash.
1049 if (flashinfo.flash_flags & FLASH_FLAG_INUSE) {
1050 #if CFG_EMBEDDED_PIC
1051 xprintf(
1052 "\n\n** DO NOT TURN OFF YOUR MACHINE UNTIL THE FLASH UPDATE COMPLETES!! **\n\n");
1053 #else
1054 #if CFG_NETWORK
1055 if (net_getparam(NET_DEVNAME)) {
1056 xprintf("Closing network.\n");
1057 net_uninit();
1059 #endif /* CFG_NETWORK */
1060 xprintf("Rewriting boot flash device '%s'\n", flashdev);
1061 xprintf("\n\n**DO NOT TURN OFF YOUR MACHINE UNTIL IT REBOOTS!**\n\n");
1062 cfe_ioctl(fh, IOCTL_FLASH_WRITE_ALL, load_addr, copysize, &retlen, 0);
1064 /* should not return */
1065 return CFE_ERR;
1066 #endif /* EMBEDDED_PIC */
1070 * Otherwise: it's not the flash we're using right
1071 * now, so we can be more verbose about things, and
1072 * more importantly, we can return to the command
1073 * prompt without rebooting!
1077 * Erase the flash, if the device requires it. Our new flash
1078 * driver does the copy/merge/erase for us.
1080 if (!noerase) {
1081 if ((devtype == CFE_DEV_FLASH) && !(flashinfo.flash_flags & FLASH_FLAG_NOERASE)) {
1082 flash_range_t range;
1083 range.range_base = offset;
1084 range.range_length = copysize;
1085 xprintf("Erasing flash...");
1086 if (cfe_ioctl(fh, IOCTL_FLASH_ERASE_RANGE, (uint8_t *)&range,
1087 sizeof(range), NULL, 0) != 0) {
1088 xprintf("Failed to erase the flash\n");
1089 cfe_close(fh);
1090 return CFE_ERR_IOERR;
1096 * Program the flash
1098 xprintf("Programming...");
1100 amtcopy = cfe_writeblk(fh, offset, load_addr, copysize);
1101 if (copysize == amtcopy) {
1102 xprintf("done. %d bytes written\n", amtcopy);
1103 res = 0;
1105 else {
1106 xprintf("Failed. %d bytes written\n", amtcopy);
1107 res = CFE_ERR_IOERR;
1111 * done!
1113 cfe_close(fh);
1114 return res;
1117 static int
1118 trx_validate(uint8_t *ptr, int *insize)
1120 struct trx_header *hdr = (struct trx_header *)ptr;
1121 uint32_t calccrc;
1122 int32 len = ltoh32(hdr->len);
1123 flash_info_t flashinfo;
1124 int fh, res;
1125 #ifdef CFG_NFLASH
1126 char flashdev[12];
1128 ui_get_trx_flashdev(flashdev);
1129 #else
1130 char *flashdev = "flash1.trx";
1131 #endif
1133 if (ltoh32(hdr->magic) != TRX_MAGIC) {
1134 xprintf("\nTRX magic number error!");
1135 return CFE_ERR;
1139 * Open the destination flash device.
1141 fh = cfe_open(flashdev);
1142 if (fh < 0) {
1143 xprintf("\nOpen device '%s' failed!", flashdev);
1144 return CFE_ERR_DEVNOTFOUND;
1147 cfe_ioctl(fh, IOCTL_FLASH_GETINFO, (unsigned char *)&flashinfo,
1148 sizeof(flash_info_t), &res, 0);
1150 cfe_close(fh);
1152 /* Do CRC check */
1153 if (len > *insize ||
1154 len > flashinfo.flash_size ||
1155 len < sizeof(struct trx_header)) {
1156 xprintf("\nTRX file size error!");
1157 return CFE_ERR;
1160 calccrc = flash_crc32(ptr + 12, len-12);
1161 if (calccrc != ltoh32(hdr->crc32)) {
1162 xprintf("\nTRX CRC error!");
1163 return CFE_ERR;
1166 *insize = len;
1167 printf("\nTRX file size = %d\n", len);
1168 return 0;