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.

proto_slam.c 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541
  1. #ifdef DOWNLOAD_PROTO_SLAM
  2. #include "etherboot.h"
  3. #include "nic.h"
  4. #define SLAM_PORT 10000
  5. #define SLAM_MULTICAST_IP ((239<<24)|(255<<16)|(1<<8)|(1<<0))
  6. #define SLAM_MULTICAST_PORT 10000
  7. #define SLAM_LOCAL_PORT 10000
  8. /* Set the timeout intervals to at least 1 second so
  9. * on a 100Mbit ethernet can receive 10000 packets
  10. * in one second.
  11. *
  12. * The only case that is likely to trigger all of the nodes
  13. * firing a nack packet is a slow server. The odds of this
  14. * happening could be reduced being slightly smarter and utilizing
  15. * the multicast channels for nacks. But that only improves the odds
  16. * it doesn't improve the worst case. So unless this proves to be
  17. * a common case having the control data going unicast should increase
  18. * the odds of the data not being dropped.
  19. *
  20. * When doing exponential backoff we increase just the timeout
  21. * interval and not the base to optimize for throughput. This is only
  22. * expected to happen when the server is down. So having some nodes
  23. * pinging immediately should get the transmission restarted quickly after a
  24. * server restart. The host nic won't be to baddly swamped because of
  25. * the random distribution of the nodes.
  26. *
  27. */
  28. #define SLAM_INITIAL_MIN_TIMEOUT (TICKS_PER_SEC/3)
  29. #define SLAM_INITIAL_TIMEOUT_INTERVAL (TICKS_PER_SEC)
  30. #define SLAM_BASE_MIN_TIMEOUT (2*TICKS_PER_SEC)
  31. #define SLAM_BASE_TIMEOUT_INTERVAL (4*TICKS_PER_SEC)
  32. #define SLAM_BACKOFF_LIMIT 5
  33. #define SLAM_MAX_RETRIES 20
  34. /*** Packets Formats ***
  35. * Data Packet:
  36. * transaction
  37. * total bytes
  38. * block size
  39. * packet #
  40. * data
  41. *
  42. * Status Request Packet
  43. * transaction
  44. * total bytes
  45. * block size
  46. *
  47. * Status Packet
  48. * received packets
  49. * requested packets
  50. * received packets
  51. * requested packets
  52. * ...
  53. * received packets
  54. * requested packtes
  55. * 0
  56. */
  57. #define MAX_HDR (7 + 7 + 7) /* transaction, total size, block size */
  58. #define MIN_HDR (1 + 1 + 1) /* transactino, total size, block size */
  59. #define MAX_SLAM_REQUEST MAX_HDR
  60. #define MIN_SLAM_REQUEST MIN_HDR
  61. #define MIN_SLAM_DATA (MIN_HDR + 1)
  62. static struct slam_nack {
  63. struct iphdr ip;
  64. struct udphdr udp;
  65. unsigned char data[ETH_MAX_MTU -
  66. (sizeof(struct iphdr) + sizeof(struct udphdr))];
  67. } nack;
  68. struct slam_state {
  69. unsigned char hdr[MAX_HDR];
  70. unsigned long hdr_len;
  71. unsigned long block_size;
  72. unsigned long total_bytes;
  73. unsigned long total_packets;
  74. unsigned long received_packets;
  75. unsigned char *image;
  76. unsigned char *bitmap;
  77. } state;
  78. static void init_slam_state(void)
  79. {
  80. state.hdr_len = sizeof(state.hdr);
  81. memset(state.hdr, 0, state.hdr_len);
  82. state.block_size = 0;
  83. state.total_packets = 0;
  84. state.received_packets = 0;
  85. state.image = 0;
  86. state.bitmap = 0;
  87. }
  88. struct slam_info {
  89. in_addr server_ip;
  90. in_addr multicast_ip;
  91. in_addr local_ip;
  92. uint16_t server_port;
  93. uint16_t multicast_port;
  94. uint16_t local_port;
  95. int (*fnc)(unsigned char *, unsigned int, unsigned int, int);
  96. int sent_nack;
  97. };
  98. #define SLAM_TIMEOUT 0
  99. #define SLAM_REQUEST 1
  100. #define SLAM_DATA 2
  101. static int await_slam(int ival __unused, void *ptr,
  102. unsigned short ptype __unused, struct iphdr *ip, struct udphdr *udp)
  103. {
  104. struct slam_info *info = ptr;
  105. if (!udp) {
  106. return 0;
  107. }
  108. /* I can receive two kinds of packets here, a multicast data packet,
  109. * or a unicast request for information
  110. */
  111. /* Check for a data request packet */
  112. if ((ip->dest.s_addr == arptable[ARP_CLIENT].ipaddr.s_addr) &&
  113. (ntohs(udp->dest) == info->local_port) &&
  114. (nic.packetlen >=
  115. ETH_HLEN +
  116. sizeof(struct iphdr) +
  117. sizeof(struct udphdr) +
  118. MIN_SLAM_REQUEST)) {
  119. return SLAM_REQUEST;
  120. }
  121. /* Check for a multicast data packet */
  122. if ((ip->dest.s_addr == info->multicast_ip.s_addr) &&
  123. (ntohs(udp->dest) == info->multicast_port) &&
  124. (nic.packetlen >=
  125. ETH_HLEN +
  126. sizeof(struct iphdr) +
  127. sizeof(struct udphdr) +
  128. MIN_SLAM_DATA)) {
  129. return SLAM_DATA;
  130. }
  131. #if 0
  132. printf("#");
  133. printf("dest: %@ port: %d len: %d\n",
  134. ip->dest.s_addr, ntohs(udp->dest), nic.packetlen);
  135. #endif
  136. return 0;
  137. }
  138. static int slam_encode(
  139. unsigned char **ptr, unsigned char *end, unsigned long value)
  140. {
  141. unsigned char *data = *ptr;
  142. int bytes;
  143. bytes = sizeof(value);
  144. while ((bytes > 0) && ((0xff & (value >> ((bytes -1)<<3))) == 0)) {
  145. bytes--;
  146. }
  147. if (bytes <= 0) {
  148. bytes = 1;
  149. }
  150. if (data + bytes >= end) {
  151. return -1;
  152. }
  153. if ((0xe0 & (value >> ((bytes -1)<<3))) == 0) {
  154. /* packed together */
  155. *data = (bytes << 5) | (value >> ((bytes -1)<<3));
  156. } else {
  157. bytes++;
  158. *data = (bytes << 5);
  159. }
  160. bytes--;
  161. data++;
  162. while(bytes) {
  163. *(data++) = 0xff & (value >> ((bytes -1)<<3));
  164. bytes--;
  165. }
  166. *ptr = data;
  167. return 0;
  168. }
  169. static int slam_skip(unsigned char **ptr, unsigned char *end)
  170. {
  171. int bytes;
  172. if (*ptr >= end) {
  173. return -1;
  174. }
  175. bytes = ((**ptr) >> 5) & 7;
  176. if (bytes == 0) {
  177. return -1;
  178. }
  179. if (*ptr + bytes >= end) {
  180. return -1;
  181. }
  182. (*ptr) += bytes;
  183. return 0;
  184. }
  185. static unsigned long slam_decode(unsigned char **ptr, unsigned char *end, int *err)
  186. {
  187. unsigned long value;
  188. unsigned bytes;
  189. if (*ptr >= end) {
  190. *err = -1;
  191. }
  192. bytes = ((**ptr) >> 5) & 7;
  193. if ((bytes == 0) || (bytes > sizeof(unsigned long))) {
  194. *err = -1;
  195. return 0;
  196. }
  197. if ((*ptr) + bytes >= end) {
  198. *err = -1;
  199. }
  200. value = (**ptr) & 0x1f;
  201. bytes--;
  202. (*ptr)++;
  203. while(bytes) {
  204. value <<= 8;
  205. value |= **ptr;
  206. (*ptr)++;
  207. bytes--;
  208. }
  209. return value;
  210. }
  211. static long slam_sleep_interval(int exp)
  212. {
  213. long range;
  214. long divisor;
  215. long interval;
  216. range = SLAM_BASE_TIMEOUT_INTERVAL;
  217. if (exp < 0) {
  218. divisor = RAND_MAX/SLAM_INITIAL_TIMEOUT_INTERVAL;
  219. } else {
  220. if (exp > SLAM_BACKOFF_LIMIT)
  221. exp = SLAM_BACKOFF_LIMIT;
  222. divisor = RAND_MAX/(range << exp);
  223. }
  224. interval = random()/divisor;
  225. if (exp < 0) {
  226. interval += SLAM_INITIAL_MIN_TIMEOUT;
  227. } else {
  228. interval += SLAM_BASE_MIN_TIMEOUT;
  229. }
  230. return interval;
  231. }
  232. static unsigned char *reinit_slam_state(
  233. unsigned char *header, unsigned char *end)
  234. {
  235. unsigned long total_bytes;
  236. unsigned long block_size;
  237. unsigned long bitmap_len;
  238. unsigned long max_packet_len;
  239. unsigned char *data;
  240. int err;
  241. #if 0
  242. printf("reinit\n");
  243. #endif
  244. data = header;
  245. state.hdr_len = 0;
  246. err = slam_skip(&data, end); /* transaction id */
  247. total_bytes = slam_decode(&data, end, &err);
  248. block_size = slam_decode(&data, end, &err);
  249. if (err) {
  250. printf("ALERT: slam size out of range\n");
  251. return 0;
  252. }
  253. state.block_size = block_size;
  254. state.total_bytes = total_bytes;
  255. state.total_packets = (total_bytes + block_size - 1)/block_size;
  256. state.hdr_len = data - header;
  257. state.received_packets = 0;
  258. data = state.hdr;
  259. slam_encode(&data, &state.hdr[sizeof(state.hdr)], state.total_packets);
  260. max_packet_len = data - state.hdr;
  261. memcpy(state.hdr, header, state.hdr_len);
  262. #if 0
  263. printf("block_size: %ld\n", block_size);
  264. printf("total_bytes: %ld\n", total_bytes);
  265. printf("total_packets: %ld\n", state.total_packets);
  266. printf("hdr_len: %ld\n", state.hdr_len);
  267. printf("max_packet_len: %ld\n", max_packet_len);
  268. #endif
  269. if (state.block_size > ETH_MAX_MTU - (
  270. sizeof(struct iphdr) + sizeof(struct udphdr) +
  271. state.hdr_len + max_packet_len)) {
  272. printf("ALERT: slam blocksize to large\n");
  273. return 0;
  274. }
  275. if (state.bitmap) {
  276. forget(state.bitmap);
  277. }
  278. bitmap_len = (state.total_packets + 1 + 7)/8;
  279. state.bitmap = allot(bitmap_len);
  280. state.image = allot(total_bytes);
  281. if ((unsigned long)state.image < 1024*1024) {
  282. printf("ALERT: slam filesize to large for available memory\n");
  283. return 0;
  284. }
  285. memset(state.bitmap, 0, bitmap_len);
  286. return header + state.hdr_len;
  287. }
  288. static int slam_recv_data(unsigned char *data)
  289. {
  290. unsigned long packet;
  291. unsigned long data_len;
  292. int err;
  293. struct udphdr *udp;
  294. udp = (struct udphdr *)&nic.packet[ETH_HLEN + sizeof(struct iphdr)];
  295. err = 0;
  296. packet = slam_decode(&data, &nic.packet[nic.packetlen], &err);
  297. if (err || (packet > state.total_packets)) {
  298. printf("ALERT: Invalid packet number\n");
  299. return 0;
  300. }
  301. /* Compute the expected data length */
  302. if (packet != state.total_packets -1) {
  303. data_len = state.block_size;
  304. } else {
  305. data_len = state.total_bytes % state.block_size;
  306. }
  307. /* If the packet size is wrong drop the packet and then continue */
  308. if (ntohs(udp->len) != (data_len + (data - (unsigned char*)udp))) {
  309. printf("ALERT: udp packet is not the correct size\n");
  310. return 1;
  311. }
  312. if (nic.packetlen < data_len + (data - nic.packet)) {
  313. printf("ALERT: Ethernet packet shorter than data_len\n");
  314. return 1;
  315. }
  316. if (data_len > state.block_size) {
  317. data_len = state.block_size;
  318. }
  319. if (((state.bitmap[packet >> 3] >> (packet & 7)) & 1) == 0) {
  320. /* Non duplicate packet */
  321. state.bitmap[packet >> 3] |= (1 << (packet & 7));
  322. memcpy(state.image + (packet*state.block_size), data, data_len);
  323. state.received_packets++;
  324. } else {
  325. #ifdef MDEBUG
  326. printf("<DUP>\n");
  327. #endif
  328. }
  329. return 1;
  330. }
  331. static void transmit_nack(unsigned char *ptr, struct slam_info *info)
  332. {
  333. int nack_len;
  334. /* Ensure the packet is null terminated */
  335. *ptr++ = 0;
  336. nack_len = ptr - (unsigned char *)&nack;
  337. build_udp_hdr(info->server_ip.s_addr,
  338. info->local_port, info->server_port, 1, nack_len, &nack);
  339. ip_transmit(nack_len, &nack);
  340. #if defined(MDEBUG) && 0
  341. printf("Sent NACK to %@ bytes: %d have:%ld/%ld\n",
  342. info->server_ip, nack_len,
  343. state.received_packets, state.total_packets);
  344. #endif
  345. }
  346. static void slam_send_nack(struct slam_info *info)
  347. {
  348. unsigned char *ptr, *end;
  349. /* Either I timed out or I was explicitly
  350. * asked for a request packet
  351. */
  352. ptr = &nack.data[0];
  353. /* Reserve space for the trailling null */
  354. end = &nack.data[sizeof(nack.data) -1];
  355. if (!state.bitmap) {
  356. slam_encode(&ptr, end, 0);
  357. slam_encode(&ptr, end, 1);
  358. }
  359. else {
  360. /* Walk the bitmap */
  361. unsigned long i;
  362. unsigned long len;
  363. unsigned long max;
  364. int value;
  365. int last;
  366. /* Compute the last bit and store an inverted trailer */
  367. max = state.total_packets;
  368. value = ((state.bitmap[(max -1) >> 3] >> ((max -1) & 7) ) & 1);
  369. value = !value;
  370. state.bitmap[max >> 3] &= ~(1 << (max & 7));
  371. state.bitmap[max >> 3] |= value << (max & 7);
  372. len = 0;
  373. last = 1; /* Start with the received packets */
  374. for(i = 0; i <= max; i++) {
  375. value = (state.bitmap[i>>3] >> (i & 7)) & 1;
  376. if (value == last) {
  377. len++;
  378. } else {
  379. if (slam_encode(&ptr, end, len))
  380. break;
  381. last = value;
  382. len = 1;
  383. }
  384. }
  385. }
  386. info->sent_nack = 1;
  387. transmit_nack(ptr, info);
  388. }
  389. static void slam_send_disconnect(struct slam_info *info)
  390. {
  391. if (info->sent_nack) {
  392. /* A disconnect is a packet with just the null terminator */
  393. transmit_nack(&nack.data[0], info);
  394. }
  395. info->sent_nack = 0;
  396. }
  397. static int proto_slam(struct slam_info *info)
  398. {
  399. int retry;
  400. long timeout;
  401. init_slam_state();
  402. retry = -1;
  403. rx_qdrain();
  404. /* Arp for my server */
  405. if (arptable[ARP_SERVER].ipaddr.s_addr != info->server_ip.s_addr) {
  406. arptable[ARP_SERVER].ipaddr.s_addr = info->server_ip.s_addr;
  407. memset(arptable[ARP_SERVER].node, 0, ETH_ALEN);
  408. }
  409. /* If I'm running over multicast join the multicast group */
  410. join_group(IGMP_SERVER, info->multicast_ip.s_addr);
  411. for(;;) {
  412. unsigned char *header;
  413. unsigned char *data;
  414. int type;
  415. header = data = 0;
  416. timeout = slam_sleep_interval(retry);
  417. type = await_reply(await_slam, 0, info, timeout);
  418. /* Compute the timeout for next time */
  419. if (type == SLAM_TIMEOUT) {
  420. /* If I timeouted recompute the next timeout */
  421. if (retry++ > SLAM_MAX_RETRIES) {
  422. return 0;
  423. }
  424. } else {
  425. retry = 0;
  426. }
  427. if ((type == SLAM_DATA) || (type == SLAM_REQUEST)) {
  428. /* Check the incomming packet and reinit the data
  429. * structures if necessary.
  430. */
  431. header = &nic.packet[ETH_HLEN +
  432. sizeof(struct iphdr) + sizeof(struct udphdr)];
  433. data = header + state.hdr_len;
  434. if (memcmp(state.hdr, header, state.hdr_len) != 0) {
  435. /* Something is fishy reset the transaction */
  436. data = reinit_slam_state(header, &nic.packet[nic.packetlen]);
  437. if (!data) {
  438. return 0;
  439. }
  440. }
  441. }
  442. if (type == SLAM_DATA) {
  443. if (!slam_recv_data(data)) {
  444. return 0;
  445. }
  446. if (state.received_packets == state.total_packets) {
  447. /* We are done get out */
  448. break;
  449. }
  450. }
  451. if ((type == SLAM_TIMEOUT) || (type == SLAM_REQUEST)) {
  452. /* Either I timed out or I was explicitly
  453. * asked by a request packet
  454. */
  455. slam_send_nack(info);
  456. }
  457. }
  458. slam_send_disconnect(info);
  459. /* Leave the multicast group */
  460. leave_group(IGMP_SERVER);
  461. /* FIXME don't overwrite myself */
  462. /* load file to correct location */
  463. return info->fnc(state.image, 1, state.total_bytes, 1);
  464. }
  465. int url_slam(const char *name, int (*fnc)(unsigned char *, unsigned int, unsigned int, int))
  466. {
  467. struct slam_info info;
  468. /* Set the defaults */
  469. info.server_ip.s_addr = arptable[ARP_SERVER].ipaddr.s_addr;
  470. info.server_port = SLAM_PORT;
  471. info.multicast_ip.s_addr = htonl(SLAM_MULTICAST_IP);
  472. info.multicast_port = SLAM_MULTICAST_PORT;
  473. info.local_ip.s_addr = arptable[ARP_CLIENT].ipaddr.s_addr;
  474. info.local_port = SLAM_LOCAL_PORT;
  475. info.fnc = fnc;
  476. info.sent_nack = 0;
  477. /* Now parse the url */
  478. if (url_port != -1) {
  479. info.server_port = url_port;
  480. }
  481. if (name[0]) {
  482. /* multicast ip */
  483. name += inet_aton(name, &info.multicast_ip);
  484. if (name[0] == ':') {
  485. name++;
  486. info.multicast_port = strtoul(name, &name, 10);
  487. }
  488. }
  489. if (name[0]) {
  490. printf("\nBad url\n");
  491. return 0;
  492. }
  493. return proto_slam(&info);
  494. }
  495. #endif /* DOWNLOAD_PROTO_SLAM */