📄 tftp.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 + -