Adding debian version 3.70~pre8+dfsg-1.
[syslinux-debian/hramrach.git] / gpxe / src / proto / fsp.c
blob9a10991de85a93afab164fd2cc414ef5563b430d
1 /*********************************************************************\
2 * Copyright (c) 2005 by Radim Kolar (hsn-sendmail.cz) *
3 * *
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. *
8 * *
9 * This file provides support for FSP v2 protocol written from scratch *
10 * by Radim Kolar, FSP project leader. *
11 * *
12 * ABOUT FSP *
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/ *
19 * *
20 * REVISION HISTORY *
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 *
28 * eof is reached.
29 * REMARKS *
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
37 #define FSP_PORT 21
39 /* FSP commands */
40 #define CC_GET_FILE 0x42
41 #define CC_BYE 0x4A
42 #define CC_ERR 0x40
43 #define CC_STAT 0x4D
45 /* etherboot limits */
46 #define FSP_MAXFILENAME 255
48 struct fsp_info {
49 in_addr server_ip;
50 uint16_t server_port;
51 uint16_t local_port;
52 const char *filename;
53 int (*fnc)(unsigned char *, unsigned int, unsigned int, int);
56 struct fsp_header {
57 uint8_t cmd;
58 uint8_t sum;
59 uint16_t key;
60 uint16_t seq;
61 uint16_t len;
62 uint32_t pos;
63 } PACKED;
65 #define FSP_MAXPAYLOAD (ETH_MAX_MTU - \
66 (sizeof(struct iphdr) + sizeof(struct udphdr) + sizeof(struct fsp_header)))
68 static struct fsp_request {
69 struct iphdr ip;
70 struct udphdr udp;
71 struct fsp_header fsp;
72 unsigned char data[FSP_MAXFILENAME + 1 + 2];
73 } request;
75 struct fsp_reply {
76 struct iphdr ip;
77 struct udphdr udp;
78 struct fsp_header fsp;
79 unsigned char data[FSP_MAXPAYLOAD];
80 } PACKED;
83 static int await_fsp(int ival, void *ptr, unsigned short ptype __unused,
84 struct iphdr *ip, struct udphdr *udp)
86 if(!udp)
87 return 0;
88 if (ip->dest.s_addr != arptable[ARP_CLIENT].ipaddr.s_addr)
89 return 0;
90 if (ntohs(udp->dest) != ival)
91 return 0;
92 if (ntohs(udp->len) < 12+sizeof(struct udphdr))
93 return 0;
94 return 1;
97 static int proto_fsp(struct fsp_info *info)
99 uint32_t filepos;
100 uint32_t filelength=0;
101 int i,retry;
102 uint16_t reqlen;
103 struct fsp_reply *reply;
104 int block=1;
106 /* prepare FSP request packet */
107 filepos=0;
108 i=strlen(info->filename);
109 if(i>FSP_MAXFILENAME)
111 printf("Boot filename is too long.\n");
112 return 0;
114 strcpy(request.data,info->filename);
115 *(uint16_t *)(request.data+i+1)=htons(FSP_MAXPAYLOAD);
116 request.fsp.len=htons(i+1);
117 reqlen=i+3+12;
119 rx_qdrain();
120 retry=0;
122 /* main loop */
123 for(;;) {
124 int sum;
125 long timeout;
127 /* query filelength if not known */
128 if(filelength == 0)
129 request.fsp.cmd=CC_STAT;
131 /* prepare request packet */
132 request.fsp.pos=htonl(filepos);
133 request.fsp.seq=random();
134 request.fsp.sum=0;
135 for(i=0,sum=reqlen;i<reqlen;i++)
137 sum += ((uint8_t *)&request.fsp)[i];
139 request.fsp.sum= sum + (sum >> 8);
140 /* send request */
141 if (!udp_transmit(info->server_ip.s_addr, info->local_port,
142 info->server_port, sizeof(request.ip) +
143 sizeof(request.udp) + reqlen, &request))
144 return (0);
145 /* wait for retry */
146 #ifdef CONGESTED
147 timeout =
148 rfc2131_sleep_interval(filepos ? TFTP_REXMT : TIMEOUT, retry);
149 #else
150 timeout = rfc2131_sleep_interval(TIMEOUT, retry);
151 #endif
152 retry++;
153 if (!await_reply(await_fsp, info->local_port, NULL, timeout))
154 continue;
155 reply=(struct fsp_reply *) &nic.packet[ETH_HLEN];
156 /* check received packet */
157 if (reply->fsp.seq != request.fsp.seq)
158 continue;
159 reply->udp.len=ntohs(reply->udp.len)-sizeof(struct udphdr);
160 if(reply->udp.len < ntohs(reply->fsp.len) + 12 )
161 continue;
162 sum=-reply->fsp.sum;
163 for(i=0;i<reply->udp.len;i++)
165 sum += ((uint8_t *)&(reply->fsp))[i];
167 sum = (sum + (sum >> 8)) & 0xff;
168 if(sum != reply->fsp.sum)
170 printf("FSP checksum failed. computed %d, but packet has %d.\n",sum,reply->fsp.sum);
171 continue;
173 if(reply->fsp.cmd == CC_ERR)
175 printf("\nFSP error: %s",info->filename);
176 if(reply->fsp.len)
177 printf(" [%s]",reply->data);
178 printf("\n");
179 return 0;
181 if(reply->fsp.cmd == CC_BYE && filelength == 1)
183 info->fnc(request.data,block,1,1);
184 return 1;
186 if(reply->fsp.cmd == CC_STAT)
188 if(reply->data[8] == 0)
190 /* file not found, etc. */
191 filelength=0xffffffff;
192 } else
194 filelength= ntohl(*((uint32_t *)&reply->data[4]));
196 request.fsp.cmd = CC_GET_FILE;
197 request.fsp.key = reply->fsp.key;
198 retry=0;
199 continue;
202 if(reply->fsp.cmd == CC_GET_FILE)
204 if(ntohl(reply->fsp.pos) != filepos)
205 continue;
206 request.fsp.key = reply->fsp.key;
207 retry=0;
208 i=ntohs(reply->fsp.len);
209 if(i == 1)
211 request.fsp.cmd=CC_BYE;
212 request.data[0]=reply->data[0];
213 continue;
215 /* let last byte alone */
216 if(i >= filelength)
217 i = filelength - 1;
218 if(!info->fnc(reply->data,block++,i,0))
219 return 0;
220 filepos += i;
221 filelength -= i;
225 return 0;
228 int url_fsp(const char *name, int (*fnc)(unsigned char *, unsigned int, unsigned int, int))
230 struct fsp_info info;
231 /* Set the defaults */
232 info.server_ip.s_addr = arptable[ARP_SERVER].ipaddr.s_addr;
233 info.server_port = FSP_PORT;
234 info.local_port = 1024 + random() & 0xfbff;
235 info.fnc = fnc;
237 /* Now parse the url */
238 /* printf("fsp-URI: [%s]\n", name); */
239 /* quick hack for now */
240 info.filename=name;
241 return proto_fsp(&info);
243 #endif