summaryrefslogtreecommitdiff
path: root/gpxe/src/proto/fsp.c
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2008-03-26 16:25:35 -0700
committerH. Peter Anvin <hpa@zytor.com>2008-03-26 16:25:35 -0700
commit9eddd22a7b53b1d02fbae0d987df8af122924248 (patch)
tree882f5152880b0b1aa2d7a0619d30065acc69fb16 /gpxe/src/proto/fsp.c
parentbbb8f15936b851e6a0ef6f7bb2c95197bff35994 (diff)
downloadsyslinux-9eddd22a7b53b1d02fbae0d987df8af122924248.tar.gz
Add gPXE into the source tree; build unified imagesyslinux-3.70-pre7
Diffstat (limited to 'gpxe/src/proto/fsp.c')
-rw-r--r--gpxe/src/proto/fsp.c243
1 files changed, 243 insertions, 0 deletions
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<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