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
40 #define CC_GET_FILE 0x42
45 /* etherboot limits */
46 #define FSP_MAXFILENAME 255
53 int (*fnc
)(unsigned char *, unsigned int, unsigned int, int);
65 #define FSP_MAXPAYLOAD (ETH_MAX_MTU - \
66 (sizeof(struct iphdr) + sizeof(struct udphdr) + sizeof(struct fsp_header)))
68 static struct fsp_request
{
71 struct fsp_header fsp
;
72 unsigned char data
[FSP_MAXFILENAME
+ 1 + 2];
78 struct fsp_header fsp
;
79 unsigned char data
[FSP_MAXPAYLOAD
];
83 static int await_fsp(int ival
, void *ptr
, unsigned short ptype __unused
,
84 struct iphdr
*ip
, struct udphdr
*udp
)
88 if (ip
->dest
.s_addr
!= arptable
[ARP_CLIENT
].ipaddr
.s_addr
)
90 if (ntohs(udp
->dest
) != ival
)
92 if (ntohs(udp
->len
) < 12+sizeof(struct udphdr
))
97 static int proto_fsp(struct fsp_info
*info
)
100 uint32_t filelength
=0;
103 struct fsp_reply
*reply
;
106 /* prepare FSP request packet */
108 i
=strlen(info
->filename
);
109 if(i
>FSP_MAXFILENAME
)
111 printf("Boot filename is too long.\n");
114 strcpy(request
.data
,info
->filename
);
115 *(uint16_t *)(request
.data
+i
+1)=htons(FSP_MAXPAYLOAD
);
116 request
.fsp
.len
=htons(i
+1);
127 /* query filelength if not known */
129 request
.fsp
.cmd
=CC_STAT
;
131 /* prepare request packet */
132 request
.fsp
.pos
=htonl(filepos
);
133 request
.fsp
.seq
=random();
135 for(i
=0,sum
=reqlen
;i
<reqlen
;i
++)
137 sum
+= ((uint8_t *)&request
.fsp
)[i
];
139 request
.fsp
.sum
= sum
+ (sum
>> 8);
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
))
148 rfc2131_sleep_interval(filepos
? TFTP_REXMT
: TIMEOUT
, retry
);
150 timeout
= rfc2131_sleep_interval(TIMEOUT
, retry
);
153 if (!await_reply(await_fsp
, info
->local_port
, NULL
, timeout
))
155 reply
=(struct fsp_reply
*) &nic
.packet
[ETH_HLEN
];
156 /* check received packet */
157 if (reply
->fsp
.seq
!= request
.fsp
.seq
)
159 reply
->udp
.len
=ntohs(reply
->udp
.len
)-sizeof(struct udphdr
);
160 if(reply
->udp
.len
< ntohs(reply
->fsp
.len
) + 12 )
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
);
173 if(reply
->fsp
.cmd
== CC_ERR
)
175 printf("\nFSP error: %s",info
->filename
);
177 printf(" [%s]",reply
->data
);
181 if(reply
->fsp
.cmd
== CC_BYE
&& filelength
== 1)
183 info
->fnc(request
.data
,block
,1,1);
186 if(reply
->fsp
.cmd
== CC_STAT
)
188 if(reply
->data
[8] == 0)
190 /* file not found, etc. */
191 filelength
=0xffffffff;
194 filelength
= ntohl(*((uint32_t *)&reply
->data
[4]));
196 request
.fsp
.cmd
= CC_GET_FILE
;
197 request
.fsp
.key
= reply
->fsp
.key
;
202 if(reply
->fsp
.cmd
== CC_GET_FILE
)
204 if(ntohl(reply
->fsp
.pos
) != filepos
)
206 request
.fsp
.key
= reply
->fsp
.key
;
208 i
=ntohs(reply
->fsp
.len
);
211 request
.fsp
.cmd
=CC_BYE
;
212 request
.data
[0]=reply
->data
[0];
215 /* let last byte alone */
218 if(!info
->fnc(reply
->data
,block
++,i
,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;
237 /* Now parse the url */
238 /* printf("fsp-URI: [%s]\n", name); */
239 /* quick hack for now */
241 return proto_fsp(&info
);