1 /*********************************************************************\
2 * Copyright (c) 2005 by Radim Kolar (hsn-sendmail.cz) *
4 * You may copy or modify this file in any manner you wish, provided *
5 * that this notice is always included, and that you hold the author *
6 * harmless for any loss or damage resulting from the installation or *
7 * use of this software. *
9 * This file provides support for FSP v2 protocol written from scratch *
10 * by Radim Kolar, FSP project leader. *
13 * FSP is a lightweight file transfer protocol and is being used for *
14 * booting, Internet firmware updates, embedded devices and in *
15 * wireless applications. FSP is very easy to implement; contact Radim *
16 * Kolar if you need hand optimized assembler FSP stacks for various *
17 * microcontrollers, CPUs or consultations. *
18 * http://fsp.sourceforge.net/ *
21 * 1.0 2005-03-17 rkolar Initial coding *
22 * 1.1 2005-03-24 rkolar We really need to send CC_BYE to the server *
23 * at end of transfer, because next stage boot *
24 * loader is unable to contact FSP server *
25 * until session timeouts. *
26 * 1.2 2005-03-26 rkolar We need to query filesize in advance, *
27 * because NBI loader do not reads file until *
30 * there is no support for selecting port number of fsp server, maybe *
31 * we should parse fsp:// URLs in boot image filename. *
32 * this implementation has filename limit 255 chars. *
33 \*********************************************************************/
35 #ifdef DOWNLOAD_PROTO_FSP
36 #include "etherboot.h"
42 #define CC_GET_FILE 0x42
47 /* etherboot limits */
48 #define FSP_MAXFILENAME 255
55 int (*fnc)(unsigned char *, unsigned int, unsigned int, int);
67 #define FSP_MAXPAYLOAD (ETH_MAX_MTU - \
68 (sizeof(struct iphdr) + sizeof(struct udphdr) + sizeof(struct fsp_header)))
70 static struct fsp_request {
73 struct fsp_header fsp;
74 unsigned char data[FSP_MAXFILENAME + 1 + 2];
80 struct fsp_header fsp;
81 unsigned char data[FSP_MAXPAYLOAD];
85 static int await_fsp(int ival, void *ptr, unsigned short ptype __unused,
86 struct iphdr *ip, struct udphdr *udp)
90 if (ip->dest.s_addr != arptable[ARP_CLIENT].ipaddr.s_addr)
92 if (ntohs(udp->dest) != ival)
94 if (ntohs(udp->len) < 12+sizeof(struct udphdr))
99 static int proto_fsp(struct fsp_info *info)
102 uint32_t filelength=0;
105 struct fsp_reply *reply;
108 /* prepare FSP request packet */
110 i=strlen(info->filename);
111 if(i>FSP_MAXFILENAME)
113 printf("Boot filename is too long.\n");
116 strcpy(request.data,info->filename);
117 *(uint16_t *)(request.data+i+1)=htons(FSP_MAXPAYLOAD);
118 request.fsp.len=htons(i+1);
129 /* query filelength if not known */
131 request.fsp.cmd=CC_STAT;
133 /* prepare request packet */
134 request.fsp.pos=htonl(filepos);
135 request.fsp.seq=random();
137 for(i=0,sum=reqlen;i<reqlen;i++)
139 sum += ((uint8_t *)&request.fsp)[i];
141 request.fsp.sum= sum + (sum >> 8);
143 if (!udp_transmit(info->server_ip.s_addr, info->local_port,
144 info->server_port, sizeof(request.ip) +
145 sizeof(request.udp) + reqlen, &request))
150 rfc2131_sleep_interval(filepos ? TFTP_REXMT : TIMEOUT, retry);
152 timeout = rfc2131_sleep_interval(TIMEOUT, retry);
155 if (!await_reply(await_fsp, info->local_port, NULL, timeout))
157 reply=(struct fsp_reply *) &nic.packet[ETH_HLEN];
158 /* check received packet */
159 if (reply->fsp.seq != request.fsp.seq)
161 reply->udp.len=ntohs(reply->udp.len)-sizeof(struct udphdr);
162 if(reply->udp.len < ntohs(reply->fsp.len) + 12 )
165 for(i=0;i<reply->udp.len;i++)
167 sum += ((uint8_t *)&(reply->fsp))[i];
169 sum = (sum + (sum >> 8)) & 0xff;
170 if(sum != reply->fsp.sum)
172 printf("FSP checksum failed. computed %d, but packet has %d.\n",sum,reply->fsp.sum);
175 if(reply->fsp.cmd == CC_ERR)
177 printf("\nFSP error: %s",info->filename);
179 printf(" [%s]",reply->data);
183 if(reply->fsp.cmd == CC_BYE && filelength == 1)
185 info->fnc(request.data,block,1,1);
188 if(reply->fsp.cmd == CC_STAT)
190 if(reply->data[8] == 0)
192 /* file not found, etc. */
193 filelength=0xffffffff;
196 filelength= ntohl(*((uint32_t *)&reply->data[4]));
198 request.fsp.cmd = CC_GET_FILE;
199 request.fsp.key = reply->fsp.key;
204 if(reply->fsp.cmd == CC_GET_FILE)
206 if(ntohl(reply->fsp.pos) != filepos)
208 request.fsp.key = reply->fsp.key;
210 i=ntohs(reply->fsp.len);
213 request.fsp.cmd=CC_BYE;
214 request.data[0]=reply->data[0];
217 /* let last byte alone */
220 if(!info->fnc(reply->data,block++,i,0))
230 int url_fsp(const char *name, int (*fnc)(unsigned char *, unsigned int, unsigned int, int))
232 struct fsp_info info;
233 /* Set the defaults */
234 info.server_ip.s_addr = arptable[ARP_SERVER].ipaddr.s_addr;
235 info.server_port = FSP_PORT;
236 info.local_port = 1024 + random() & 0xfbff;
239 /* Now parse the url */
240 /* printf("fsp-URI: [%s]\n", name); */
241 /* quick hack for now */
243 return proto_fsp(&info);