Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / SLOF / clients / net-snk / app / netlib / tftp.c
1 /******************************************************************************
2  * Copyright (c) 2004, 2008 IBM Corporation
3  * All rights reserved.
4  * This program and the accompanying materials
5  * are made available under the terms of the BSD License
6  * which accompanies this distribution, and is available at
7  * http://www.opensource.org/licenses/bsd-license.php
8  *
9  * Contributors:
10  *     IBM Corporation - initial implementation
11  *****************************************************************************/
12
13 #include <tftp.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <time.h>
18 #include <sys/socket.h>
19
20 #include <ethernet.h>
21 #include <ipv4.h>
22 #include <ipv6.h>
23 #include <udp.h>
24
25 //#define __DEBUG__
26
27 #define MAX_BLOCKSIZE 1428
28 #define BUFFER_LEN 256
29
30 #define ENOTFOUND 1
31 #define EACCESS   2
32 #define EBADOP    4
33 #define EBADID    5
34 #define ENOUSER   7
35 //#define EUNDEF 0
36 //#define ENOSPACE 3
37 //#define EEXISTS 6
38
39 #define RRQ   1
40 #define WRQ   2
41 #define DATA  3
42 #define ACK   4
43 #define ERROR 5
44 #define OACK  6
45
46 /* Local variables */
47 static unsigned char packet[BUFFER_LEN];
48 static unsigned char  *buffer = NULL;
49 static unsigned short block = 0;
50 static unsigned short blocksize;
51 static char blocksize_str[6];    /* Blocksize string for read request */
52 static int received_len = 0;
53 static int retries = 0;
54 static int huge_load;
55 static int len;
56 static int tftp_finished = 0;
57 static int lost_packets = 0;
58 static int tftp_errno = 0; 
59 static int ip_version = 0; 
60 static short port_number = -1;
61 static tftp_err_t *tftp_err;
62 static filename_ip_t  *fn_ip;
63
64 /**
65  * dump_package - Prints a package.
66  *
67  * @package: package which is to print
68  * @len:     length of the package
69  */
70 #ifdef __DEBUG__
71
72 static void
73 dump_package(unsigned char *buffer, unsigned int len)
74 {
75         int i;
76
77         for (i = 1; i <= len; i++) {
78                 printf("%02x%02x ", buffer[i - 1], buffer[i]);
79                 i++;
80                 if ((i % 16) == 0)
81                         printf("\n");
82         }
83         printf("\n");
84 }
85 #endif
86
87 /**
88  * send_rrq - Sends a read request package.
89  *
90  * @fd:          Socket Descriptor
91  */
92 static void
93 send_rrq(int fd)
94 {
95         int ip_len = 0;
96         int ip6_payload_len    = 0;
97         unsigned short udp_len = 0;
98         unsigned char mode[] = "octet";
99         char *ptr            = NULL;
100         struct iphdr *ip     = NULL;
101         struct ip6hdr *ip6   = NULL;
102         struct udphdr *udph  = NULL;
103         struct tftphdr *tftp = NULL;
104
105         memset(packet, 0, BUFFER_LEN);
106
107         if (4 == ip_version) {
108                 ip = (struct iphdr *) packet;
109                 udph = (struct udphdr *) (ip + 1);
110                 ip_len = sizeof(struct iphdr) + sizeof(struct udphdr)
111                         + strlen((char *) fn_ip->filename) + strlen((char *) mode) + 4
112                         + strlen("blksize") + strlen(blocksize_str) + 2;
113                 fill_iphdr ((uint8_t *) ip, ip_len, IPTYPE_UDP, 0,
114                             fn_ip->server_ip);
115         }
116         else if (6 == ip_version) {
117                 ip6 = (struct ip6hdr *) packet;
118                 udph = (struct udphdr *) (ip6 + 1);
119                 ip6_payload_len = sizeof(struct udphdr)
120                         + strlen((char *) fn_ip->filename) + strlen((char *) mode) + 4
121                         + strlen("blksize") + strlen(blocksize_str) + 2;
122                 ip_len = sizeof(struct ip6hdr) + ip6_payload_len;
123                 fill_ip6hdr ((uint8_t *) ip6, ip6_payload_len, IPTYPE_UDP, get_ipv6_address(),
124                              &(fn_ip->server_ip6)); 
125
126         }
127         udp_len = htons(sizeof(struct udphdr)
128                               + strlen((char *) fn_ip->filename) + strlen((char *) mode) + 4
129                               + strlen("blksize") + strlen(blocksize_str) + 2);
130         fill_udphdr ((uint8_t *) udph, udp_len, htons(2001), htons(69));
131
132         tftp = (struct tftphdr *) (udph + 1);
133         tftp->th_opcode = htons(RRQ);
134
135         ptr = (char *) &tftp->th_data;
136         memcpy(ptr, fn_ip->filename, strlen((char *) fn_ip->filename) + 1);
137
138         ptr += strlen((char *) fn_ip->filename) + 1;
139         memcpy(ptr, mode, strlen((char *) mode) + 1);
140
141         ptr += strlen((char *) mode) + 1;
142         memcpy(ptr, "blksize", strlen("blksize") + 1);
143
144         ptr += strlen("blksize") + 1;
145         memcpy(ptr, blocksize_str, strlen(blocksize_str) + 1);
146
147         send_ip (fd, packet, ip_len);
148
149 #ifdef __DEBUG__
150         printf("tftp RRQ with %d bytes transmitted.\n", ip_len);
151 #endif
152         return;
153 }
154
155 /**
156  * send_ack - Sends a acknowlege package.
157  *
158  * @blckno: block number
159  * @dport:  UDP destination port
160  */
161 static void
162 send_ack(int fd, int blckno, unsigned short dport)
163 {
164         int ip_len             = 0;
165         int ip6_payload_len    = 0;
166         unsigned short udp_len = 0;
167         struct iphdr *ip     = NULL;
168         struct ip6hdr *ip6   = NULL;
169         struct udphdr *udph  = NULL;
170         struct tftphdr *tftp = NULL;
171
172         memset(packet, 0, BUFFER_LEN);
173
174         if (4 == ip_version) {
175                 ip = (struct iphdr *) packet;
176                 udph = (struct udphdr *) (ip + 1);
177                 ip_len = sizeof(struct iphdr) + sizeof(struct udphdr) + 4;
178                 fill_iphdr ((uint8_t *) ip, ip_len, IPTYPE_UDP, 0,
179                             fn_ip->server_ip);
180         }
181         else if (6 == ip_version) {
182                 ip6 = (struct ip6hdr *) packet;
183                 udph = (struct udphdr *) (ip6 + 1);
184                 ip6_payload_len = sizeof(struct udphdr) + 4;
185                 ip_len = sizeof(struct ethhdr) + sizeof(struct ip6hdr) +
186                          ip6_payload_len;
187                 fill_ip6hdr ((uint8_t *) ip6, ip6_payload_len, IPTYPE_UDP, get_ipv6_address(),
188                              &(fn_ip->server_ip6));
189         }
190         udp_len = htons(sizeof(struct udphdr) + 4);
191         fill_udphdr ((uint8_t *) udph, udp_len, htons(2001), htons(dport));
192
193         tftp = (struct tftphdr *) (udph + 1);
194         tftp->th_opcode = htons(ACK);
195         tftp->th_data = htons(blckno);
196
197         send_ip(fd, packet, ip_len);
198
199 #ifdef __DEBUG__
200         printf("tftp ACK %d bytes transmitted.\n", ip_len);
201 #endif
202
203         return;
204 }
205
206 /**
207  * send_error - Sends an error package.
208  *
209  * @fd:          Socket Descriptor
210  * @error_code:  Used sub code for error packet
211  * @dport:       UDP destination port
212  */
213 static void
214 send_error(int fd, int error_code, unsigned short dport)
215 {
216         int ip_len             = 0;
217         int ip6_payload_len    = 0;
218         unsigned short udp_len = 0;
219         struct ip6hdr *ip6   = NULL;
220         struct iphdr *ip     = NULL;
221         struct udphdr *udph  = NULL;
222         struct tftphdr *tftp = NULL;
223
224         memset(packet, 0, BUFFER_LEN);
225
226         if (4 == ip_version) {
227                 ip = (struct iphdr *) packet;
228                 udph = (struct udphdr *) (ip + 1);
229                 ip_len = sizeof(struct iphdr) + sizeof(struct udphdr) + 5;
230                 fill_iphdr ((uint8_t *) ip, ip_len, IPTYPE_UDP, 0,
231                             fn_ip->server_ip);
232         }
233         else if (6 == ip_version) {
234                 ip6 = (struct ip6hdr *) packet;
235                 udph = (struct udphdr *) (ip6 + 1);
236                 ip6_payload_len = sizeof(struct udphdr) + 5;
237                 ip_len = sizeof(struct ethhdr) + sizeof(struct ip6hdr) +
238                          ip6_payload_len; 
239                 fill_ip6hdr ((uint8_t *) ip6, ip6_payload_len, IPTYPE_UDP, get_ipv6_address(),
240                             &(fn_ip->server_ip6));
241         }
242         udp_len = htons(sizeof(struct udphdr) + 5);
243         fill_udphdr ((uint8_t *) udph, udp_len, htons(2001), htons(dport));
244
245         tftp = (struct tftphdr *) (udph + 1);
246         tftp->th_opcode = htons(ERROR);
247         tftp->th_data = htons(error_code);
248         ((char *) &tftp->th_data)[2] = 0;
249
250         send_ip(fd, packet, ip_len);
251
252 #ifdef __DEBUG__
253         printf("tftp ERROR %d bytes transmitted.\n", ip_len);
254 #endif
255
256         return;
257 }
258
259 static void
260 print_progress(int urgent, int received_bytes)
261 {
262         static unsigned int i = 1;
263         static int first = -1;
264         static int last_bytes = 0;
265         char buffer[100];
266         char *ptr;
267
268         // 1MB steps or 0x400 times or urgent 
269         if(((received_bytes - last_bytes) >> 20) > 0
270         || (i & 0x3FF) == 0 || urgent) {
271                 if(!first) {
272                         sprintf(buffer, "%d KBytes", (last_bytes >> 10));
273                         for(ptr = buffer; *ptr != 0; ++ptr)
274                                 *ptr = '\b';
275                         printf(buffer);
276                 }
277                 printf("%d KBytes", (received_bytes >> 10));
278                 i = 1;
279                 first = 0;
280                 last_bytes = received_bytes;
281         }
282         ++i;
283 }
284
285 /**
286  * get_blksize tries to extract the blksize from the OACK package
287  * the TFTP returned. From RFC 1782
288  * The OACK packet has the following format:
289  *
290  *   +-------+---~~---+---+---~~---+---+---~~---+---+---~~---+---+
291  *   |  opc  |  opt1  | 0 | value1 | 0 |  optN  | 0 | valueN | 0 |
292  *   +-------+---~~---+---+---~~---+---+---~~---+---+---~~---+---+
293  *
294  * @param buffer  the network packet
295  * @param len  the length of the network packet
296  * @return  the blocksize the server supports or 0 for error
297  */
298 static int
299 get_blksize(unsigned char *buffer, unsigned int len)
300 {
301         unsigned char *orig = buffer;
302         /* skip all headers until tftp has been reached */
303         buffer += sizeof(struct udphdr);
304         /* skip opc */
305         buffer += 2;
306         while (buffer < orig + len) {
307                 if (!memcmp(buffer, "blksize", strlen("blksize") + 1))
308                         return (unsigned short) strtoul((char *) (buffer +
309                                                         strlen("blksize") + 1),
310                                                         (char **) NULL, 10);
311                 else {
312                         /* skip the option name */
313                         buffer = (unsigned char *) strchr((char *) buffer, 0);
314                         if (!buffer)
315                                 return 0;
316                         buffer++;
317                         /* skip the option value */
318                         buffer = (unsigned char *) strchr((char *) buffer, 0);
319                         if (!buffer)
320                                 return 0;
321                         buffer++;
322                 }
323         }
324         return 0;
325 }
326
327 /**
328  * Handle incoming tftp packets after read request was sent 
329  *
330  * this function also prints out some status characters
331  * \|-/ for each packet received
332  * A for an arp packet
333  * I for an ICMP packet
334  * #+* for different unexpected TFTP packets (not very good)
335  *
336  * @param fd     socket descriptor
337  * @param packet points to the UDP header of the packet 
338  * @param len    the length of the network packet
339  * @return       ZERO if packet was handled successfully
340  *               ERRORCODE if error occurred 
341  */
342 int32_t
343 handle_tftp(int fd, uint8_t *pkt, int32_t packetsize) 
344 {
345         struct udphdr *udph;
346         struct tftphdr *tftp;
347
348         /* buffer is only set if we are handling TFTP */
349         if (buffer == NULL )
350                 return 0;
351
352 #ifndef __DEBUG__
353         print_progress(0, received_len);
354 #endif
355         udph = (struct udphdr *) pkt;
356         tftp = (struct tftphdr *) ((void *) udph + sizeof(struct udphdr));
357         set_timer(TICKS_SEC);
358
359 #ifdef __DEBUG__
360         dump_package(pkt, packetsize);
361 #endif
362
363         port_number = udph->uh_sport;
364         if (tftp->th_opcode == htons(OACK)) {
365                 /* an OACK means that the server answers our blocksize request */
366                 blocksize = get_blksize(pkt, packetsize);
367                 if (!blocksize || blocksize > MAX_BLOCKSIZE) {
368                         send_error(fd, 8, port_number);
369                         tftp_errno = -8;
370                         goto error;
371                 }
372                 send_ack(fd, 0, port_number);
373         } else if (tftp->th_opcode == htons(ACK)) {
374                 /* an ACK means that the server did not answers
375                  * our blocksize request, therefore we will set the blocksize
376                  * to the default value of 512 */
377                 blocksize = 512;
378                 send_ack(fd, 0, port_number);
379         } else if ((unsigned char) tftp->th_opcode == ERROR) {
380 #ifdef __DEBUG__
381                 printf("tftp->th_opcode : %x\n", tftp->th_opcode);
382                 printf("tftp->th_data   : %x\n", tftp->th_data);
383 #endif
384                 switch ( (uint8_t) tftp->th_data) {
385                 case ENOTFOUND:
386                         tftp_errno = -3;        // ERROR: file not found
387                         break;
388                 case EACCESS:
389                         tftp_errno = -4;        // ERROR: access violation
390                         break;
391                 case EBADOP:
392                         tftp_errno = -5;        // ERROR: illegal TFTP operation
393                         break;
394                 case EBADID:
395                         tftp_errno = -6;        // ERROR: unknown transfer ID
396                         break;
397                 case ENOUSER:
398                         tftp_errno = -7;        // ERROR: no such user
399                         break;
400                 default:        
401                         tftp_errno = -1;        // ERROR: unknown error
402                 }
403                 goto error;
404         } else if (tftp->th_opcode == DATA) {
405                 /* DATA PACKAGE */
406                 if (block + 1 == tftp->th_data) {
407                         ++block;
408                 }
409                 else if( block == 0xffff && huge_load != 0
410                      &&  (tftp->th_data == 0 || tftp->th_data == 1) ) {
411                         block = tftp->th_data;
412                 }
413                 else if (tftp->th_data == block) {
414 #ifdef __DEBUG__
415                         printf
416                             ("\nTFTP: Received block %x, expected block was %x\n",
417                              tftp->th_data, block + 1);
418                         printf("\b+ ");
419 #endif
420                         send_ack(fd, tftp->th_data, port_number);
421                         lost_packets++;
422                         tftp_err->bad_tftp_packets++;
423                         return 0;
424                 } else if (tftp->th_data < block) {
425 #ifdef __DEBUG__
426                         printf
427                             ("\nTFTP: Received block %x, expected block was %x\n",
428                              tftp->th_data, block + 1);
429                         printf("\b* ");
430 #endif
431                         /* This means that an old data packet appears (again);
432                          * this happens sometimes if we don't answer fast enough
433                          * and a timeout is generated on the server side;
434                          * as we already have this packet we just ignore it */
435                         tftp_err->bad_tftp_packets++;
436                         return 0;
437                 } else {
438                         tftp_err->blocks_missed = block + 1;
439                         tftp_err->blocks_received = tftp->th_data;
440                         tftp_errno = -42;
441                         goto error;
442                 }
443                 tftp_err->bad_tftp_packets = 0;
444                 /* check if our buffer is large enough */
445                 if (received_len + udph->uh_ulen - 12 > len) {
446                         tftp_errno = -2;
447                         goto error;
448                 }
449                 memcpy(buffer + received_len, &tftp->th_data + 1,
450                        udph->uh_ulen - 12);
451                 send_ack(fd, tftp->th_data, port_number);
452                 received_len += udph->uh_ulen - 12;
453                 /* Last packet reached if the payload of the UDP packet
454                  * is smaller than blocksize + 12
455                  * 12 = UDP header (8) + 4 bytes TFTP payload */
456                 if (udph->uh_ulen < blocksize + 12) {
457                         tftp_finished = 1;
458                         return 0;
459                 }
460                 /* 0xffff is the highest block number possible
461                  * see the TFTP RFCs */
462
463                 if (block >= 0xffff && huge_load == 0) {
464                         tftp_errno = -9;
465                         goto error;
466                 }
467         } else {
468 #ifdef __DEBUG__
469                 printf("Unknown packet %x\n", tftp->th_opcode);
470                 printf("\b# ");
471 #endif
472                 tftp_err->bad_tftp_packets++;
473                 return 0;
474         }
475
476         return 0;
477
478 error:
479 #ifdef __DEBUG__
480         printf("\nTFTP errno: %d\n", tftp_errno);
481 #endif
482         tftp_finished = 1;
483         return tftp_errno;
484 }
485
486 /**
487  * TFTP: This function handles situation when "Destination unreachable"
488  *       ICMP-error occurs during sending TFTP-packet.
489  *
490  * @param  err_code   Error Code (e.g. "Host unreachable")
491  */
492 void
493 handle_tftp_dun(uint8_t err_code)
494 {
495         tftp_errno = - err_code - 10;
496         tftp_finished = 1;
497 }
498
499 /**
500  * TFTP: Interface function to load files via TFTP.
501  *
502  * @param  _fn_ip        contains the following configuration information:
503  *                       client IP, TFTP-server IP, filename to be loaded
504  * @param  _buffer       destination buffer for the file
505  * @param  _len          size of destination buffer
506  * @param  _retries      max number of retries
507  * @param  _tftp_err     contains info about TFTP-errors (e.g. lost packets)
508  * @param  _mode         NON ZERO - multicast, ZERO - unicast
509  * @param  _blocksize    blocksize for DATA-packets
510  * @return               ZERO - error condition occurs
511  *                       NON ZERO - size of received file
512  */
513 int
514 tftp(filename_ip_t * _fn_ip, unsigned char *_buffer, int _len,
515      unsigned int _retries, tftp_err_t * _tftp_err,
516      int32_t _mode, int32_t _blocksize, int _ip_version)
517 {
518         retries     = _retries;
519         fn_ip       = _fn_ip;
520         len         = _len;
521         huge_load   = _mode;
522         ip_version  = _ip_version;
523         tftp_errno  = 0;
524         tftp_err    = _tftp_err;
525         tftp_err->bad_tftp_packets = 0;
526         tftp_err->no_packets = 0;
527
528         /* Default blocksize must be 512 for TFTP servers
529          * which do not support the RRQ blocksize option */
530         blocksize = 512;
531
532         /* Preferred blocksize - used as option for the read request */
533         if (_blocksize < 8)
534                 _blocksize = 8;
535         else if (_blocksize > MAX_BLOCKSIZE)
536                 _blocksize = MAX_BLOCKSIZE;
537         sprintf(blocksize_str, "%d", _blocksize);
538
539         printf("  Receiving data:  ");
540         print_progress(-1, 0);
541
542         // Setting buffer to a non-zero address enabled handling of received TFTP packets.
543         buffer = _buffer;
544
545         set_timer(TICKS_SEC);
546         send_rrq(fn_ip->fd);
547
548         while (! tftp_finished) {
549                 /* if timeout (no packet received) */
550                 if(get_timer() <= 0) {
551                         /* the server doesn't seem to retry let's help out a bit */
552                         if (tftp_err->no_packets > 4 && port_number != -1
553                             && block > 1) {
554                                 send_ack(fn_ip->fd, block, port_number);
555                         }
556                         else if (port_number == -1 && block == 0
557                                  && (tftp_err->no_packets&3) == 3) {
558                                 printf("\nRepeating TFTP read request...\n");
559                                 send_rrq(fn_ip->fd);
560                         }
561                         tftp_err->no_packets++;
562                         set_timer(TICKS_SEC);
563                 }
564
565                 /* handle received packets */
566                 receive_ether(fn_ip->fd);
567
568                 /* bad_tftp_packets are counted whenever we receive a TFTP packet
569                         * which was not expected; if this gets larger than 'retries'
570                         * we just exit */
571                 if (tftp_err->bad_tftp_packets > retries) {
572                         tftp_errno = -40;
573                         break;
574                 }
575
576                 /* no_packets counts the times we have returned from receive_ether()
577                         * without any packet received; if this gets larger than 'retries'
578                         * we also just exit */
579                 if (tftp_err->no_packets > retries) {
580                         tftp_errno = -41;
581                         break;
582                 }
583         }
584
585         // Setting buffer to NULL disables handling of received TFTP packets.
586         buffer = NULL;
587
588         if (tftp_errno)
589                 return tftp_errno;
590
591         print_progress(-1, received_len);
592         printf("\n");
593         if (lost_packets)
594                 printf("Lost ACK packets: %d\n", lost_packets);
595                 
596         return received_len;
597 }