123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243 |
- /*********************************************************************\
- * Copyright (c) 2005 by Radim Kolar (hsn-sendmail.cz) *
- * *
- * You may copy or modify this file in any manner you wish, provided *
- * that this notice is always included, and that you hold the author *
- * harmless for any loss or damage resulting from the installation or *
- * use of this software. *
- * *
- * This file provides support for FSP v2 protocol written from scratch *
- * by Radim Kolar, FSP project leader. *
- * *
- * ABOUT FSP *
- * FSP is a lightweight file transfer protocol and is being used for *
- * booting, Internet firmware updates, embedded devices and in *
- * wireless applications. FSP is very easy to implement; contact Radim *
- * Kolar if you need hand optimized assembler FSP stacks for various *
- * microcontrollers, CPUs or consultations. *
- * http://fsp.sourceforge.net/ *
- * *
- * REVISION HISTORY *
- * 1.0 2005-03-17 rkolar Initial coding *
- * 1.1 2005-03-24 rkolar We really need to send CC_BYE to the server *
- * at end of transfer, because next stage boot *
- * loader is unable to contact FSP server *
- * until session timeouts. *
- * 1.2 2005-03-26 rkolar We need to query filesize in advance, *
- * because NBI loader do not reads file until *
- * eof is reached.
- * REMARKS *
- * there is no support for selecting port number of fsp server, maybe *
- * we should parse fsp:// URLs in boot image filename. *
- * this implementation has filename limit 255 chars. *
- \*********************************************************************/
-
- #ifdef DOWNLOAD_PROTO_FSP
-
- #define FSP_PORT 21
-
- /* FSP commands */
- #define CC_GET_FILE 0x42
- #define CC_BYE 0x4A
- #define CC_ERR 0x40
- #define CC_STAT 0x4D
-
- /* etherboot limits */
- #define FSP_MAXFILENAME 255
-
- struct fsp_info {
- in_addr server_ip;
- uint16_t server_port;
- uint16_t local_port;
- const char *filename;
- int (*fnc)(unsigned char *, unsigned int, unsigned int, int);
- };
-
- struct fsp_header {
- uint8_t cmd;
- uint8_t sum;
- uint16_t key;
- uint16_t seq;
- uint16_t len;
- uint32_t pos;
- } PACKED;
-
- #define FSP_MAXPAYLOAD (ETH_MAX_MTU - \
- (sizeof(struct iphdr) + sizeof(struct udphdr) + sizeof(struct fsp_header)))
-
- static struct fsp_request {
- struct iphdr ip;
- struct udphdr udp;
- struct fsp_header fsp;
- unsigned char data[FSP_MAXFILENAME + 1 + 2];
- } request;
-
- struct fsp_reply {
- struct iphdr ip;
- struct udphdr udp;
- struct fsp_header fsp;
- unsigned char data[FSP_MAXPAYLOAD];
- } PACKED;
-
-
- static int await_fsp(int ival, void *ptr, unsigned short ptype __unused,
- struct iphdr *ip, struct udphdr *udp)
- {
- if(!udp)
- return 0;
- if (ip->dest.s_addr != arptable[ARP_CLIENT].ipaddr.s_addr)
- return 0;
- if (ntohs(udp->dest) != ival)
- return 0;
- if (ntohs(udp->len) < 12+sizeof(struct udphdr))
- return 0;
- return 1;
- }
-
- static int proto_fsp(struct fsp_info *info)
- {
- uint32_t filepos;
- uint32_t filelength=0;
- int i,retry;
- uint16_t reqlen;
- struct fsp_reply *reply;
- int block=1;
-
- /* prepare FSP request packet */
- filepos=0;
- i=strlen(info->filename);
- if(i>FSP_MAXFILENAME)
- {
- printf("Boot filename is too long.\n");
- return 0;
- }
- strcpy(request.data,info->filename);
- *(uint16_t *)(request.data+i+1)=htons(FSP_MAXPAYLOAD);
- request.fsp.len=htons(i+1);
- reqlen=i+3+12;
-
- rx_qdrain();
- retry=0;
-
- /* main loop */
- for(;;) {
- int sum;
- long timeout;
-
- /* query filelength if not known */
- if(filelength == 0)
- request.fsp.cmd=CC_STAT;
-
- /* prepare request packet */
- request.fsp.pos=htonl(filepos);
- request.fsp.seq=random();
- request.fsp.sum=0;
- for(i=0,sum=reqlen;i<reqlen;i++)
- {
- sum += ((uint8_t *)&request.fsp)[i];
- }
- request.fsp.sum= sum + (sum >> 8);
- /* send request */
- if (!udp_transmit(info->server_ip.s_addr, info->local_port,
- info->server_port, sizeof(request.ip) +
- sizeof(request.udp) + reqlen, &request))
- return (0);
- /* wait for retry */
- #ifdef CONGESTED
- timeout =
- rfc2131_sleep_interval(filepos ? TFTP_REXMT : TIMEOUT, retry);
- #else
- timeout = rfc2131_sleep_interval(TIMEOUT, retry);
- #endif
- retry++;
- if (!await_reply(await_fsp, info->local_port, NULL, timeout))
- continue;
- reply=(struct fsp_reply *) &nic.packet[ETH_HLEN];
- /* check received packet */
- if (reply->fsp.seq != request.fsp.seq)
- continue;
- reply->udp.len=ntohs(reply->udp.len)-sizeof(struct udphdr);
- if(reply->udp.len < ntohs(reply->fsp.len) + 12 )
- continue;
- sum=-reply->fsp.sum;
- for(i=0;i<reply->udp.len;i++)
- {
- sum += ((uint8_t *)&(reply->fsp))[i];
- }
- sum = (sum + (sum >> 8)) & 0xff;
- if(sum != reply->fsp.sum)
- {
- printf("FSP checksum failed. computed %d, but packet has %d.\n",sum,reply->fsp.sum);
- continue;
- }
- if(reply->fsp.cmd == CC_ERR)
- {
- printf("\nFSP error: %s",info->filename);
- if(reply->fsp.len)
- printf(" [%s]",reply->data);
- printf("\n");
- return 0;
- }
- if(reply->fsp.cmd == CC_BYE && filelength == 1)
- {
- info->fnc(request.data,block,1,1);
- return 1;
- }
- if(reply->fsp.cmd == CC_STAT)
- {
- if(reply->data[8] == 0)
- {
- /* file not found, etc. */
- filelength=0xffffffff;
- } else
- {
- filelength= ntohl(*((uint32_t *)&reply->data[4]));
- }
- request.fsp.cmd = CC_GET_FILE;
- request.fsp.key = reply->fsp.key;
- retry=0;
- continue;
- }
-
- if(reply->fsp.cmd == CC_GET_FILE)
- {
- if(ntohl(reply->fsp.pos) != filepos)
- continue;
- request.fsp.key = reply->fsp.key;
- retry=0;
- i=ntohs(reply->fsp.len);
- if(i == 1)
- {
- request.fsp.cmd=CC_BYE;
- request.data[0]=reply->data[0];
- continue;
- }
- /* let last byte alone */
- if(i >= filelength)
- i = filelength - 1;
- if(!info->fnc(reply->data,block++,i,0))
- return 0;
- filepos += i;
- filelength -= i;
- }
- }
-
- return 0;
- }
-
- int url_fsp(const char *name, int (*fnc)(unsigned char *, unsigned int, unsigned int, int))
- {
- struct fsp_info info;
- /* Set the defaults */
- info.server_ip.s_addr = arptable[ARP_SERVER].ipaddr.s_addr;
- info.server_port = FSP_PORT;
- info.local_port = 1024 + random() & 0xfbff;
- info.fnc = fnc;
-
- /* Now parse the url */
- /* printf("fsp-URI: [%s]\n", name); */
- /* quick hack for now */
- info.filename=name;
- return proto_fsp(&info);
- }
- #endif
|