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 #include <dns.h>
25
26 //#define __DEBUG__
27
28 #define MAX_BLOCKSIZE 1428
29 #define BUFFER_LEN 256
30 #define INVALID_BUFFER ((void *)-1L)
31
32 #define ENOTFOUND 1
33 #define EACCESS 2
34 #define EBADOP 4
35 #define EBADID 5
36 #define ENOUSER 7
37 //#define EUNDEF 0
38 //#define ENOSPACE 3
39 //#define EEXISTS 6
40
41 #define RRQ 1
42 #define WRQ 2
43 #define DATA 3
44 #define ACK 4
45 #define ERROR 5
46 #define OACK 6
47
48 /* Local variables */
49 static unsigned char packet[BUFFER_LEN];
50 static unsigned char *buffer = INVALID_BUFFER;
51 static unsigned short block;
52 static unsigned short blocksize;
53 static char blocksize_str[6]; /* Blocksize string for read request */
54 static int received_len;
55 static unsigned int retries;
56 static int huge_load;
57 static int len;
58 static int tftp_finished;
59 static int lost_packets;
60 static int tftp_errno;
61 static int ip_version;
62 static short port_number;
63 static tftp_err_t *tftp_err;
64 static filename_ip_t *fn_ip;
65 static int progress_first;
66 static int progress_last_bytes;
67
68 /**
69 * dump_package - Prints a package.
70 *
71 * @package: package which is to print
72 * @len: length of the package
73 */
74 #ifdef __DEBUG__
75
dump_package(unsigned char * buffer,unsigned int len)76 static void dump_package(unsigned char *buffer, unsigned int len)
77 {
78 int i;
79
80 for (i = 1; i <= len; i++) {
81 printf("%02x%02x ", buffer[i - 1], buffer[i]);
82 i++;
83 if ((i % 16) == 0)
84 printf("\n");
85 }
86 printf("\n");
87 }
88 #endif
89
90 /**
91 * send_rrq - Sends a read request package.
92 *
93 * @fd: Socket Descriptor
94 */
send_rrq(int fd)95 static void send_rrq(int fd)
96 {
97 int ip_len = 0;
98 int ip6_payload_len = 0;
99 unsigned short udp_len = 0;
100 const char mode[] = "octet";
101 char *ptr = NULL;
102 struct iphdr *ip = NULL;
103 struct ip6hdr *ip6 = NULL;
104 struct udphdr *udph = NULL;
105 struct tftphdr *tftp = NULL;
106
107 memset(packet, 0, BUFFER_LEN);
108
109 if (4 == ip_version) {
110 ip = (struct iphdr *) packet;
111 udph = (struct udphdr *) (ip + 1);
112 ip_len = sizeof(struct iphdr) + sizeof(struct udphdr)
113 + strlen(fn_ip->filename) + strlen(mode) + 4
114 + strlen("blksize") + strlen(blocksize_str) + 2;
115 fill_iphdr ((uint8_t *) ip, ip_len, IPTYPE_UDP, 0,
116 fn_ip->server_ip);
117 }
118 else if (6 == ip_version) {
119 ip6 = (struct ip6hdr *) packet;
120 udph = (struct udphdr *) (ip6 + 1);
121 ip6_payload_len = sizeof(struct udphdr)
122 + strlen(fn_ip->filename) + strlen(mode) + 4
123 + strlen("blksize") + strlen(blocksize_str) + 2;
124 ip_len = sizeof(struct ip6hdr) + ip6_payload_len;
125 fill_ip6hdr ((uint8_t *) ip6, ip6_payload_len, IPTYPE_UDP, get_ipv6_address(),
126 &(fn_ip->server_ip6));
127
128 }
129 udp_len = htons(sizeof(struct udphdr)
130 + strlen(fn_ip->filename) + strlen(mode) + 4
131 + strlen("blksize") + strlen(blocksize_str) + 2);
132 fill_udphdr ((uint8_t *) udph, udp_len, htons(2001), htons(69));
133
134 tftp = (struct tftphdr *) (udph + 1);
135 tftp->th_opcode = htons(RRQ);
136
137 ptr = (char *) &tftp->th_data;
138 memcpy(ptr, fn_ip->filename, strlen(fn_ip->filename) + 1);
139
140 ptr += strlen(fn_ip->filename) + 1;
141 memcpy(ptr, mode, strlen(mode) + 1);
142
143 ptr += strlen(mode) + 1;
144 memcpy(ptr, "blksize", strlen("blksize") + 1);
145
146 ptr += strlen("blksize") + 1;
147 memcpy(ptr, blocksize_str, strlen(blocksize_str) + 1);
148
149 send_ip (fd, packet, ip_len);
150
151 #ifdef __DEBUG__
152 printf("tftp RRQ with %d bytes transmitted.\n", ip_len);
153 #endif
154 return;
155 }
156
157 /**
158 * send_ack - Sends a acknowlege package.
159 *
160 * @blckno: block number
161 * @dport: UDP destination port
162 */
send_ack(int fd,int blckno,unsigned short dport)163 static void send_ack(int fd, int blckno, unsigned short dport)
164 {
165 int ip_len = 0;
166 int ip6_payload_len = 0;
167 unsigned short udp_len = 0;
168 struct iphdr *ip = NULL;
169 struct ip6hdr *ip6 = NULL;
170 struct udphdr *udph = NULL;
171 struct tftphdr *tftp = NULL;
172
173 memset(packet, 0, BUFFER_LEN);
174
175 if (4 == ip_version) {
176 ip = (struct iphdr *) packet;
177 udph = (struct udphdr *) (ip + 1);
178 ip_len = sizeof(struct iphdr) + sizeof(struct udphdr) + 4;
179 fill_iphdr ((uint8_t *) ip, ip_len, IPTYPE_UDP, 0,
180 fn_ip->server_ip);
181 }
182 else if (6 == ip_version) {
183 ip6 = (struct ip6hdr *) packet;
184 udph = (struct udphdr *) (ip6 + 1);
185 ip6_payload_len = sizeof(struct udphdr) + 4;
186 ip_len = sizeof(struct ip6hdr) + 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 */
send_error(int fd,int error_code,unsigned short dport)213 static void send_error(int fd, int error_code, unsigned short dport)
214 {
215 int ip_len = 0;
216 int ip6_payload_len = 0;
217 unsigned short udp_len = 0;
218 struct ip6hdr *ip6 = NULL;
219 struct iphdr *ip = NULL;
220 struct udphdr *udph = NULL;
221 struct tftphdr *tftp = NULL;
222
223 memset(packet, 0, BUFFER_LEN);
224
225 if (4 == ip_version) {
226 ip = (struct iphdr *) packet;
227 udph = (struct udphdr *) (ip + 1);
228 ip_len = sizeof(struct iphdr) + sizeof(struct udphdr) + 5;
229 fill_iphdr ((uint8_t *) ip, ip_len, IPTYPE_UDP, 0,
230 fn_ip->server_ip);
231 }
232 else if (6 == ip_version) {
233 ip6 = (struct ip6hdr *) packet;
234 udph = (struct udphdr *) (ip6 + 1);
235 ip6_payload_len = sizeof(struct udphdr) + 5;
236 ip_len = sizeof(struct ip6hdr) + ip6_payload_len;
237 fill_ip6hdr ((uint8_t *) ip6, ip6_payload_len, IPTYPE_UDP, get_ipv6_address(),
238 &(fn_ip->server_ip6));
239 }
240 udp_len = htons(sizeof(struct udphdr) + 5);
241 fill_udphdr ((uint8_t *) udph, udp_len, htons(2001), htons(dport));
242
243 tftp = (struct tftphdr *) (udph + 1);
244 tftp->th_opcode = htons(ERROR);
245 tftp->th_data = htons(error_code);
246 ((char *) &tftp->th_data)[2] = 0;
247
248 send_ip(fd, packet, ip_len);
249
250 #ifdef __DEBUG__
251 printf("tftp ERROR %d bytes transmitted.\n", ip_len);
252 #endif
253
254 return;
255 }
256
print_progress(int urgent,int received_bytes)257 static void print_progress(int urgent, int received_bytes)
258 {
259 static unsigned int i = 1;
260 char buffer[100];
261 char *ptr;
262
263 // 1MB steps or 0x400 times or urgent
264 if(((received_bytes - progress_last_bytes) >> 20) > 0
265 || (i & 0x3FF) == 0 || urgent) {
266 if (!progress_first) {
267 sprintf(buffer, "%d KBytes", (progress_last_bytes >> 10));
268 for(ptr = buffer; *ptr != 0; ++ptr)
269 *ptr = '\b';
270 printf("%s", buffer);
271 }
272 printf("%d KBytes", (received_bytes >> 10));
273 i = 1;
274 progress_first = 0;
275 progress_last_bytes = received_bytes;
276 }
277 ++i;
278 }
279
280 /**
281 * get_blksize tries to extract the blksize from the OACK package
282 * the TFTP returned. From RFC 1782
283 * The OACK packet has the following format:
284 *
285 * +-------+---~~---+---+---~~---+---+---~~---+---+---~~---+---+
286 * | opc | opt1 | 0 | value1 | 0 | optN | 0 | valueN | 0 |
287 * +-------+---~~---+---+---~~---+---+---~~---+---+---~~---+---+
288 *
289 * @param buffer the network packet
290 * @param len the length of the network packet
291 * @return the blocksize the server supports or 0 for error
292 */
get_blksize(unsigned char * buffer,unsigned int len)293 static int get_blksize(unsigned char *buffer, unsigned int len)
294 {
295 unsigned char *orig = buffer;
296 /* skip all headers until tftp has been reached */
297 buffer += sizeof(struct udphdr);
298 /* skip opc */
299 buffer += 2;
300 while (buffer < orig + len) {
301 if (!memcmp(buffer, "blksize", strlen("blksize") + 1))
302 return (unsigned short) strtoul((char *) (buffer +
303 strlen("blksize") + 1),
304 (char **) NULL, 10);
305 else {
306 /* skip the option name */
307 buffer = (unsigned char *) strchr((char *) buffer, 0);
308 if (!buffer)
309 return 0;
310 buffer++;
311 /* skip the option value */
312 buffer = (unsigned char *) strchr((char *) buffer, 0);
313 if (!buffer)
314 return 0;
315 buffer++;
316 }
317 }
318 return 0;
319 }
320
321 /**
322 * Handle incoming tftp packets after read request was sent
323 *
324 * this function also prints out some status characters
325 * \|-/ for each packet received
326 * A for an arp packet
327 * I for an ICMP packet
328 * #+* for different unexpected TFTP packets (not very good)
329 *
330 * @param fd socket descriptor
331 * @param packet points to the UDP header of the packet
332 * @param len the length of the network packet
333 * @return ZERO if packet was handled successfully
334 * ERRORCODE if error occurred
335 */
handle_tftp(int fd,uint8_t * pkt,int32_t packetsize)336 int32_t handle_tftp(int fd, uint8_t *pkt, int32_t packetsize)
337 {
338 struct udphdr *udph;
339 struct tftphdr *tftp;
340
341 /* buffer is only set if we are handling TFTP */
342 if (buffer == INVALID_BUFFER)
343 return 0;
344
345 #ifndef __DEBUG__
346 print_progress(0, received_len);
347 #endif
348 udph = (struct udphdr *) pkt;
349 tftp = (struct tftphdr *) ((void *) udph + sizeof(struct udphdr));
350 set_timer(TICKS_SEC);
351
352 #ifdef __DEBUG__
353 dump_package(pkt, packetsize);
354 #endif
355
356 port_number = udph->uh_sport;
357 if (tftp->th_opcode == htons(OACK)) {
358 /* an OACK means that the server answers our blocksize request */
359 blocksize = get_blksize(pkt, packetsize);
360 if (!blocksize || blocksize > MAX_BLOCKSIZE) {
361 send_error(fd, 8, port_number);
362 tftp_errno = -8;
363 goto error;
364 }
365 send_ack(fd, 0, port_number);
366 } else if (tftp->th_opcode == htons(ACK)) {
367 /* an ACK means that the server did not answers
368 * our blocksize request, therefore we will set the blocksize
369 * to the default value of 512 */
370 blocksize = 512;
371 send_ack(fd, 0, port_number);
372 } else if ((unsigned char) tftp->th_opcode == ERROR) {
373 #ifdef __DEBUG__
374 printf("tftp->th_opcode : %x\n", tftp->th_opcode);
375 printf("tftp->th_data : %x\n", tftp->th_data);
376 #endif
377 switch ( (uint8_t) tftp->th_data) {
378 case ENOTFOUND:
379 tftp_errno = -3; // ERROR: file not found
380 break;
381 case EACCESS:
382 tftp_errno = -4; // ERROR: access violation
383 break;
384 case EBADOP:
385 tftp_errno = -5; // ERROR: illegal TFTP operation
386 break;
387 case EBADID:
388 tftp_errno = -6; // ERROR: unknown transfer ID
389 break;
390 case ENOUSER:
391 tftp_errno = -7; // ERROR: no such user
392 break;
393 default:
394 tftp_errno = -1; // ERROR: unknown error
395 }
396 goto error;
397 } else if (tftp->th_opcode == DATA) {
398 /* DATA PACKAGE */
399 if (block + 1 == tftp->th_data) {
400 ++block;
401 }
402 else if( block == 0xffff && huge_load != 0
403 && (tftp->th_data == 0 || tftp->th_data == 1) ) {
404 block = tftp->th_data;
405 }
406 else if (tftp->th_data == block) {
407 #ifdef __DEBUG__
408 printf
409 ("\nTFTP: Received block %x, expected block was %x\n",
410 tftp->th_data, block + 1);
411 printf("\b+ ");
412 #endif
413 send_ack(fd, tftp->th_data, port_number);
414 lost_packets++;
415 tftp_err->bad_tftp_packets++;
416 return 0;
417 } else if (tftp->th_data < block) {
418 #ifdef __DEBUG__
419 printf
420 ("\nTFTP: Received block %x, expected block was %x\n",
421 tftp->th_data, block + 1);
422 printf("\b* ");
423 #endif
424 /* This means that an old data packet appears (again);
425 * this happens sometimes if we don't answer fast enough
426 * and a timeout is generated on the server side;
427 * as we already have this packet we just ignore it */
428 tftp_err->bad_tftp_packets++;
429 return 0;
430 } else {
431 tftp_err->blocks_missed = block + 1;
432 tftp_err->blocks_received = tftp->th_data;
433 tftp_errno = -42;
434 goto error;
435 }
436 tftp_err->bad_tftp_packets = 0;
437 /* check if our buffer is large enough */
438 if (received_len + udph->uh_ulen - 12 > len) {
439 tftp_errno = -2;
440 goto error;
441 }
442 memcpy(buffer + received_len, &tftp->th_data + 1,
443 udph->uh_ulen - 12);
444 send_ack(fd, tftp->th_data, port_number);
445 received_len += udph->uh_ulen - 12;
446 /* Last packet reached if the payload of the UDP packet
447 * is smaller than blocksize + 12
448 * 12 = UDP header (8) + 4 bytes TFTP payload */
449 if (udph->uh_ulen < blocksize + 12) {
450 tftp_finished = 1;
451 return 0;
452 }
453 /* 0xffff is the highest block number possible
454 * see the TFTP RFCs */
455
456 if (block >= 0xffff && huge_load == 0) {
457 tftp_errno = -9;
458 goto error;
459 }
460 } else {
461 #ifdef __DEBUG__
462 printf("Unknown packet %x\n", tftp->th_opcode);
463 printf("\b# ");
464 #endif
465 tftp_err->bad_tftp_packets++;
466 return 0;
467 }
468
469 return 0;
470
471 error:
472 #ifdef __DEBUG__
473 printf("\nTFTP errno: %d\n", tftp_errno);
474 #endif
475 tftp_finished = 1;
476 return tftp_errno;
477 }
478
479 /**
480 * TFTP: This function handles situation when "Destination unreachable"
481 * ICMP-error occurs during sending TFTP-packet.
482 *
483 * @param err_code Error Code (e.g. "Host unreachable")
484 */
handle_tftp_dun(uint8_t err_code)485 void handle_tftp_dun(uint8_t err_code)
486 {
487 tftp_errno = - err_code - 10;
488 tftp_finished = 1;
489 }
490
491 /**
492 * TFTP: Interface function to load files via TFTP.
493 *
494 * @param _fn_ip contains the following configuration information:
495 * client IP, TFTP-server IP, filename to be loaded
496 * @param _buffer destination buffer for the file
497 * @param _len size of destination buffer
498 * @param _retries max number of retries
499 * @param _tftp_err contains info about TFTP-errors (e.g. lost packets)
500 * @return ZERO - error condition occurs
501 * NON ZERO - size of received file
502 */
tftp(filename_ip_t * _fn_ip,unsigned char * _buffer,int _len,unsigned int _retries,tftp_err_t * _tftp_err)503 int tftp(filename_ip_t * _fn_ip, unsigned char *_buffer, int _len,
504 unsigned int _retries, tftp_err_t * _tftp_err)
505 {
506 retries = _retries;
507 fn_ip = _fn_ip;
508 len = _len;
509 ip_version = _fn_ip->ip_version;
510 tftp_errno = 0;
511 tftp_err = _tftp_err;
512 tftp_err->bad_tftp_packets = 0;
513 tftp_err->no_packets = 0;
514
515 block = 0;
516 received_len = 0;
517 tftp_finished = 0;
518 lost_packets = 0;
519 port_number = -1;
520 progress_first = -1;
521 progress_last_bytes = 0;
522 huge_load = 1;
523
524 /* Default blocksize must be 512 for TFTP servers
525 * which do not support the RRQ blocksize option */
526 blocksize = 512;
527
528 /* Preferred blocksize - used as option for the read request */
529 sprintf(blocksize_str, "%d", MAX_BLOCKSIZE);
530
531 printf(" Receiving data: ");
532 print_progress(-1, 0);
533
534 /* Set buffer to a valid address, enables handling of received packets */
535 buffer = _buffer;
536
537 set_timer(TICKS_SEC);
538 send_rrq(fn_ip->fd);
539
540 while (! tftp_finished) {
541 /* if timeout (no packet received) */
542 if(get_timer() <= 0) {
543 /* the server doesn't seem to retry let's help out a bit */
544 if (tftp_err->no_packets > 4 && port_number != -1
545 && block > 1) {
546 send_ack(fn_ip->fd, block, port_number);
547 }
548 else if (port_number == -1 && block == 0
549 && (tftp_err->no_packets&3) == 3) {
550 printf("\nRepeating TFTP read request...\n");
551 send_rrq(fn_ip->fd);
552 }
553 tftp_err->no_packets++;
554 set_timer(TICKS_SEC);
555 }
556
557 /* handle received packets */
558 receive_ether(fn_ip->fd);
559
560 /* bad_tftp_packets are counted whenever we receive a TFTP packet
561 * which was not expected; if this gets larger than 'retries'
562 * we just exit */
563 if (tftp_err->bad_tftp_packets > retries) {
564 tftp_errno = -40;
565 break;
566 }
567
568 /* no_packets counts the times we have returned from receive_ether()
569 * without any packet received; if this gets larger than 'retries'
570 * we also just exit */
571 if (tftp_err->no_packets > retries) {
572 tftp_errno = -41;
573 break;
574 }
575 }
576
577 /* Setting buffer invalid to disable handling of received packets */
578 buffer = INVALID_BUFFER;
579
580 if (tftp_errno)
581 return tftp_errno;
582
583 print_progress(-1, received_len);
584 printf("\n");
585 if (lost_packets)
586 printf("Lost ACK packets: %d\n", lost_packets);
587
588 return received_len;
589 }
590
591 /**
592 * Parses a tftp arguments, extracts all
593 * parameters and fills server ip according to this
594 *
595 * Parameters:
596 * @param buffer string with arguments,
597 * @param server_ip server ip as result
598 * @param filename default filename
599 * @param fd Socket descriptor
600 * @param len len of the buffer,
601 * @return 0 on SUCCESS and -1 on failure
602 */
parse_tftp_args(char buffer[],char * server_ip,char filename[],int fd,int len)603 int parse_tftp_args(char buffer[], char *server_ip, char filename[], int fd,
604 int len)
605 {
606 char *raw;
607 char *tmp, *tmp1;
608 int i, j = 0;
609 char domainname[256];
610 uint8_t server_ip6[16];
611
612 raw = malloc(len);
613 if (raw == NULL) {
614 printf("\n unable to allocate memory, parsing failed\n");
615 return -1;
616 }
617 strncpy(raw, (const char *)buffer, len);
618 /* tftp url contains tftp://[fd00:4f53:4444:90:214:5eff:fed9:b200]/testfile */
619 if (strncmp(raw, "tftp://", 7)){
620 printf("\n tftp missing in %s\n", raw);
621 free(raw);
622 return -1;
623 }
624 tmp = strchr(raw, '[');
625 if (tmp != NULL && *tmp == '[') {
626 /* check for valid ipv6 address */
627 tmp1 = strchr(tmp, ']');
628 if (tmp1 == NULL) {
629 printf("\n missing ] in %s\n", raw);
630 free(raw);
631 return -1;
632 }
633 i = tmp1 - tmp;
634 /* look for file name */
635 tmp1 = strchr(tmp, '/');
636 if (tmp1 == NULL) {
637 printf("\n missing filename in %s\n", raw);
638 free(raw);
639 return -1;
640 }
641 tmp[i] = '\0';
642 /* check for 16 byte ipv6 address */
643 if (!str_to_ipv6(tmp + 1, (uint8_t *)server_ip)) {
644 printf("\n wrong format IPV6 address in %s\n", raw);
645 free(raw);
646 return -1;;
647 }
648 else {
649 /* found filename */
650 strcpy(filename, tmp1 + 1);
651 free(raw);
652 return 0;
653 }
654 }
655 else {
656 /* here tftp://hostname/testfile from option request of dhcp */
657 /* look for dns server name */
658 tmp1 = strchr(raw, '.');
659 if (tmp1 == NULL) {
660 printf("\n missing . seperator in %s\n", raw);
661 free(raw);
662 return -1;
663 }
664 /* look for domain name beyond dns server name
665 * so ignore the current . and look for one more */
666 tmp = strchr(tmp1 + 1, '.');
667 if (tmp == NULL) {
668 printf("\n missing domain in %s\n", raw);
669 free(raw);
670 return -1;
671 }
672 tmp1 = strchr(tmp1, '/');
673 if (tmp1 == NULL) {
674 printf("\n missing filename in %s\n", raw);
675 free(raw);
676 return -1;
677 }
678 j = tmp1 - (raw + 7);
679 tmp = raw + 7;
680 tmp[j] = '\0';
681 strcpy(domainname, tmp);
682 if (dns_get_ip(fd, domainname, server_ip6, 6) == 0) {
683 printf("\n DNS failed for IPV6\n");
684 return -1;
685 }
686 ipv6_to_str(server_ip6, server_ip);
687
688 strcpy(filename, tmp1 + 1);
689 free(raw);
690 return 0;
691 }
692 }
693
tftp_get_error_info(filename_ip_t * fnip,tftp_err_t * tftperr,int rc,const char ** errstr,int * ecode)694 int tftp_get_error_info(filename_ip_t *fnip, tftp_err_t *tftperr, int rc,
695 const char **errstr, int *ecode)
696 {
697 static char estrbuf[80];
698
699 if (rc == -1) {
700 *ecode = 0x3003;
701 *errstr = "unknown TFTP error";
702 return -103;
703 } else if (rc == -2) {
704 *ecode = 0x3004;
705 snprintf(estrbuf, sizeof(estrbuf),
706 "TFTP buffer of %d bytes is too small for %s", len,
707 fnip->filename);
708 *errstr = estrbuf;
709 return -104;
710 } else if (rc == -3) {
711 *ecode = 0x3009;
712 snprintf(estrbuf, sizeof(estrbuf), "file not found: %s",
713 fnip->filename);
714 *errstr = estrbuf;
715 return -108;
716 } else if (rc == -4) {
717 *ecode = 0x3010;
718 *errstr = "TFTP access violation";
719 return -109;
720 } else if (rc == -5) {
721 *ecode = 0x3011;
722 *errstr = "illegal TFTP operation";
723 return -110;
724 } else if (rc == -6) {
725 *ecode = 0x3012;
726 *errstr = "unknown TFTP transfer ID";
727 return -111;
728 } else if (rc == -7) {
729 *ecode = 0x3013;
730 *errstr = "no such TFTP user";
731 return -112;
732 } else if (rc == -8) {
733 *ecode = 0x3017;
734 *errstr = "TFTP blocksize negotiation failed";
735 return -116;
736 } else if (rc == -9) {
737 *ecode = 0x3018;
738 *errstr = "file exceeds maximum TFTP transfer size";
739 return -117;
740 } else if (rc <= -10 && rc >= -15) {
741 const char *icmp_err_str;
742 switch (rc) {
743 case -ICMP_NET_UNREACHABLE - 10:
744 icmp_err_str = "net unreachable";
745 break;
746 case -ICMP_HOST_UNREACHABLE - 10:
747 icmp_err_str = "host unreachable";
748 break;
749 case -ICMP_PROTOCOL_UNREACHABLE - 10:
750 icmp_err_str = "protocol unreachable";
751 break;
752 case -ICMP_PORT_UNREACHABLE - 10:
753 icmp_err_str = "port unreachable";
754 break;
755 case -ICMP_FRAGMENTATION_NEEDED - 10:
756 icmp_err_str = "fragmentation needed and DF set";
757 break;
758 case -ICMP_SOURCE_ROUTE_FAILED - 10:
759 icmp_err_str = "source route failed";
760 break;
761 default:
762 icmp_err_str = "UNKNOWN";
763 break;
764 }
765 *ecode = 0x3005;
766 sprintf(estrbuf, "ICMP ERROR \"%s\"", icmp_err_str);
767 *errstr = estrbuf;
768 return -105;
769 } else if (rc == -40) {
770 *ecode = 0x3014;
771 sprintf(estrbuf,
772 "TFTP error occurred after %d bad packets received",
773 tftperr->bad_tftp_packets);
774 *errstr = estrbuf;
775 return -113;
776 } else if (rc == -41) {
777 *ecode = 0x3015;
778 sprintf(estrbuf,
779 "TFTP error occurred after missing %d responses",
780 tftperr->no_packets);
781 *errstr = estrbuf;
782 return -114;
783 } else if (rc == -42) {
784 *ecode = 0x3016;
785 sprintf(estrbuf,
786 "TFTP error missing block %d, expected block was %d",
787 tftperr->blocks_missed, tftperr->blocks_received);
788 *errstr = estrbuf;
789 return -115;
790 }
791
792 return rc;
793 }
794