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 unsigned 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
72 static void dump_package(unsigned char *buffer, unsigned int len)
76 for (i = 1; i <= len; i++) {
77 printf("%02x%02x ", buffer[i - 1], buffer[i]);
87 * send_rrq - Sends a read request package.
89 * @fd: Socket Descriptor
91 static void send_rrq(int fd)
94 int ip6_payload_len = 0;
95 unsigned short udp_len = 0;
96 unsigned char mode[] = "octet";
98 struct iphdr *ip = NULL;
99 struct ip6hdr *ip6 = NULL;
100 struct udphdr *udph = NULL;
101 struct tftphdr *tftp = NULL;
103 memset(packet, 0, BUFFER_LEN);
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,
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));
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));
130 tftp = (struct tftphdr *) (udph + 1);
131 tftp->th_opcode = htons(RRQ);
133 ptr = (char *) &tftp->th_data;
134 memcpy(ptr, fn_ip->filename, strlen((char *) fn_ip->filename) + 1);
136 ptr += strlen((char *) fn_ip->filename) + 1;
137 memcpy(ptr, mode, strlen((char *) mode) + 1);
139 ptr += strlen((char *) mode) + 1;
140 memcpy(ptr, "blksize", strlen("blksize") + 1);
142 ptr += strlen("blksize") + 1;
143 memcpy(ptr, blocksize_str, strlen(blocksize_str) + 1);
145 send_ip (fd, packet, ip_len);
148 printf("tftp RRQ with %d bytes transmitted.\n", ip_len);
154 * send_ack - Sends a acknowlege package.
156 * @blckno: block number
157 * @dport: UDP destination port
159 static void send_ack(int fd, int blckno, unsigned short dport)
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;
169 memset(packet, 0, BUFFER_LEN);
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,
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));
186 udp_len = htons(sizeof(struct udphdr) + 4);
187 fill_udphdr ((uint8_t *) udph, udp_len, htons(2001), htons(dport));
189 tftp = (struct tftphdr *) (udph + 1);
190 tftp->th_opcode = htons(ACK);
191 tftp->th_data = htons(blckno);
193 send_ip(fd, packet, ip_len);
196 printf("tftp ACK %d bytes transmitted.\n", ip_len);
203 * send_error - Sends an error package.
205 * @fd: Socket Descriptor
206 * @error_code: Used sub code for error packet
207 * @dport: UDP destination port
209 static void send_error(int fd, int error_code, unsigned short dport)
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;
219 memset(packet, 0, BUFFER_LEN);
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,
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));
236 udp_len = htons(sizeof(struct udphdr) + 5);
237 fill_udphdr ((uint8_t *) udph, udp_len, htons(2001), htons(dport));
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;
244 send_ip(fd, packet, ip_len);
247 printf("tftp ERROR %d bytes transmitted.\n", ip_len);
253 static void print_progress(int urgent, int received_bytes)
255 static unsigned int i = 1;
256 static int first = -1;
257 static int last_bytes = 0;
261 // 1MB steps or 0x400 times or urgent
262 if(((received_bytes - last_bytes) >> 20) > 0
263 || (i & 0x3FF) == 0 || urgent) {
265 sprintf(buffer, "%d KBytes", (last_bytes >> 10));
266 for(ptr = buffer; *ptr != 0; ++ptr)
270 printf("%d KBytes", (received_bytes >> 10));
273 last_bytes = received_bytes;
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:
283 * +-------+---~~---+---+---~~---+---+---~~---+---+---~~---+---+
284 * | opc | opt1 | 0 | value1 | 0 | optN | 0 | valueN | 0 |
285 * +-------+---~~---+---+---~~---+---+---~~---+---+---~~---+---+
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
291 static int get_blksize(unsigned char *buffer, unsigned int len)
293 unsigned char *orig = buffer;
294 /* skip all headers until tftp has been reached */
295 buffer += sizeof(struct udphdr);
298 while (buffer < orig + len) {
299 if (!memcmp(buffer, "blksize", strlen("blksize") + 1))
300 return (unsigned short) strtoul((char *) (buffer +
301 strlen("blksize") + 1),
304 /* skip the option name */
305 buffer = (unsigned char *) strchr((char *) buffer, 0);
309 /* skip the option value */
310 buffer = (unsigned char *) strchr((char *) buffer, 0);
320 * Handle incoming tftp packets after read request was sent
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)
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
334 int32_t handle_tftp(int fd, uint8_t *pkt, int32_t packetsize)
337 struct tftphdr *tftp;
339 /* buffer is only set if we are handling TFTP */
344 print_progress(0, received_len);
346 udph = (struct udphdr *) pkt;
347 tftp = (struct tftphdr *) ((void *) udph + sizeof(struct udphdr));
348 set_timer(TICKS_SEC);
351 dump_package(pkt, packetsize);
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);
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 */
369 send_ack(fd, 0, port_number);
370 } else if ((unsigned char) tftp->th_opcode == ERROR) {
372 printf("tftp->th_opcode : %x\n", tftp->th_opcode);
373 printf("tftp->th_data : %x\n", tftp->th_data);
375 switch ( (uint8_t) tftp->th_data) {
377 tftp_errno = -3; // ERROR: file not found
380 tftp_errno = -4; // ERROR: access violation
383 tftp_errno = -5; // ERROR: illegal TFTP operation
386 tftp_errno = -6; // ERROR: unknown transfer ID
389 tftp_errno = -7; // ERROR: no such user
392 tftp_errno = -1; // ERROR: unknown error
395 } else if (tftp->th_opcode == DATA) {
397 if (block + 1 == tftp->th_data) {
400 else if( block == 0xffff && huge_load != 0
401 && (tftp->th_data == 0 || tftp->th_data == 1) ) {
402 block = tftp->th_data;
404 else if (tftp->th_data == block) {
407 ("\nTFTP: Received block %x, expected block was %x\n",
408 tftp->th_data, block + 1);
411 send_ack(fd, tftp->th_data, port_number);
413 tftp_err->bad_tftp_packets++;
415 } else if (tftp->th_data < block) {
418 ("\nTFTP: Received block %x, expected block was %x\n",
419 tftp->th_data, block + 1);
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++;
429 tftp_err->blocks_missed = block + 1;
430 tftp_err->blocks_received = tftp->th_data;
434 tftp_err->bad_tftp_packets = 0;
435 /* check if our buffer is large enough */
436 if (received_len + udph->uh_ulen - 12 > len) {
440 memcpy(buffer + received_len, &tftp->th_data + 1,
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) {
451 /* 0xffff is the highest block number possible
452 * see the TFTP RFCs */
454 if (block >= 0xffff && huge_load == 0) {
460 printf("Unknown packet %x\n", tftp->th_opcode);
463 tftp_err->bad_tftp_packets++;
471 printf("\nTFTP errno: %d\n", tftp_errno);
478 * TFTP: This function handles situation when "Destination unreachable"
479 * ICMP-error occurs during sending TFTP-packet.
481 * @param err_code Error Code (e.g. "Host unreachable")
483 void handle_tftp_dun(uint8_t err_code)
485 tftp_errno = - err_code - 10;
490 * TFTP: Interface function to load files via TFTP.
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
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)
511 ip_version = _ip_version;
513 tftp_err = _tftp_err;
514 tftp_err->bad_tftp_packets = 0;
515 tftp_err->no_packets = 0;
517 /* Default blocksize must be 512 for TFTP servers
518 * which do not support the RRQ blocksize option */
521 /* Preferred blocksize - used as option for the read request */
524 else if (_blocksize > MAX_BLOCKSIZE)
525 _blocksize = MAX_BLOCKSIZE;
526 sprintf(blocksize_str, "%d", _blocksize);
528 printf(" Receiving data: ");
529 print_progress(-1, 0);
531 // Setting buffer to a non-zero address enabled handling of received TFTP packets.
534 set_timer(TICKS_SEC);
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
543 send_ack(fn_ip->fd, block, port_number);
545 else if (port_number == -1 && block == 0
546 && (tftp_err->no_packets&3) == 3) {
547 printf("\nRepeating TFTP read request...\n");
550 tftp_err->no_packets++;
551 set_timer(TICKS_SEC);
554 /* handle received packets */
555 receive_ether(fn_ip->fd);
557 /* bad_tftp_packets are counted whenever we receive a TFTP packet
558 * which was not expected; if this gets larger than 'retries'
560 if (tftp_err->bad_tftp_packets > retries) {
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) {
574 // Setting buffer to NULL disables handling of received TFTP packets.
580 print_progress(-1, received_len);
583 printf("Lost ACK packets: %d\n", lost_packets);