[国嵌攻略][068][tftp网络协议实现]

IP协议结构

UDP协议结构

TFTP协议结构

TFTP端口

读写请求端口: 69

其他请求端口:1024~65535

主程序

/********************************************************************
*名称:menu
*参数:
*	none
*返回:
*	none
*功能:菜单命令
*********************************************************************/
void menu(){
	int num = 0;   //输入选项

	//显示菜单
	printf("\n");
	printf("**********************************************************************\n");
	printf("*                             Bootloader                             *\n");
	printf("*[1]Get MAC Address.                                                 *\n");
	printf("*[2]Download Kernel.                                                 *\n");
	printf("*[3]                                                                 *\n");
	printf("**********************************************************************\n");
	printf("Please Select: ");

	//选择菜单
	scanf("%d", &num);
	switch(num){
		case 1:   //获取物理地址
			send_arp_req();
			isDisplay = 0;   //关闭显示菜单,等待获取物理地址
			break;

		case 2:   //下载内核文件
			send_tftp_read_req();
			isDisplay = 0;   //关闭显示菜单,等待下载内核文件
			break;

		default:
			break;
	}
}

网络头文件

/********************************************************************
*名称:net.h
*作者:D
*时间:2015.11.28
*功能:网络协议头文件
*********************************************************************/

/********************************************************************
*宏定义
*********************************************************************/
//MAC协议
#define ETH_IP   0x0800  //IP
#define ETH_ARP  0x0806  //ARP
#define ETH_RARP 0x0805  //RARP

//ARP协议
#define ARP_ETH 0x0001   //Ethernet
#define ARP_REQ 0x0001   //Request
#define ARP_ACK 0x0002   //Acknowledge

//IP协议
#define IP_VHL 0x45     //version:4, header length:20byte
#define IP_TOS 0x00     //type of service
#define IP_ID  0x0000   //identifiier
#define IP_OFF 0x4000   //flags and fragment offset
#define IP_TTL 0xFF     //time of live
#define IP_TCP 0x06     //TCP
#define IP_UDP 0x11     //UDP
#define IP_SUM 0x0000   //clear checksum
#define IP_LEN 20       //header length

//UDP协议
#define UDP_TFTP_SRC 48915   //源端口
#define UDP_TFTP_DST 69      //目的端口
#define UDP_SUM 0            //假校验和

//TFTP协议
#define TFTP_RRQ 0x0001   //Read Request
#define TFTP_WRQ 0x0002   //Write Request
#define TFTP_DAT 0x0003   //File Data
#define TFTP_ACK 0x0004   //Data Acknowledge
#define TFTP_ERR 0x0005   //Error

#define TFTP_DONWLOAD 0x31000000   //TFTP下载地址

/*----------------------------------------分割线----------------------------------------*/

#define EH_ADR_LEN 6       //物理地址长度
#define IP_ADR_LEN 4       //协议地址长度
#define ETH_PKT_MIN 64     //以太网帧最小长度
#define ETH_PKT_MAX 1518   //以太网帧最大长度

#define ETH_DAT_LEN  (ETH_PKT_MAX - sizeof(EHHDR))             //MAC数据部分长度
#define IP_DAT_LEN   (ETH_DAT_LEN - sizeof(IPHDR))             //IP数据部分长度
#define UDP_DAT_LEN  (IP_DAT_LEN - sizeof(UDPHDR))             //UDP数据部分长度
#define TFTP_REQ_LEN (UDP_DAT_LEN - sizeof(TFTPHDR))           //TFTP请求数据部分长度
#define TFTP_ACK_LEN (TFTP_REQ_LEN - sizeof(unsigned short))   //TFTP响应数据部分长度
#define TFTP_DAT_LEN 512                                       //TFTP数据响应最大长度

/*----------------------------------------分割线----------------------------------------*/

#define HTONS(n) ( (((n)&0xFF00)>>8) | (((n)&0x00FF)<<8) )   //把unsigned short类型的主机序转换到网络序
#define NTOHS(n) ( (((n)&0xFF00)>>8) | (((n)&0x00FF)<<8) )   //把unsigned short类型的网络序转换到主机序

/********************************************************************
*类型定义
*********************************************************************/
//MAC头部
typedef struct ehhdr
{
	unsigned char eh_dst[6];   //destination ethernet addrress
	unsigned char eh_src[6];   //source ethernet addresss
	unsigned short eh_type;    //ethernet packet type
}EHHDR;

//MAC帧
typedef struct ehPacket
{
	EHHDR ehhdr;             //MAC头部

	unsigned char data[ETH_DAT_LEN];   //MAC数据
}EHPACKET;

