Chinaunix首页 | 论坛 | 博客
  • 博客访问: 353384
  • 博文数量: 49
  • 博客积分: 3229
  • 博客等级: 中校
  • 技术积分: 616
  • 用 户 组: 普通用户
  • 注册时间: 2006-11-26 21:46
文章分类

全部博文(49)

文章存档

2011年(8)

2010年(2)

2009年(3)

2008年(36)

我的朋友

分类:

2008-09-25 11:42:23

以uboot-1.3.3为例,我们来看看其tftp下载实现的方法。
先看发送接受缓存区的内存分布:
 32bytes NetTxPacket      1536bytes
    |-----------|-------------------------------------|
 NetRxPackets[0]|-------------------------------------|
 NetRxPackets[1]|-------------------------------------|
 NetRxPackets[2]|-------------------------------------|
 NetRxPackets[3]|-------------------------------------|
   
   32bytes  NetArpWaitTxPacket  1536bytes   
    |-----------|-------------------------------------|

再来看几个函数的实现:
NetLoop():
设置NetOurEther,NetOurIP,NetourGateWayIp,NetOurSubnetMark,NetOurVLAN,NetOurNativeVlan,NetserveIP.的值,--->TftpStart()发送一个TFTP读请求或者ARP请求--->eth_rx()接受一个网络包--->ArpTimeoutcheck()arp超时检查,

TftpStart():
设置超时处理函数TftpTimeout--->设置接受到一个tftp包的处理函数TftpHander---->服务器端口号设为69--->板子的端口号根据时间随机产生-->TftpState = STATE_RRQ;TftpBlock = 0;TftpBlkSize = TFTP_BLOCK_SIZE;-->TftpSend ()

TftpSend():
设置tftp包头,设为tftp读请求--->NetSendUDPPacket()
RRQ请求的包头:

2 bytes    string   1 byte string 1 byte
------------------------------------------------
| Opcode | Filename | 0 | Mode | 0 |
------------------------------------------------
操作码Opcode设为TFTP_RRQ,Filename和0合起来就是个以\0结束的字符串.模式Mode包括了字符串"netascii","octet"或"mail",名称不分大小写。netascii格式数据的主机必须将数据转换为本地格式。octet模式用于传输文件,这种文件在源机上以8位格式存储。同样Mode和0合起来就是个以\0结束的字符串


NetSendUDPPacket():
如果知道服务器的mac,则有NetSetEther()--->NetSetIP()--->eth_send()。否则将先前带发送的数据包复制到NetArpWaitTxPacket中,然后执行一次arp请求。待收到arp应答之后,再填充NetArpWaitTxPacket的各协议头,发送出去。

NetSetEther():
设置帧头,其格式为:
------------------------------------------
|目的mac  |源mac   |类型     |
------------------------------------------ 
如果为一般的ip数据包,这类型字段为0x0800 , 如为arp请求/应答,则为0x0806,如为rarp请求应答,则为0x8035。。
如果是要arp请求,则目的mac设为: 0xff:0xff:0xff:0xff:0xff:0xff
帧头占14个字节(以太网封装,RFC894)

     
NetSetIP():
设置IP首部和UDP首部。IP首部需要源IP和目的IP,UDP首部需要源端口和目的端口。
如果TFTP数据报的长度是奇数,这在数据报后补0,使为偶数,目的是为了好计算校验和。
以下是uboot-1.3.3中NetSetIP函数的片断:


void
NetSetIP(volatile uchar * xip, IPaddr_t dest, int dport, int sport, int len)
{
    volatile IP_t *ip = (IP_t *)xip;

    /*
     * If the data is an odd number of bytes, zero the
     * byte after the last byte so that the checksum
     * will work.
    */

    if (len & 1)
        xip[IP_HDR_SIZE + len] = 0;

    /*
     * Construct an IP and UDP header.
     * (need to set no fragment bit - XXX)
    */

    ip->ip_hl_v = 0x45; /* IP_HDR_SIZE / 4 (not including UDP) */
    ip->ip_tos = 0;
    ip->ip_len = htons(IP_HDR_SIZE + len);
    ip->ip_id = htons(NetIPID++);
    ...
    ...
}

用arm-linux-gcc 2.95.3编译器编译通过,运行的时候却卡在了这个函数中,百思不得其解为什么。后来参考kn所做的vivi_tftp的代码,将volatile IP_t *ip = (IP_t *)xip;改为IP_t *ip = (IP_t *)xip;问题解决。。

ArpRequest():
填充一个arp包.
arp包格式:
--------------------------------------------------------------------------------------------------------
|以太网首部|硬件类型|协议类型|硬件地址长度|协议地址长度|op|发送端以太网地址|发送端ip|目的以太网地址|目的IP地址
--------------------------------------------------------------------------------------------------------


NetReceive():
当用eth_rx接受到一个包之后就会调用NetReceive对包进行分析并处理。
通过对以太网帧头的分析得出此包是个IP数据报,arp请求/应答包还是rarp请求/应答包.然后对不同类型的包,有不同的处理方法。

tcp/ip协议结构图



阅读(2042) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~

chinaunix网友2009-12-01 21:28:04

原来是,过真是,将volatile IP_t *ip = (IP_t *)xip;改为IP_t *ip = (IP_t *)xip;问题解决。。,好爽,搞了好久,原来是这个问题,害我一段段调试。