You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

fsp.c 7.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  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. \*********************************************************************/
  34. #ifdef DOWNLOAD_PROTO_FSP
  35. #include "etherboot.h"
  36. #include "nic.h"
  37. #define FSP_PORT 21
  38. /* FSP commands */
  39. #define CC_GET_FILE 0x42
  40. #define CC_BYE 0x4A
  41. #define CC_ERR 0x40
  42. #define CC_STAT 0x4D
  43. /* etherboot limits */
  44. #define FSP_MAXFILENAME 255
  45. struct fsp_info {
  46. in_addr server_ip;
  47. uint16_t server_port;
  48. uint16_t local_port;
  49. const char *filename;
  50. int (*fnc)(unsigned char *, unsigned int, unsigned int, int);
  51. };
  52. struct fsp_header {
  53. uint8_t cmd;
  54. uint8_t sum;
  55. uint16_t key;
  56. uint16_t seq;
  57. uint16_t len;
  58. uint32_t pos;
  59. } PACKED;
  60. #define FSP_MAXPAYLOAD (ETH_MAX_MTU - \
  61. (sizeof(struct iphdr) + sizeof(struct udphdr) + sizeof(struct fsp_header)))
  62. static struct fsp_request {
  63. struct iphdr ip;
  64. struct udphdr udp;
  65. struct fsp_header fsp;
  66. unsigned char data[FSP_MAXFILENAME + 1 + 2];
  67. } request;
  68. struct fsp_reply {
  69. struct iphdr ip;
  70. struct udphdr udp;
  71. struct fsp_header fsp;
  72. unsigned char data[FSP_MAXPAYLOAD];
  73. } PACKED;
  74. static int await_fsp(int ival, void *ptr, unsigned short ptype __unused,
  75. struct iphdr *ip, struct udphdr *udp)
  76. {
  77. if(!udp)
  78. return 0;
  79. if (ip->dest.s_addr != arptable[ARP_CLIENT].ipaddr.s_addr)
  80. return 0;
  81. if (ntohs(udp->dest) != ival)
  82. return 0;
  83. if (ntohs(udp->len) < 12+sizeof(struct udphdr))
  84. return 0;
  85. return 1;
  86. }
  87. static int proto_fsp(struct fsp_info *info)
  88. {
  89. uint32_t filepos;
  90. uint32_t filelength=0;
  91. int i,retry;
  92. uint16_t reqlen;
  93. struct fsp_reply *reply;
  94. int block=1;
  95. /* prepare FSP request packet */
  96. filepos=0;
  97. i=strlen(info->filename);
  98. if(i>FSP_MAXFILENAME)
  99. {
  100. printf("Boot filename is too long.\n");
  101. return 0;
  102. }
  103. strcpy(request.data,info->filename);
  104. *(uint16_t *)(request.data+i+1)=htons(FSP_MAXPAYLOAD);
  105. request.fsp.len=htons(i+1);
  106. reqlen=i+3+12;
  107. rx_qdrain();
  108. retry=0;
  109. /* main loop */
  110. for(;;) {
  111. int sum;
  112. long timeout;
  113. /* query filelength if not known */
  114. if(filelength == 0)
  115. request.fsp.cmd=CC_STAT;
  116. /* prepare request packet */
  117. request.fsp.pos=htonl(filepos);
  118. request.fsp.seq=random();
  119. request.fsp.sum=0;
  120. for(i=0,sum=reqlen;i<reqlen;i++)
  121. {
  122. sum += ((uint8_t *)&request.fsp)[i];
  123. }
  124. request.fsp.sum= sum + (sum >> 8);
  125. /* send request */
  126. if (!udp_transmit(info->server_ip.s_addr, info->local_port,
  127. info->server_port, sizeof(request.ip) +
  128. sizeof(request.udp) + reqlen, &request))
  129. return (0);
  130. /* wait for retry */
  131. #ifdef CONGESTED
  132. timeout =
  133. rfc2131_sleep_interval(filepos ? TFTP_REXMT : TIMEOUT, retry);
  134. #else
  135. timeout = rfc2131_sleep_interval(TIMEOUT, retry);
  136. #endif
  137. retry++;
  138. if (!await_reply(await_fsp, info->local_port, NULL, timeout))
  139. continue;
  140. reply=(struct fsp_reply *) &nic.packet[ETH_HLEN];
  141. /* check received packet */
  142. if (reply->fsp.seq != request.fsp.seq)
  143. continue;
  144. reply->udp.len=ntohs(reply->udp.len)-sizeof(struct udphdr);
  145. if(reply->udp.len < ntohs(reply->fsp.len) + 12 )
  146. continue;
  147. sum=-reply->fsp.sum;
  148. for(i=0;i<reply->udp.len;i++)
  149. {
  150. sum += ((uint8_t *)&(reply->fsp))[i];
  151. }
  152. sum = (sum + (sum >> 8)) & 0xff;
  153. if(sum != reply->fsp.sum)
  154. {
  155. printf("FSP checksum failed. computed %d, but packet has %d.\n",sum,reply->fsp.sum);
  156. continue;
  157. }
  158. if(reply->fsp.cmd == CC_ERR)
  159. {
  160. printf("\nFSP error: %s",info->filename);
  161. if(reply->fsp.len)
  162. printf(" [%s]",reply->data);
  163. printf("\n");
  164. return 0;
  165. }
  166. if(reply->fsp.cmd == CC_BYE && filelength == 1)
  167. {
  168. info->fnc(request.data,block,1,1);
  169. return 1;
  170. }
  171. if(reply->fsp.cmd == CC_STAT)
  172. {
  173. if(reply->data[8] == 0)
  174. {
  175. /* file not found, etc. */
  176. filelength=0xffffffff;
  177. } else
  178. {
  179. filelength= ntohl(*((uint32_t *)&reply->data[4]));
  180. }
  181. request.fsp.cmd = CC_GET_FILE;
  182. request.fsp.key = reply->fsp.key;
  183. retry=0;
  184. continue;
  185. }
  186. if(reply->fsp.cmd == CC_GET_FILE)
  187. {
  188. if(ntohl(reply->fsp.pos) != filepos)
  189. continue;
  190. request.fsp.key = reply->fsp.key;
  191. retry=0;
  192. i=ntohs(reply->fsp.len);
  193. if(i == 1)
  194. {
  195. request.fsp.cmd=CC_BYE;
  196. request.data[0]=reply->data[0];
  197. continue;
  198. }
  199. /* let last byte alone */
  200. if(i >= filelength)
  201. i = filelength - 1;
  202. if(!info->fnc(reply->data,block++,i,0))
  203. return 0;
  204. filepos += i;
  205. filelength -= i;
  206. }
  207. }
  208. return 0;
  209. }
  210. int url_fsp(const char *name, int (*fnc)(unsigned char *, unsigned int, unsigned int, int))
  211. {
  212. struct fsp_info info;
  213. /* Set the defaults */
  214. info.server_ip.s_addr = arptable[ARP_SERVER].ipaddr.s_addr;
  215. info.server_port = FSP_PORT;
  216. info.local_port = 1024 + random() & 0xfbff;
  217. info.fnc = fnc;
  218. /* Now parse the url */
  219. /* printf("fsp-URI: [%s]\n", name); */
  220. /* quick hack for now */
  221. info.filename=name;
  222. return proto_fsp(&info);
  223. }
  224. #endif