/*----------------------------------------分割线----------------------------------------*/

//ARP头部
typedef struct arphdr
{
	unsigned short arp_hrd;   //format of hardware address
	unsigned short arp_pro;   //format of protocol address

	unsigned char  arp_hln;   //length of hardware address
	unsigned char  arp_pln;   //length of protocol address
	unsigned short arp_op;    //ARP/RARP operation

	unsigned char arp_sha[6];   //sender hardware address
	unsigned char arp_spa[4];   //sender protocol address
	unsigned char arp_tha[6];   //target hardware address
	unsigned char arp_tpa[4];   //target protocol address
}ARPHDR;

//ARP报文包
typedef struct arpPacket
{
	EHHDR ehhdr;     //MAC头部
	ARPHDR arphdr;   //ARP头部
}ARPPACKET;

/*----------------------------------------分割线----------------------------------------*/

//IP头部
typedef struct iphdr
{
	unsigned char  ip_vhl;   //version and header length
	unsigned char  ip_tos;   //type of service
	unsigned short ip_len;   //total length

	unsigned short ip_id;    //identifiier
	unsigned short ip_off;   //flags and fragment offset

	unsigned char  ip_ttl;   //time of live
	unsigned char  ip_pro;   //protocol
	unsigned short ip_sum;   //header checksum

	unsigned char ip_src[IP_ADR_LEN];   //source address
	unsigned char ip_dst[IP_ADR_LEN];   //destination address
}IPHDR;

//IP报文包
typedef struct ipPacket
{
	EHHDR ehhdr;             //MAC头部
	IPHDR iphdr;             //IP头部

	unsigned char data[IP_DAT_LEN];   //IP数据
}IPPACKET;

/*----------------------------------------分割线----------------------------------------*/

//UDP头部
typedef struct udphdr
{
	unsigned short udp_sport;   //source port
	unsigned short udp_dport;   //destination port

	unsigned short udp_len;     //length
	unsigned short udp_sum;     //checksum
}UDPHDR;

//UDP报文包
typedef struct udpPacket
{
	EHHDR ehhdr;             //MAC头部
	IPHDR iphdr;             //IP头部
	UDPHDR udphdr;           //UDP头部

	unsigned char data[UDP_DAT_LEN];   //UDP数据
}UDPPACKET;

/*----------------------------------------分割线----------------------------------------*/

//TFTP头部
typedef struct tftphdr
{
	unsigned short tftp_op;   //opcode
}TFTPHDR;

//TFTP请求包
typedef struct tftpReqPacket
{
	EHHDR ehhdr;             //MAC头部
	IPHDR iphdr;             //IP头部
	UDPHDR udphdr;           //UDP头部
	TFTPHDR tftphdr;         //TFTP头部

	unsigned char data[TFTP_REQ_LEN];   //TFTP数据
}TFTPREQPACKET;

//TFTP响应包
typedef struct tftpAckPacket
{
	EHHDR ehhdr;             //MAC头部
	IPHDR iphdr;             //IP头部
	UDPHDR udphdr;           //UDP头部
	TFTPHDR tftphdr;         //TFTP头部

	unsigned short blocknum;            //TFTP块号
	unsigned char data[TFTP_ACK_LEN];   //TFTP数据
}TFTPACKPACKET;

网卡中断

/********************************************************************
*名称:dm9000_irq
*参数:
*	none
*返回:
*	none
*功能:网卡中断服务
*********************************************************************/
void dm9000_irq(){
	int state;             //接收状态
	EHPACKET *eh_packet;   //MAC帧

	//接收网卡数据
	state = rx_dm9000(packet);

	//处理网卡数据
	if(state){   //如果接收成功,那么处理数据
		//转换成MAC帧
		eh_packet = (EHPACKET *)packet;

		//提供网络接口层服务
		switch(NTOHS(eh_packet->ehhdr.eh_type)){   //判断网络层协议
			case ETH_IP:    //IP协议
				rece_ip_pro(eh_packet);
				break;

			case ETH_ARP:   //ARP协议
				rece_arp_pro(eh_packet);
				break;

			default:
				break;
		}
	}

	//清除外部中断请求
	EINTPEND |= (1<<7);   //EINT8:cleard

	//清除中断源请求
	SRCPND |= (1<<4);   //EINT4_7:cleard

	//清除中断请求
	INTPND |= (1<<4);   //EINT4_7:cleard
}

ARP协议

/********************************************************************
*名称:arp.c
*作者:D
*时间:2015.11.26
*功能:ARP协议
*********************************************************************/

/********************************************************************
*头文件
*********************************************************************/
#include "net.h"

