📄 tftp.c
字号:
/* * File: tftp.c * * This is an implementation of a tftp.h interface. This implementation * supplies a file byte stream as pulled from the UDP/IP/ether network stack * via TFTP. * * See Also * tftp.h * * Copyright (C) 2002 RidgeRun, Inc. * Author: RidgeRun, Inc <skranz@ridgerun.com> * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 675 Mass Ave, Cambridge, MA 02139, USA. * * Please report all bugs/problems to the author or <support@dsplinux.net> * * key: RRGPLCR (do not remove) * *////////////////////////////////////////////////////////// A typical TFTP session goes like this://// 1. Device sends the read request to the remote server// indicating the filename of interest and the UDP port// number which is to receive the file blocks.// 2. Remote server sends the next 512 bytes of the file// to the requesting device/port.// 3. Device processes the block of bytes and sends// the remote server a TFTP ACK datagram signaling the// server that the device is ready for the next block.// 4. goto step 2. Process continues until the last byte// of the file has been retrieved. Device finishes// up with a final TFTP ACK to the remote server after// recieving the last block from the server.// Last block can be identified by the one the has// less than 512 bytes or has 0 bytes.//// For more info see page 427,// "Internetworking With TCP/IP (3rd edition, vol 1)"///////////////////////////////////////////////////////#include "types.h"#include "io.h"#include "net.h"#include "util.h"#include "tftp.h"#define NORM_TFTP_PORT 69#define TFTP_RRQ 1#define TFTP_WRQ 2#define TFTP_DATA 3#define TFTP_ACK 4#define TFTP_ERROR 5typedef enum { do_RRQ, do_ACK} dg_type_t;#define MAX_FNAME_CHAR 200typedef struct { unsigned short opcode; unsigned char fname_and_mode[MAX_FNAME_CHAR]; // hmmm? that should be plenty.} tftp_RRQ_datagram_t;typedef struct { unsigned short opcode; unsigned char fname_and_mode[MAX_FNAME_CHAR]; // hmmm? that should be plenty.} tftp_WRQ_datagram_t;typedef struct { unsigned short opcode; unsigned short block_num; unsigned char block_buff[512]; // size as per page 428, "Internetworking With TCP/IP (3rd edition, vol 1)"} tftp_DATA_datagram_t; // total bytes 516.typedef struct { unsigned short opcode; unsigned short block_num;} tftp_ACK_datagram_t;typedef struct { unsigned short opcode; unsigned short err_code; unsigned char err_msg[MAX_FNAME_CHAR]; // hmmm? that should be plenty.} tftp_ERROR_datagram_t;// --tftp_datagram_t--// This datagram can take on any one of these// specific formats. Of course, one at a time// since this is a "union" not a "struct".typedef union { unsigned short opcode; // first 2 bytes indicate which format applies. tftp_RRQ_datagram_t RRQ; tftp_WRQ_datagram_t WRQ; tftp_DATA_datagram_t DATA; tftp_ACK_datagram_t ACK; tftp_ERROR_datagram_t ERROR;} tftp_datagram_t; // total bytes 516 (the largest component of this union).// --full_ether_frame_t--// This memory represents the full buffer space needed// by the various levels of the network stack extending// from TFTP down to the ether chipset. The TFTP layer// will only deal with tftp_data_gram field and as we// pass it to the network stack the other fields will// be supplied as the datagram is furthur prepared before// finally being sent to the remote server as a full// ether frame.typedef struct { ether_hdr_t reserved_space1; ip_hdr_t reserved_space2; udp_hdr_t reserved_space3; tftp_datagram_t tftp_data_gram; long dummy1; // See Note below} __attribute__ ((packed)) full_ether_frame_t;// Note: the dummy1 field just insures that we// tack on an extra 32bits worth to give the// underlying ethernet implementation used the// freedom to round-up the incoming packet size// to the nearest 32bit boudary and still have// the bytes contained within what we define to// be the longest ether frame. They may chose// to round up for speed reasons.// Okay, I've carefully added up the number of bytes that// full_ether_frame_t should contain assuming no compiler// padding. We don't want compiler padding since the// network specs require contiguous fields side-by-side// with no compiler ejected padding. The following// constant will help us catch the padding case at// run-time. If one day we switch to a compiler that does// the padding we'll have to re-architect the way we've// currently choosen to express the full_ether_frame_t here.#define SIZEFULLFRAME (562)// Note:// The Start_Of_Session is a global variable that was added// to work around some network issues discovered on the c5471// platform. The idea is that sometimes the first tftp packet// will not arrive at the destination machine -- so a workaround// at the lowest levels (ether_c5471.c) was to recognize the// start of a tftp session so that if no response arrived at// the ether driver in X milliseconds following the outgoing// tftp packet, then it could retry the packet xmit a number// of times in the hopes to get things going. It seems that// once that first packet arrived at the destination machine// then the remaining packets of the TFTP session seemed to// go fine. The issue seemed to be getting that first packet// of a session to go out. Skranz Jan 2002.//int Start_Of_Session; // See Note Above.static full_ether_frame_t full_ether_frame;static tftp_datagram_t *data_gram;static unsigned char *block_buff_curr;static unsigned char *block_buff_end;static int new_connection;static int Whole_file_xferred;static unsigned short expected_block_num;static unsigned short reply_port;static char tftp_filename[MAX_FNAME_CHAR]; // hmmm?, should be plenty.static char tftp_device_IP[16]; // standard size. "100.200.300.400\0"static char tftp_server_IP[16]; // standard size. "100.200.300.400\0"static char tftp_device_MAC[18];// standard size. "00:e0:81:10:36:cf\0"static char tftp_server_MAC[18];// standard size. "00:50:DA:CC:5D:09\0"/****************************** Routine: Description: Build a tftp datagram as per page 428, "Internetworking With TCP/IP (3rd edition, vol 1)" ******************************/static void build_tftp_datagram(dg_type_t type, // in tftp_datagram_t *data_g, // out unsigned short *num_bytes) // out{ unsigned char *curr; curr = (unsigned char *) data_g; *num_bytes = 0; switch (type) { case do_RRQ: *((unsigned short *)curr) = htons(TFTP_RRQ); curr += 2; util_strcpy (curr,tftp_filename); curr += util_strlen(tftp_filename) + 1; util_strcpy (curr, "octet"); curr += util_strlen("octet") + 1; *num_bytes = curr - (unsigned char *)data_g; break; case do_ACK: data_g->DATA.opcode = htons(TFTP_ACK); data_g->DATA.block_num = htons(expected_block_num-1); *num_bytes = sizeof(tftp_ACK_datagram_t); break; default: SYSTEM_FATAL("Logic Error"); break; }}/****************************** Routine: Description: See tftp.h for more info. ******************************/void connect_tftp(char *device_IP, char *server_IP, char *device_MAC, // MACs may be NULL only if char *server_MAC, // our network stack has ARP. char *fname){ // Just cache the values locally so we'll have them // when we need them for the client's upcoming calls // to getchar_tftp(). util_strcpy(tftp_filename,fname); util_strcpy(tftp_device_IP,device_IP); util_strcpy(tftp_server_IP,server_IP); util_strcpy(tftp_device_MAC,device_MAC);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -