移植 tftp 客户端

tftp网络协议分析

可以通过tftp下载Linux内核和程序文件到开发板运行。

tftp交互过程
这里写图片描述

tftp报文格式
每个包的数据不能超过512字节。
tftp协议属于udp协议,udp协议属于ip协议。
这里写图片描述

tftp网络协议的实现

arp.h

typedef unsigned int   u32;
typedef unsigned short u16;
typedef unsigned char  u8;

typedef struct eth_hdr
{
    u8 d_mac[6];
    u8 s_mac[6];
    u16 type;
}ETH_HDR;

typedef struct arp_hdr
{
    ETH_HDR ethhdr;
    u16 hwtype;
    u16 protocol;
    u8 hwlen;
    u8 protolen;
    u16 opcode;
    u8 smac[6];
    u8 sipaddr[4];
    u8 dmac[6];
    u8 dipaddr[4];
}ARP_HDR;

typedef struct ip_hdr
{
    ETH_HDR ethhdr;
    u8 vhl;
    u8 tos;
    u16 len;
    u16 ipid;
    u16 ipoffset;
    u8 ttl;
    u8 proto;
    u16 ipchksum;
    u8 srcipaddr[4];
    u8 destipaddr[4];
}IP_HDR;

typedef struct udp_hdr
{
    IP_HDR iphdr;
    u16 sport;
    u16 dport;
    u16 len;
    u16 udpchksum;
}UDP_HDR;

typedef struct tftp_package
{
    u16 opcode;
    u16 blocknum;
    u8 data[0]; 
}TFTP_PAK;

ARP_HDR arpbuf;

#define PROTO_ARP 0x0806
#define PROTO_IP 0x0800
#define PROTO_UDP 0x11

extern u8 host_mac_addr[6];
extern u8 mac_addr[6];
extern u8 ip_addr[4];
extern u8 host_ip_addr[4];
extern u16 packet_len;

arp.c

#include "arp.h"

#define HON(n) ((((u16)((n) & 0xff)) << 8) | (((n) & 0xff00) >> 8))

/*1.发送arp请求包*/
void arp_request()
{
     /*1.构成arp请求包*/
     memcpy(arpbuf.ethhdr.d_mac,host_mac_addr,6);
     memcpy(arpbuf.ethhdr.s_mac,mac_addr,6);
     arpbuf.ethhdr.type = HON(0x0806);

     arpbuf.hwtype = HON(1);
     arpbuf.protocol = HON(0x0800);

     arpbuf.hwlen = 6;
     arpbuf.protolen = 4;

     arpbuf.opcode = HON(1);

     memcpy(arpbuf.smac,mac_addr,6);
     memcpy(arpbuf.sipaddr,ip_addr,4);
     memcpy(arpbuf.dipaddr,host_ip_addr,4);

     packet_len = 14+28;

     /*2.调用dm9000发送函数,发送应答包*/   
     dm9000_tx(&arpbuf,packet_len);
}

/*2.解析arp应答包,提取mac*/
u8 arp_process(u8 *buf, u32 len)
{
    u32 i;
    ARP_HDR *arp_p = (ARP_HDR *)buf;

    if (packet_len<28)
        return 0;

    switch (HON(arp_p->opcode))
    {
        case 2: /*arp响应包*/
            memcpy(host_ip_addr,arp_p->sipaddr,4);
            printf("host ip is : ");
            for(i=0;i<4;i++)
               printf("%03d ",host_ip_addr[i]);
            printf("\n\r");

            memcpy(host_mac_addr,arp_p->smac,6);
            printf("host mac is : ");
            for(i=0;i<6;i++)
            printf("%02x ",host_mac_addr[i]);
            printf("\n\r");

            break;

        case 1: /*arp请求包*/
        /*发送arp响应包*/
            memcpy(arpbuf.ethhdr.d_mac,arp_p->smac,6);
            memcpy(arpbuf.ethhdr.s_mac,mac_addr,6);
            arpbuf.ethhdr.type = HON(0x0806);

            arpbuf.hwtype = HON(1);
            arpbuf.protocol = HON(0x0800);

            arpbuf.hwlen = 6;
            arpbuf.protolen = 4;

            arpbuf.opcode = HON(2);

            memcpy(arpbuf.smac,mac_addr,6);
            memcpy(arpbuf.sipaddr,ip_addr,4);
            memcpy(arpbuf.dmac,arp_p->smac,6);
            memcpy(arpbuf.dipaddr,arp_p->sipaddr,4);

            packet_len = 14+28;

         /*2.调用dm9000发送函数,发送应答包*/   
            dm9000_tx(&arpbuf,packet_len);           
            break;
     }
}

void udp_process(u8* buf, u32 len)
{
     UDP_HDR *udphdr = (UDP_HDR *)buf;

     tftp_process(buf,len,HON(udphdr->sport));      
}

void ip_process(u8 *buf, u32 len)
{
     IP_HDR *p = (IP_HDR *)buf; 

     switch(p->proto)
     {
        case PROTO_UDP:
            udp_process(buf,len);
            break;

        default:
            break;  
     }
}

void net_handle(u8 *buf, u32 len)
{
     ETH_HDR *p = (ETH_HDR *)buf;

     switch (HON(p->type))
     {
        case PROTO_ARP:
            arp_process(buf,len);
            break;

        case PROTO_IP:
            ip_process(buf,len);
            break;

        default:
            break;
     }
}

void dm9000_arp()
{
    while(1)
        arp_request();  
}

tftp.c

#include "string.h"
#include "arp.h"

u8 sendbuf[1024];
u8* tftp_down_addr = 0x31000000;
u16 serverport = 0;
u16 curblock = 1;

#define HON(n) ((((u16)((n) & 0xff)) << 8) | (((n) & 0xff00) >> 8))

u16 checksum(u8 *ptr, int len)
{
    u32 sum = 0;
    u16 *p = (u16 *)ptr;

    while (len > 1)
    {
        sum += *p++;
        len -= 2;
    }

    if(len == 1)
        sum += *(u8 *)p;

    while(sum>>16)
        sum = (sum&0xffff) + (sum>>16);

    return (u16)((~sum)&0xffff);
}

void tftp_send_request(const char *filename)
{
    u8 *ptftp = &sendbuf[200];
    u32 tftp_len = 0;
    UDP_HDR *udphdr;
    u8 *iphdr;

    ptftp[0] = 0x00;
    ptftp[1] = 0x01;
    tftp_len += 2 ;

    sprintf(&ptftp[tftp_len],"%s",filename);
    tftp_len += strlen(filename);
    ptftp[tftp_len] = '\0';
    tftp_len += 1;

    sprintf(&ptftp[tftp_len],"%s","octet");
    tftp_len += strlen("octect");
    ptftp[tftp_len] = '\0';
    tftp_len += 1;

    udphdr = ptftp-sizeof(UDP_HDR);
    iphdr =  ptftp-sizeof(UDP_HDR)+ sizeof(ETH_HDR);

    /*UDP帧头信息*/
    udphdr->sport = HON(48915);
    udphdr->dport = HON(69);
    udphdr->len = HON(tftp_len+sizeof(UDP_HDR)-sizeof(IP_HDR));
    udphdr->udpchksum = 0x00;

    /*IP帧头信息*/
    udphdr->iphdr.vhl = 0x45;
    udphdr->iphdr.tos = 0x00;
    udphdr->iphdr.len = HON(tftp_len+sizeof(UDP_HDR)-sizeof(ETH_HDR));
    udphdr->iphdr.ipid = HON(0x00);
    udphdr->iphdr.ipoffset = HON(0x4000);
    udphdr->iphdr.ttl = 0xff;
    udphdr->iphdr.proto = 17;
    memcpy(udphdr->iphdr.srcipaddr,ip_addr,4);
    memcpy(udphdr->iphdr.destipaddr,host_ip_addr,4);
    udphdr->iphdr.ipchksum = 0;
    udphdr->iphdr.ipchksum = checksum(iphdr,20);

    memcpy(udphdr->iphdr.ethhdr.s_mac,mac_addr,6);
    memcpy(udphdr->iphdr.ethhdr.d_mac,host_mac_addr,6);
    udphdr->iphdr.ethhdr.type = HON(PROTO_IP);

    dm9000_tx((u32 *)udphdr,sizeof(UDP_HDR)+tftp_len);
}

void tftp_send_ack(u16 blocknum)
{
    u8 *ptftp = &sendbuf[200];
    u32 tftp_len = 0;
    UDP_HDR *udphdr;
    u8 *iphdr;

    ptftp[0] = 0x00;
    ptftp[1] = 0x04;
    tftp_len += 2 ;

    ptftp[2] = (blocknum&0xff00)>>8;
    ptftp[3] = (blocknum&0xff);
    tftp_len += 2 ;

    udphdr = ptftp-sizeof(UDP_HDR);
    iphdr =  ptftp-sizeof(UDP_HDR)+ sizeof(ETH_HDR);

    /*UDP帧头信息*/
    udphdr->sport = HON(48915);
    udphdr->dport = HON(serverport);
    udphdr->len = HON(tftp_len+sizeof(UDP_HDR)-sizeof(IP_HDR));
    udphdr->udpchksum = 0x00;

    /*IP帧头信息*/
    udphdr->iphdr.vhl = 0x45;
    udphdr->iphdr.tos = 0x00;
    udphdr->iphdr.len = HON(tftp_len+sizeof(UDP_HDR)-sizeof(ETH_HDR));
    udphdr->iphdr.ipid = HON(0x00);
    udphdr->iphdr.ipoffset = HON(0x4000);
    udphdr->iphdr.ttl = 0xff;
    udphdr->iphdr.proto = 17;
    memcpy(udphdr->iphdr.srcipaddr,ip_addr,4);
    memcpy(udphdr->iphdr.destipaddr,host_ip_addr,4);
    udphdr->iphdr.ipchksum = 0;
    udphdr->iphdr.ipchksum = checksum(iphdr,20);

    memcpy(udphdr->iphdr.ethhdr.s_mac,mac_addr,6);
    memcpy(udphdr->iphdr.ethhdr.d_mac,host_mac_addr,6);
    udphdr->iphdr.ethhdr.type = HON(PROTO_IP);

    dm9000_tx((u32 *)udphdr,sizeof(UDP_HDR)+tftp_len);
}

void tftp_process(u8 *buf, u32 len, u16 port)
{
     u32 i;
     u32 tftp_len;

     serverport = port;

     TFTP_PAK *ptftp = buf + sizeof(UDP_HDR);

     tftp_len = len - sizeof(UDP_HDR);

     if(HON(ptftp->opcode) == 3)
     {
         if (HON(ptftp->blocknum) == curblock)
         {
              for (i = 0;i<(tftp_len-4);i++)
              {
                  *(tftp_down_addr) = *(ptftp->data+i);
              } 

              tftp_send_ack(HON(ptftp->blocknum));

              curblock++;

              if ((tftp_len-4)<512)
                  curblock = 1;
         }
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值