/********************************************************************
*全局变量声明
*********************************************************************/
//外部变量,定义在DM9000.c中
extern unsigned char eh_src[EH_ADR_LEN];   //物理源地址
extern unsigned char eh_dst[EH_ADR_LEN];   //物理目的地址
extern unsigned char ip_src[IP_ADR_LEN];   //协议源地址
extern unsigned char ip_dst[IP_ADR_LEN];   //协议目的地址

extern int isDisplay;   //是否显示菜单标志

/********************************************************************
*函数原型声明
*********************************************************************/
void send_arp_req();
void rece_arp_pro(ARPPACKET *arp_packet);
void send_arp_ack(ARPPACKET *arp_packet);
void rece_arp_ack(ARPPACKET *arp_packet);

int create_arp_packet(ARPPACKET *arp_packet, unsigned short arp_op);
int get_arp_dst_adr(ARPPACKET *arp_packet);
void get_arp_src_adr(ARPPACKET *arp_packet);
void put_arp_src_adr();

/********************************************************************
*名称:send_arp_req
*参数:
*	none
*返回:
*	none
*功能:发送ARP请求包
*********************************************************************/
void send_arp_req(){
	int length = 0;             //MAC帧长度
	ARPPACKET arp_req_packet;   //ARP请求包

	//创建ARP请求包
	length = create_arp_packet(&arp_req_packet, ARP_REQ);

	//发送ARP请求包
	tx_dm9000(&arp_req_packet, length);
}

/********************************************************************
*名称:rece_arp_pro
*参数:
*	arp_packet   ARP报文包
*返回:
*	none
*功能:接收ARP协议
*********************************************************************/
void rece_arp_pro(ARPPACKET *arp_packet){
	//提取目的地址
	if( !get_arp_dst_adr(arp_packet) ){   //如果IP目的地址不匹配,那么返回
		return ;
	}

	//提供网络层服务
	switch(NTOHS(arp_packet->arphdr.arp_op)){   //判断ARP操作码
		case ARP_REQ:   //ARP请求
			send_arp_ack(arp_packet);
			break;

		case ARP_ACK:   //ARP响应
			rece_arp_ack(arp_packet);
			break;

		default:
			break;
	}
}

/********************************************************************
*名称:send_arp_ack
*参数:
*	arp_packet   ARP报文包
*返回:
*	none
*功能:发送ARP响应包
*********************************************************************/
void send_arp_ack(ARPPACKET *arp_packet){
	int length = 0;             //MAC帧长度
	ARPPACKET arp_ack_packet;   //ARP响应包

	//提取源地址
	get_arp_src_adr(arp_packet);

	//创建ARP响应包
	length = create_arp_packet(&arp_ack_packet, ARP_ACK);

	//发送ARP响应包
	tx_dm9000(&arp_ack_packet, length);
}

/********************************************************************
*名称:rece_arp_ack
*参数:
*	arp_packet   ARP报文包
*返回:
*	none
*功能:接收ARP响应包
*********************************************************************/
void rece_arp_ack(ARPPACKET *arp_packet){
	//提取源地址
	get_arp_src_adr(arp_packet);

	//打印源地址
	put_arp_src_adr();

	//打开显示菜单
	isDisplay = 1;
}

/*----------------------------------------分割线----------------------------------------*/

/********************************************************************
*名称:create_arp_packet
*参数:
*	arp_packet   ARP报文包
*	arp_op       ARP操作码
*返回:
*	length       MAC帧长度
*功能:创建ARP报文包
*********************************************************************/
int create_arp_packet(ARPPACKET *arp_packet, unsigned short arp_op){
	int length = 0;

	//填充ARP头部
	length = length + sizeof(ARPHDR);              //ARP报文长度
	arp_packet->arphdr.arp_hrd = HTONS(ARP_ETH);   //硬件类型
	arp_packet->arphdr.arp_pro = HTONS(ETH_IP);    //协议类型
	arp_packet->arphdr.arp_hln = EH_ADR_LEN;       //MAC地址长度
	arp_packet->arphdr.arp_pln = IP_ADR_LEN;       //IP地址长度
	arp_packet->arphdr.arp_op  = HTONS(arp_op);    //操作类型

	memcpy(arp_packet->arphdr.arp_sha, eh_src, EH_ADR_LEN);   //MAC源地址
	memcpy(arp_packet->arphdr.arp_spa, ip_src, IP_ADR_LEN);   //IP源地址
	memcpy(arp_packet->arphdr.arp_tha, eh_dst, EH_ADR_LEN);   //MAC目的地址
	memcpy(arp_packet->arphdr.arp_tpa, ip_dst, IP_ADR_LEN);   //IP目的地址

	//填充MAC头部
	length = length + sizeof(EHHDR);                        //MAC帧长度
	memcpy(arp_packet->ehhdr.eh_dst, eh_dst, EH_ADR_LEN);   //MAC目的地址
	memcpy(arp_packet->ehhdr.eh_src, eh_src, EH_ADR_LEN);   //MAC源地址
	arp_packet->ehhdr.eh_type = HTONS(ETH_ARP);             //MAC帧类型

	return length;
}

/********************************************************************
*名称:get_arp_dst_adr
*参数:
*	arp_packet   ARP报文包
*返回:
*	return       1 匹配成功
*	             0 匹配失败
*功能:提取目的地址
*********************************************************************/
int get_arp_dst_adr(ARPPACKET *arp_packet){
	unsigned char arp_ip_dst[IP_ADR_LEN];   //IP目的地址

	//提取IP目的地址
	memcpy(arp_ip_dst, arp_packet->arphdr.arp_tpa, IP_ADR_LEN);

	//判断IP目的地址
	if(memcmp(arp_ip_dst, ip_src, IP_ADR_LEN) != 0){   //如果目的地址不等于该主机IP地址,那么匹配失败
		return 0;
	}

	return 1;   //匹配成功
}

/********************************************************************
*名称:get_arp_src_adr
*参数:
*	arp_packet   ARP报文包
*返回:
*	none
*功能:提取源地址
*********************************************************************/
void get_arp_src_adr(ARPPACKET *arp_packet){
	memcpy(eh_dst, arp_packet->arphdr.arp_sha, EH_ADR_LEN);   //提取MAC源地址,并写到目的地址
	memcpy(ip_dst, arp_packet->arphdr.arp_spa, IP_ADR_LEN);   //提取IP源地址,并写到目的地址
}

/********************************************************************
*名称:put_arp_src_adr
*参数:
*	none
*返回:
*	none
*功能:打印源地址
*********************************************************************/
void put_arp_src_adr(){
	int i;

	printf("\nIP  Address : ");
	for(i = 0; i < IP_ADR_LEN; i++){
		printf("%d.", ip_dst[i]);   //打印IP源地址
	}
	printf("\b \n");

	printf("MAC Address : ");
	for(i = 0; i < EH_ADR_LEN; i++){
		printf("%02X:", eh_dst[i]);   //打印MAC源地址
	}
	printf("\b \n");
}

IP协议

/********************************************************************
*名称:ip.c
*作者:D
*时间:2015.11.28
*功能:IP协议
*********************************************************************/

/********************************************************************
*头文件
*********************************************************************/
#include "net.h"

/********************************************************************
*全局变量声明
*********************************************************************/
//外部变量,定义在DM9000.c中
extern unsigned char ip_src[IP_ADR_LEN];   //IP源地址

/********************************************************************
*函数原型声明
*********************************************************************/
void rece_ip_pro(IPPACKET *ip_packet);
int get_ip_dst_adr(IPPACKET *ip_packet);

/********************************************************************
*名称:rece_ip_pro
*参数:
*	ip_packet   IP报文包
*返回:
*	none
*功能:接收IP协议
*********************************************************************/
void rece_ip_pro(IPPACKET *ip_packet){
	//提取目的地址
	if( !get_ip_dst_adr(ip_packet) ){   //如果IP目的地址不匹配,那么返回
		return ;
	}

	//提供网络层服务
	switch(ip_packet->iphdr.ip_pro){   //判断运输层协议
		case IP_UDP:   //UDP协议
			rece_udp_pro(ip_packet);
			break;

		default:
			break;
	}
}

/********************************************************************
*名称:get_ip_dst_adr
*参数:
*	ip_packet   IP报文包
*返回:
*	return      1 匹配成功
*	            0 匹配失败
*功能:提取目的地址
*********************************************************************/
int get_ip_dst_adr(IPPACKET *ip_packet){
	unsigned char ip_dst_adr[IP_ADR_LEN];   //IP目的地址

	//提取IP目的地址
	memcpy(ip_dst_adr, ip_packet->iphdr.ip_dst, IP_ADR_LEN);

	//判断IP目的地址
	if(memcmp(ip_dst_adr, ip_src, IP_ADR_LEN) != 0){   //如果目的地址不等于该主机IP地址,那么匹配失败
		return 0;
	}

	return 1;   //匹配成功
}

UDP协议

/********************************************************************
*名称:udp.c
*作者:D
*时间:2015.11.30
*功能:UDP协议
*********************************************************************/

