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