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