/********************************************************************
*头文件
*********************************************************************/
#include "net.h"

/********************************************************************
*函数原型声明
*********************************************************************/
void rece_udp_pro(UDPPACKET *udp_packet);

/********************************************************************
*名称:rece_udp_pro
*参数:
*	udp_packet   UDP报文包
*返回:
*	none
*功能:接收UDP协议
*********************************************************************/
void rece_udp_pro(UDPPACKET *udp_packet){
	//提供运输层服务
	switch(NTOHS(udp_packet->udphdr.udp_dport)){   //判断应用层端口
		case UDP_TFTP_SRC:   //TFTP协议源端口
			rece_tftp_pro(udp_packet);
			break;

		default:
			break;
	}
}

TFTP协议

/********************************************************************
*名称:tftp.c
*作者:D
*时间:2015.11.29
*功能:TFTP协议
*********************************************************************/

/********************************************************************
*头文件
*********************************************************************/
#include "net.h"

/********************************************************************
*全局变量声明
*********************************************************************/
//外部变量,定义在DM9000.c中
extern unsigned char eh_src[EH_ADR_LEN];   //物理源地址
extern unsigned char eh_dst[EH_ADR_LEN];   //物理目的地址
extern unsigned char ip_src[IP_ADR_LEN];   //协议源地址
extern unsigned char ip_dst[IP_ADR_LEN];   //协议目的地址

extern int isDisplay;   //是否显示菜单标志

unsigned short reqblknum;       //TFTP请求块号
unsigned char *tftp_download;   //TFTP下载地址

/********************************************************************
*函数原型声明
*********************************************************************/
void send_tftp_read_req();
void rece_tftp_pro(TFTPACKPACKET *tftp_packet);
void rece_tftp_data_ack(TFTPACKPACKET *tftp_packet);

int get_tftp_data_ack(TFTPACKPACKET *tftp_packet, unsigned short *blocknum, unsigned short *udpdport);
int create_tftp_req_packet(TFTPREQPACKET *tftp_packet, unsigned short tftp_op, const char *filename, const char *mode);
int create_tftp_ack_packet(TFTPACKPACKET *tftp_packet, unsigned short tftp_op, unsigned short blocknum, unsigned short udpdport);
unsigned short checksum(unsigned short* iphdr, int size);

/********************************************************************
*名称:send_tftp_read_req
*参数:
*	none
*返回:
*	none
*功能:发送TFTP读请求包
*********************************************************************/
void send_tftp_read_req(){
	int length = 0;                  //MAC帧长度
	TFTPREQPACKET tftp_req_packet;   //TFTP请求包

	//设置TFTP请求块号
	reqblknum = 1;

	//设置TFTP下载地址
	tftp_download = (unsigned char *)TFTP_DONWLOAD;

	//创建TFTP读请求包
	length = create_tftp_req_packet(&tftp_req_packet, TFTP_RRQ, "boot.bin", "octet");

	//发送TFTP读请求包
	tx_dm9000(&tftp_req_packet, length);
}

/********************************************************************
*名称:rece_tftp_pro
*参数:
*	rece_tftp_pro   TFTP响应包
*返回:
*	none
*功能:接收TFTP协议
*********************************************************************/
void rece_tftp_pro(TFTPACKPACKET *tftp_packet){
	//提供应用层服务
	switch(NTOHS(tftp_packet->tftphdr.tftp_op)){   //判断TFTP操作码
		case TFTP_DAT:   //TFTP文件数据
			rece_tftp_data_ack(tftp_packet);
			break;

		default:
			break;
	}
}

/********************************************************************
*名称:rece_tftp_data_ack
*参数:
*	tftp_packet   TFTP响应包
*返回:
*	none
*功能:接收TFTP数据响应包
*********************************************************************/
void rece_tftp_data_ack(TFTPACKPACKET *tftp_packet){
	int length = 0;                  //MAC帧长度
	unsigned short blocknum = 0;     //TFTP块号
	unsigned short udpdport = 0;     //UDP目的端口
	TFTPACKPACKET tftp_ack_packet;   //TFTP响应包

	//提取数据响应包
	if( !get_tftp_data_ack(tftp_packet, &blocknum, &udpdport) ){   //如果提取失败,那么返回
		return ;
	}

	//创建TFTP响应包
	length  = create_tftp_ack_packet(&tftp_ack_packet, TFTP_ACK, blocknum, udpdport);

	//发送TFTP响应包
	tx_dm9000(&tftp_ack_packet, length);
}

/*----------------------------------------分割线----------------------------------------*/

