1 /******************************************************************************
2 * Copyright (c) 2004, 2008 IBM Corporation
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
10 * IBM Corporation - initial implementation
11 *****************************************************************************/
18 #include <sys/socket.h>
27 #define MAX_BLOCKSIZE 1428
28 #define BUFFER_LEN 256
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;
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;
65 * dump_package - Prints a package.
67 * @package: package which is to print
68 * @len: length of the package
73 dump_package(unsigned char *buffer, unsigned int len)
77 for (i = 1; i <= len; i++) {
78 printf("%02x%02x ", buffer[i - 1], buffer[i]);
88 * send_rrq - Sends a read request package.
90 * @fd: Socket Descriptor
96 int ip6_payload_len = 0;
97 unsigned short udp_len = 0;
98 unsigned char mode[] = "octet";
100 struct iphdr *ip = NULL;
101 struct ip6hdr *ip6 = NULL;
102 struct udphdr *udph = NULL;
103 struct tftphdr *tftp = NULL;
105 memset(packet, 0, BUFFER_LEN);
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,
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));
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));
132 tftp = (struct tftphdr *) (udph + 1);
133 tftp->th_opcode = htons(RRQ);
135 ptr = (char *) &tftp->th_data;
136 memcpy(ptr, fn_ip->filename, strlen((char *) fn_ip->filename) + 1);
138 ptr += strlen((char *) fn_ip->filename) + 1;
139 memcpy(ptr, mode, strlen((char *) mode) + 1);
141 ptr += strlen((char *) mode) + 1;
142 memcpy(ptr, "blksize", strlen("blksize") + 1);
144 ptr += strlen("blksize") + 1;
145 memcpy(ptr, blocksize_str, strlen(blocksize_str) + 1);
147 send_ip (fd, packet, ip_len);
150 printf("tftp RRQ with %d bytes transmitted.\n", ip_len);
156 * send_ack - Sends a acknowlege package.
158 * @blckno: block number
159 * @dport: UDP destination port
162 send_ack(int fd, int blckno, unsigned short dport)
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;
172 memset(packet, 0, BUFFER_LEN);
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,
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) +
187 fill_ip6hdr ((uint8_t *) ip6, ip6_payload_len, IPTYPE_UDP, get_ipv6_address(),
188 &(fn_ip->server_ip6));
190 udp_len = htons(sizeof(struct udphdr) + 4);
191 fill_udphdr ((uint8_t *) udph, udp_len, htons(2001), htons(dport));
193 tftp = (struct tftphdr *) (udph + 1);
194 tftp->th_opcode = htons(ACK);
195 tftp->th_data = htons(blckno);
197 send_ip(fd, packet, ip_len);
200 printf("tftp ACK %d bytes transmitted.\n", ip_len);
207 * send_error - Sends an error package.
209 * @fd: Socket Descriptor
210 * @error_code: Used sub code for error packet
211 * @dport: UDP destination port
214 send_error(int fd, int error_code, unsigned short dport)
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;
224 memset(packet, 0, BUFFER_LEN);
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,
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) +
239 fill_ip6hdr ((uint8_t *) ip6, ip6_payload_len, IPTYPE_UDP, get_ipv6_address(),
240 &(fn_ip->server_ip6));
242 udp_len = htons(sizeof(struct udphdr) + 5);
243 fill_udphdr ((uint8_t *) udph, udp_len, htons(2001), htons(dport));
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;
250 send_ip(fd, packet, ip_len);
253 printf("tftp ERROR %d bytes transmitted.\n", ip_len);
260 print_progress(int urgent, int received_bytes)
262 static unsigned int i = 1;
263 static int first = -1;
264 static int last_bytes = 0;
268 // 1MB steps or 0x400 times or urgent
269 if(((received_bytes - last_bytes) >> 20) > 0
270 || (i & 0x3FF) == 0 || urgent) {
272 sprintf(buffer, "%d KBytes", (last_bytes >> 10));
273 for(ptr = buffer; *ptr != 0; ++ptr)
277 printf("%d KBytes", (received_bytes >> 10));
280 last_bytes = received_bytes;
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:
290 * +-------+---~~---+---+---~~---+---+---~~---+---+---~~---+---+
291 * | opc | opt1 | 0 | value1 | 0 | optN | 0 | valueN | 0 |
292 * +-------+---~~---+---+---~~---+---+---~~---+---+---~~---+---+
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
299 get_blksize(unsigned char *buffer, unsigned int len)
301 unsigned char *orig = buffer;
302 /* skip all headers until tftp has been reached */
303 buffer += sizeof(struct udphdr);
306 while (buffer < orig + len) {
307 if (!memcmp(buffer, "blksize", strlen("blksize") + 1))
308 return (unsigned short) strtoul((char *) (buffer +
309 strlen("blksize") + 1),
312 /* skip the option name */
313 buffer = (unsigned char *) strchr((char *) buffer, 0);
317 /* skip the option value */
318 buffer = (unsigned char *) strchr((char *) buffer, 0);
328 * Handle incoming tftp packets after read request was sent
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)
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
343 handle_tftp(int fd, uint8_t *pkt, int32_t packetsize)
346 struct tftphdr *tftp;
348 /* buffer is only set if we are handling TFTP */
353 print_progress(0, received_len);
355 udph = (struct udphdr *) pkt;
356 tftp = (struct tftphdr *) ((void *) udph + sizeof(struct udphdr));
357 set_timer(TICKS_SEC);
360 dump_package(pkt, packetsize);
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);
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 */
378 send_ack(fd, 0, port_number);
379 } else if ((unsigned char) tftp->th_opcode == ERROR) {
381 printf("tftp->th_opcode : %x\n", tftp->th_opcode);
382 printf("tftp->th_data : %x\n", tftp->th_data);
384 switch ( (uint8_t) tftp->th_data) {
386 tftp_errno = -3; // ERROR: file not found
389 tftp_errno = -4; // ERROR: access violation
392 tftp_errno = -5; // ERROR: illegal TFTP operation
395 tftp_errno = -6; // ERROR: unknown transfer ID
398 tftp_errno = -7; // ERROR: no such user
401 tftp_errno = -1; // ERROR: unknown error
404 } else if (tftp->th_opcode == DATA) {
406 if (block + 1 == tftp->th_data) {
409 else if( block == 0xffff && huge_load != 0
410 && (tftp->th_data == 0 || tftp->th_data == 1) ) {
411 block = tftp->th_data;
413 else if (tftp->th_data == block) {
416 ("\nTFTP: Received block %x, expected block was %x\n",
417 tftp->th_data, block + 1);
420 send_ack(fd, tftp->th_data, port_number);
422 tftp_err->bad_tftp_packets++;
424 } else if (tftp->th_data < block) {
427 ("\nTFTP: Received block %x, expected block was %x\n",
428 tftp->th_data, block + 1);
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++;
438 tftp_err->blocks_missed = block + 1;
439 tftp_err->blocks_received = tftp->th_data;
443 tftp_err->bad_tftp_packets = 0;
444 /* check if our buffer is large enough */
445 if (received_len + udph->uh_ulen - 12 > len) {
449 memcpy(buffer + received_len, &tftp->th_data + 1,
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) {
460 /* 0xffff is the highest block number possible
461 * see the TFTP RFCs */
463 if (block >= 0xffff && huge_load == 0) {
469 printf("Unknown packet %x\n", tftp->th_opcode);
472 tftp_err->bad_tftp_packets++;
480 printf("\nTFTP errno: %d\n", tftp_errno);
487 * TFTP: This function handles situation when "Destination unreachable"
488 * ICMP-error occurs during sending TFTP-packet.
490 * @param err_code Error Code (e.g. "Host unreachable")
493 handle_tftp_dun(uint8_t err_code)
495 tftp_errno = - err_code - 10;
500 * TFTP: Interface function to load files via TFTP.
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
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)
522 ip_version = _ip_version;
524 tftp_err = _tftp_err;
525 tftp_err->bad_tftp_packets = 0;
526 tftp_err->no_packets = 0;
528 /* Default blocksize must be 512 for TFTP servers
529 * which do not support the RRQ blocksize option */
532 /* Preferred blocksize - used as option for the read request */
535 else if (_blocksize > MAX_BLOCKSIZE)
536 _blocksize = MAX_BLOCKSIZE;
537 sprintf(blocksize_str, "%d", _blocksize);
539 printf(" Receiving data: ");
540 print_progress(-1, 0);
542 // Setting buffer to a non-zero address enabled handling of received TFTP packets.
545 set_timer(TICKS_SEC);
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
554 send_ack(fn_ip->fd, block, port_number);
556 else if (port_number == -1 && block == 0
557 && (tftp_err->no_packets&3) == 3) {
558 printf("\nRepeating TFTP read request...\n");
561 tftp_err->no_packets++;
562 set_timer(TICKS_SEC);
565 /* handle received packets */
566 receive_ether(fn_ip->fd);
568 /* bad_tftp_packets are counted whenever we receive a TFTP packet
569 * which was not expected; if this gets larger than 'retries'
571 if (tftp_err->bad_tftp_packets > retries) {
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) {
585 // Setting buffer to NULL disables handling of received TFTP packets.
591 print_progress(-1, received_len);
594 printf("Lost ACK packets: %d\n", lost_packets);