From 9eddd22a7b53b1d02fbae0d987df8af122924248 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Wed, 26 Mar 2008 16:25:35 -0700 Subject: Add gPXE into the source tree; build unified image --- gpxe/src/proto/fsp.c | 243 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 243 insertions(+) create mode 100644 gpxe/src/proto/fsp.c (limited to 'gpxe/src/proto/fsp.c') diff --git a/gpxe/src/proto/fsp.c b/gpxe/src/proto/fsp.c new file mode 100644 index 00000000..9a10991d --- /dev/null +++ b/gpxe/src/proto/fsp.c @@ -0,0 +1,243 @@ + /*********************************************************************\ + * 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> 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;iudp.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 -- cgit v1.2.1