/********************************************************************
*名称:get_tftp_data_ack
*参数:
*	tftp_packet   TFTP响应包
*	blocknum      TFTP块号
*	udpdport      UDP目的端口
*返回:
*	return        1 提取成功
*	              0 提取失败
*功能:提取TFTP数据响应包
*********************************************************************/
int get_tftp_data_ack(TFTPACKPACKET *tftp_packet, unsigned short *blocknum, unsigned short *udpdport){
	int i;
	int length = 0;   //TFTP数据长度

	//提取TFTP响应块号
	*blocknum = NTOHS(tftp_packet->blocknum);
	if(*blocknum != reqblknum){   //如果TFTP块号不等于请求块号,那么返回
		return 0;
	}

	//增加TFTP请求块号
	reqblknum++;

	//提取UDP目的端口
	*udpdport = NTOHS(tftp_packet->udphdr.udp_sport);

	//计算TFTP数据长度
	length = NTOHS(tftp_packet->udphdr.udp_len);   //提取UDP报文长度
	length = length - sizeof(UDPHDR);              //计算TFTP报文长度
	length = length - sizeof(TFTPHDR);             //计算TFTP数据长度
	length = length - sizeof(unsigned short);

	//提取TFTP响应数据
	for(i = 0; i < length; i++){
		*(tftp_download++) = tftp_packet->data[i];   //下载到指定内存地址
	}

	//判断最后数据响应
	if(length < TFTP_DAT_LEN){   //如果数据长度小于最大长度,那么发出最后响应包
		printf("\nTFTP Donwload Success!\n");
		isDisplay = 1;   //打开显示菜单
	}

	return 1;
}

/********************************************************************
*名称:create_tftp_req_packet
*参数:
*	tftp_packet   TFTP请求包
*	tftp_op       TFTP操作码
*	filename      请求文件名
*	mode          请求模式
*返回:
*	length        MAC帧长度
*功能:创建TFTP请求包
*********************************************************************/
int create_tftp_req_packet(TFTPREQPACKET *tftp_packet, unsigned short tftp_op, const char *filename, const char *mode){
	int i;
	int length = 0;
	unsigned char data[TFTP_REQ_LEN];   //TFTP数据
	unsigned short *iphdr;              //IP起始地址
	unsigned short chksum;              //IP头校验和

	//填充TFTP数据
	for(i = 0; i < strlen(filename); i++){   //填充请求文件名
		data[length++] = filename[i];
	}
	data[length++] = ‘\0‘;   //结束标志

	for(i = 0; i < strlen(mode); i++){   //填充请求模式
		data[length++] = mode[i];
	}
	data[length++] = ‘\0‘;   //结束标志

	memcpy(tftp_packet->data, data, length);   //填充TFTP数据

	//填充TFTP头部
	length = length + sizeof(TFTPHDR);                //TFTP报文长度
	tftp_packet->tftphdr.tftp_op = HTONS(tftp_op);    //填充操作码

	//填充UDP头部
	length =length + sizeof(UDPHDR);                       //UDP报文长度
	tftp_packet->udphdr.udp_sport = HTONS(UDP_TFTP_SRC);   //UDP源端口
	tftp_packet->udphdr.udp_dport = HTONS(UDP_TFTP_DST);   //UDP目的端口
	tftp_packet->udphdr.udp_len = HTONS(length);           //UDP报文长度
	tftp_packet->udphdr.udp_sum = HTONS(UDP_SUM);          //UDP头假校验和

	//填充IP头部
	length = length + sizeof(IPHDR);             //IP报文长度
	tftp_packet->iphdr.ip_vhl = IP_VHL;          //版本号:IPv4,协议头长度:20字节
	tftp_packet->iphdr.ip_tos = IP_TOS;          //普通服务类型
	tftp_packet->iphdr.ip_len = HTONS(length);   //IP报文长度

	tftp_packet->iphdr.ip_id = HTONS(IP_ID);    //标识符
	tftp_packet->iphdr.ip_off = HTONS(IP_OFF);  //标记

	tftp_packet->iphdr.ip_ttl = IP_TTL;   //生存时间
	tftp_packet->iphdr.ip_pro = IP_UDP;   //UDP协议

	memcpy(tftp_packet->iphdr.ip_src, ip_src, IP_ADR_LEN);   //IP源地址
	memcpy(tftp_packet->iphdr.ip_dst, ip_dst, IP_ADR_LEN);   //IP目的地址

	tftp_packet->iphdr.ip_sum = HTONS(IP_SUM);          //清零校验和
	iphdr = (unsigned short *)&(tftp_packet->iphdr);    //获取IP指针
	chksum = checksum(iphdr, IP_LEN);                   //计算校验和
	tftp_packet->iphdr.ip_sum = chksum;                 //头部校验和,注意不需要网络序转换,计算的本来就是网络序的校验和

	//填充MAC头部
	length = length + sizeof(EHHDR);                         //MAC帧长度
	memcpy(tftp_packet->ehhdr.eh_dst, eh_dst, EH_ADR_LEN);   //MAC目的地址
	memcpy(tftp_packet->ehhdr.eh_src, eh_src, EH_ADR_LEN);   //MAC源地址
	tftp_packet->ehhdr.eh_type = HTONS(ETH_IP);              //MAC帧类型

	return length;
}

