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