⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tftp.c

📁 增加了tftp功能的vivi代码
💻 C
字号:
/*************************************************
12月27号,修改了以下几点block_number改成now_block_number;
在udelay中的init()改成init_timer();
发送、接收 数据长度全部定为600

*************************************************/
//#include <stdio.h>
#include <string.h>
#include "net.h"
#include "cs8900.h"
#include "udelay.h"
 u8 receive_packet[600];
 u8 transmit_packet[600];
 u16 now_block_number;
 u16 last_block_number;
//仅此处可用的
#define tftp_read_request_mode 1
#define tftp_ACK_mode 2
#define tftp_data_mode 3
#define tftp_error_mode 5
//结构体声明区
struct tftp_read_request_packet{
u16 opcode;

u8 filename[20];

};

struct tftp_ACK_packet{
u16 opcode;
u16 block_number;
};

struct tftp_data_packet{
u16 opcode;
u16 block_number;
u8 tftp_data[512];
};

struct tftp_error{
u16 opcode;
u16 error_code;
u8 error_message;
};



///函数声明区
static s32 request_packet(u8 *,s32);
static s32 ACK_packet(s32);
static s32 error_packet(void);
static s32 data_unpacket(u8 * , s32 );
static s32 error_unpacket(void);
s32 get_packet(void);
s32 resend_time;
s32 receive_cycle(s32);
unsigned long write_address;
unsigned long write_offset;

//主程序

int tftp(const u8 * filename)
{
//u8 * filename = fp ;
	volatile s32 length,i;
	last_block_number=0;//已收到的块号
	now_block_number=0;//当前收到的块号
	tftp_server_port=69;//服务器.
	init_timer();
	eth_halt();
	eth_init();
	for(resend_time=0;resend_time<3;resend_time++)
	{
	i=arp_broadcast();
	if(i)
	{memcpy(host_MAC_address,receive_packet+6,6);
	resend_time=0;
	printk("\n 192.168.1.10的MAC地址:");
	for(i=0;i<6;i++)
		printk("0x%02lx ",host_MAC_address[i]);
	break;
	}
	}
	
	if(0==i)printk("\n网络不通,连网线啊哥哥!!\n");
	
	i=0;
	length=send_packet(filename,NULL,tftp_read_request_mode);
	last_block_number=0;//第一次发的时候清0;
	now_block_number=0;//第一次发的时候清0;
	
	do{
	length=get_packet();
	if(-3==length) break;
	i++;
	if(i==1000) break;
	}while(512!=length);//只要arp通过就一定可以收得到。到100就是超时
	

	
		if(512!=length) 
		{
		if(-3!=length)
		printk("\n开tftp 服务器没有O?\n");
		else
			printk("\n文件不存在\n");
		
		return 0;
		}
	
	if(now_block_number==1) tftp_server_port=temp_port;
	printk("\n开始接收数据:\n");
	length=receive_cycle(length);
	printk("\n接收数据共%d:\n",length*512);

	/********
	for(i=0;i<20;i++)
	{
	length=send_packet(NULL,1,tftp_ACK_mode);
	length=get_packet();
    }
	*******/
	now_block_number=0;
	last_block_number=0;
	memset(receive_packet,0,600);
	memset(transmit_packet,0,600);
	//MAC地址也清零.
	return length;


}
s32 receive_cycle( s32 length)
{
	volatile unsigned  int i,temp;
	write_address=0x30008000;
	write_offset=0;
	i=1;
	
packet_handle:	
			memcpy((void *)(write_address+write_offset),receive_packet+46,length);
			++last_block_number;
			i++;
			temp=send_packet(NULL,last_block_number ,tftp_ACK_mode);
			write_offset +=512;
			if(length<512) return i;
			if(i%0x20==0)printk("#");
			if(i%0x400==0)printk("\n");
reget:		temp=get_packet();
			if(temp<0) goto error_handle;
			if(now_block_number==(last_block_number+1))
			{
			length=temp; 
			goto packet_handle;
			}//收到正确的包
			if(now_block_number==last_block_number )goto reget;//ACK中途丢失,重发.
			else goto reget;
	
	
error_handle:	
	switch (temp)
	{
	case -1://没有收到任何包
	case -3://服器发出的出错信息包
		printk("有没有搞错啊,这都能出错,你人品也太差了吧!");
		return 0;
	case -2:
		goto reget;//错包重收
	}	
	
	return 0;
	
}