/********************************************************************
*名称:create_tftp_ack_packet
*参数:
*	tftp_packet   TFTP响应包
*	tftp_op       TFTP操作码
*	blocknum      TFTP块号
*	udpdport      UDP目的端口
*返回:
*	length        MAC帧长度
*功能:创建TFTP响应包
*********************************************************************/
int create_tftp_ack_packet(TFTPACKPACKET *tftp_packet, unsigned short tftp_op, unsigned short blocknum, unsigned short udpdport){
	int i;
	int length = 0;          //数据长度
	unsigned short *iphdr;   //IP起始地址
	unsigned short chksum;   //IP头校验和

	//填充TFTP块号
	length = length + sizeof(unsigned short);   //TFTP数据长度
	tftp_packet->blocknum = HTONS(blocknum);    //填充TFTP块号

	//填充TFTP头部
	length = length + sizeof(TFTPHDR);               //TFTP报文长度
	tftp_packet->tftphdr.tftp_op = HTONS(tftp_op);   //填充操作码

	//填充UDP头部
	length =length + sizeof(UDPHDR);                       //UDP报文长度
	tftp_packet->udphdr.udp_sport = HTONS(UDP_TFTP_SRC);   //UDP源端口
	tftp_packet->udphdr.udp_dport = HTONS(udpdport);       //UDP目的端口
	tftp_packet->udphdr.udp_len = HTONS(length);           //UDP数据包长度
	tftp_packet->udphdr.udp_sum = HTONS(UDP_SUM);          //UDP头假校验和

	//填充IP头部
	length = length + sizeof(IPHDR);             //IP报文长度
	tftp_packet->iphdr.ip_vhl = IP_VHL;          //版本号:IPv4,协议头长度:20字节
	tftp_packet->iphdr.ip_tos = IP_TOS;          //普通服务类型
	tftp_packet->iphdr.ip_len = HTONS(length);   //IP报文长度

	tftp_packet->iphdr.ip_id = HTONS(IP_ID);    //标识符
	tftp_packet->iphdr.ip_off = HTONS(IP_OFF);  //标记

	tftp_packet->iphdr.ip_ttl = IP_TTL;   //生存时间
	tftp_packet->iphdr.ip_pro = IP_UDP;   //UDP协议

	memcpy(tftp_packet->iphdr.ip_src, ip_src, IP_ADR_LEN);   //IP源地址
	memcpy(tftp_packet->iphdr.ip_dst, ip_dst, IP_ADR_LEN);   //IP目的地址

	tftp_packet->iphdr.ip_sum = HTONS(IP_SUM);          //清零校验和
	iphdr = (unsigned short *)&(tftp_packet->iphdr);    //获取IP地址
	chksum = checksum(iphdr, IP_LEN);                   //计算校验和
	tftp_packet->iphdr.ip_sum = chksum;                 //头部校验和,注意不需要网络序转换,计算的本来就是网络序的校验和

	//填充以太网帧头部
	length = length + sizeof(EHHDR);                         //MAC帧长度
	memcpy(tftp_packet->ehhdr.eh_dst, eh_dst, EH_ADR_LEN);   //MAC目的地址
	memcpy(tftp_packet->ehhdr.eh_src, eh_src, EH_ADR_LEN);   //MAC源地址
	tftp_packet->ehhdr.eh_type = HTONS(ETH_IP);              //MAC帧类型

	return length;
}

/********************************************************************
*名称:checksum
*参数:
*	iphdr    IP起始地址
*	size     IP头部长度
*返回:
*	chksum   IP头校验和
*功能:计算IP头校验和
*********************************************************************/
unsigned short checksum(unsigned short* iphdr, int size){
    unsigned long chksum = 0;

    while(size > 1){   //16位二进制求和
        chksum += *iphdr++;
        size -= sizeof(unsigned short);
    }
    if(size == 1){    //如果头部长度为奇数,那么再加上最后8位
        chksum += *((unsigned char*)iphdr);
    }

    chksum = (chksum>>16) + (chksum&0xFFFF);   //加上进位
    chksum += (chksum>>16);                    //加上进位产生的进位

    return (unsigned short)(~chksum);   //返回反码
}
时间: 2024-10-25 18:31:04

[国嵌攻略][068][tftp网络协议实现]的相关文章

[国嵌攻略][090][linux网络编程模型]

编程模型 Socket的实质就是一个接口,利用该接口,用户在使用不同的网络协议时,操作函数得以统一.而针对不同协议的差异性操作,则交给了Socket去自行解决. TCP编程模型 UDP编程模型

[国嵌攻略][067][tftp协议分析]

TFTP作用 用于网络下载,TFTP客户机在TFTP服务器中下载文件. TFTP交换过程 1.配置TFTP服务器 vim /etc/xinetd.d/tftp 2.交换过程 客户端发请求包到服务器 服务器发数据包到客户段 客户端发相应包到服务器 TFTP报文格式 操作码 1 请求报文 2 写入报文 3 数据报文 4 应答报文 5 出错报文

[国嵌攻略][091][TCP网络程序设计]

server.c #include <sys/socket.h> #include <netinet/in.h> #include <strings.h> #include <stdio.h> #define SERVER_PORT 3333 void main(){ //创建标识 int serverfd; serverfd = socket(AF_INET, SOCK_STREAM, 0); //建立TCP连接 //绑定地址 struct sockadd

[国嵌攻略][089][网络协议分析]

网络模型 OSI参考模型: 物理层.数据链路层 | 网络层 | 传输层 | 会话层.表示层.应用层 TCP/IP参考模型: 网络接口层         | 网络层 | 传输层 | 应用层 网络协议要素 1.协议规则 2.数据格式 协议架构 以太网协议格式 IP协议格式 TCP协议格式 UDP协议格式

[国嵌攻略][099][Linux内核配置与编译]

为什么要配置内核 基于硬件和软件的需求选出需要的功能,去掉不要的功能. 内核配置的方法 make config:基于文本交互的配置. make menuconfig:基于图形菜单的配置. make menuconfig配置方法 1.菜单项的分类 processor type and features   处理器类型 networking support            网络协议支持 device drivers                设备驱动支持 file systems     

[国嵌攻略][133][网卡驱动架构分析]

Linux网络子系统 1.系统调用接口:提供系统调用 2.协议无关接口:统一网络协议给系统调用接口使用 3.网络协议栈  :实现网络协议 4.设备无关接口:统一设备驱动程序给网络协议使用 5.设备驱动程序:实现网卡驱动 Linux驱动在内核中都有一个结构来描述,首先找到设备描述结构,然后找到设备如何注册和初始化. 网卡描述结构 在Linux内核中,每个网卡都由一个net_device结构来描述,其中一些重要成员: char name[IFNAMSIZ]   设备名,如:eth%d unsigne

[国嵌攻略][135][网络子系统深度分析]

网络发包模型 1.选择路由 2.交给邻居子系统(路由中紧挨着发送方的网关).如果没有邻居信息,那么由Linux中的邻居子系统来建立邻居信息. 发送数据过程 //系统调用层和协议无关层 1.发送入口sock_aio_write 2.调用do_sock_write 3.调用__sock_sendmsg //网络协议栈 4.调用udp_sendmsg 5.调用ip_route_output_flow(选择路由) 6.调用udp_push_pending_frames 7.调用ip_push_pendi

[国嵌攻略][162][USB协议分析]

USB设备逻辑结构 在USB设备的逻辑组织中,包含设备.配置.接口和端点4个层次.设备通常有一个或多个配置,配置通常有一个或多个接口,接口通常有零个或多个端点. USB设备描述符 当我们把USB设备(例如USB鼠标)插到我们的PC时,主机能够自动识别出我们的USB设备类型.在每一个USB设备内部,包含了固定格式的数据,通过这些数据,USB主机就可以获取USB设备的类型.生产厂商等信息.这些固定格式的数据,我们称之为USB描述符.标准设备有5种USB描述符:设备描述符.配置描述符.接口描述符.端点

[国嵌攻略][102][内核驱动开发环境搭建]

服务器环境搭建 1.配置tftp服务器 1.1.设置tftp目录 vim /etc/xinetd.d/tftp server_args             = -s .../tftp disable                 = no 1.2.启动tftp服务 /etc/init.d/xinetd restart 2.配置nfs服务器 2.1.设置nfs目录 vim /etc/exports .../nfs *(rw,sync,no_root_squash) 2.2.启动nfs服务 /