/*************************************************************
在使用这个函数之前需要初始化定时器,CPU频率,还有cs8900要停止后再启动,
入口参数:
	u8 * filename是发送读请求的时候发送的文件名,
	s32 ACK_block_number是发送ACK确认帧的时候当前的块号
	s32 mode 是用来做模式选择。
出口参数:length 发送成功后返回1,失败返回0;
发送完毕后会清零last_block_number,now_block_number,还有transmit_packet.
**************************************************************/
s32 send_packet(u8 *filename,s32 ACK_block_number,s32 mode)
{ s32 length;
	
resend:	length=strlen(filename);
        if(mode==tftp_ACK_mode)length=ACK_block_number;
		length=pack_tftp(filename,length,mode);
		length=pack_UDP(transmit_packet,length);
    	length=pack_IP(transmit_packet,length);
		length=pack_LLC(transmit_packet,length);
		length=eth_send(transmit_packet,length);
		if(!length) goto resend;
	
		memset(transmit_packet,0,80);
		return length;
}

s32 get_packet(void)
{
     int i;
     i=eth_rx();
     if(0==i) return 0;//没收到任何东西。
     i=unpack_UDP(receive_packet+34);//直接检查UDP的检查和
     if(i<0) return i;
     i=unpack_tftp(receive_packet+42,i);//检查是否为tftp包
     return i;    
  }




s32 pack_tftp(u8 *  buf , s32 length,s32 mode)
{
	s32 i=0;
	switch (mode){
case tftp_read_request_mode:
	i=request_packet(buf,length);
	break ;
case tftp_ACK_mode:
	i=ACK_packet(length);//这里的length是指块号
	break;
case tftp_data_mode:
//	i=data_packet(buf,length);不根本就不发送数据。
	break;
case tftp_error_mode:
	i=error_packet();
	break;
default:
    return -1;
	}
return i;
}

static s32 request_packet(u8 *name,s32 length)
{
struct tftp_read_request_packet * temp_request_packet;
temp_request_packet=(struct tftp_read_request_packet *)transmit_packet;
temp_request_packet->opcode =0x100;//操作码是0x0001,这里高低是反的所以是0x0100;
strcpy(temp_request_packet->filename ,name);
strcpy(temp_request_packet->filename+length+1 ,"octet");//加mode
return length+9;//opcode 有2字节,mode有5字节,加两个字符结束符,详情还要看真实截的包才行
}
//这里传入的参数是块号
static s32 ACK_packet(s32 block_number)
{
struct tftp_ACK_packet * temp_ACK_packet;
temp_ACK_packet=(struct tftp_ACK_packet *)transmit_packet;
temp_ACK_packet->opcode=0x400;//操作码0x004,这里高低是反的.........
temp_ACK_packet->block_number=shift16((u16)block_number);
return 4;
}

static s32 error_packet(void)
{
	return -3;
}


s32 unpack_tftp(u8 * packet, s32 packet_length)
{
	s32 i;
	i=-2;
	switch (packet[1]){
case tftp_read_request_mode:
	//i=request_unpacket(buf,length);根本就不会收到这种包
	break ;
case tftp_ACK_mode:
	//i=ACK_unpacket(length);实际上这个包也不会有
	break;
case tftp_data_mode:
	i=data_unpacket(packet,packet_length);//主要收数据包,重点o
	break;
case tftp_error_mode:
	i=error_unpacket();//搞笑包,一般不理它
	break;
default:
    return -2;
	}
	return i;
}
//接收数据包,提出包号
static s32 data_unpacket(u8 * buf, s32 length)
{
 struct tftp_data_packet * packet_point;
 //u16 rx_block_number;
 packet_point=(struct tftp_data_packet *) buf;
now_block_number=shift16(packet_point->block_number);
// if(rx_block_number!=last_block_number+1) return -1;//包
 //last_block_number++ ;
 //block_number=rx_block_number;
return length-12;
}



//出错信息包
static s32 error_unpacket(void)
{
	return -3;
}

/* 将一个16位的数高8位与低8位互换*/
u16 shift16(u16 b)
{
    u16 t;
	t=(b>>8)&0xff;
	t |=(b<<8)&0xff00;
	return t;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -