uboot tftp code structure


TftpSend (void)
pkt = NetTxPacket + NetEthHdrSize() + IP_HDR_SIZE;
case STATE_RRQ:
xp = pkt;
s = (ushort *)pkt;
*s++ = htons(TFTP_RRQ);
pkt = (uchar *)s;
strcpy ((char *)pkt, tftp_filename);
pkt += strlen(tftp_filename) + 1;
strcpy ((char *)pkt, "octet");
pkt += 5 /*strlen("octet")*/ + 1;
strcpy ((char *)pkt, "timeout");
pkt += 7 /*strlen("timeout")*/ + 1;
sprintf((char *)pkt, "%d", TIMEOUT);
pkt += strlen((char *)pkt) + 1;
len = pkt - xp;
break;


NetSendUDPPacket(NetServerEther, NetServerIP, TftpServerPort, TftpOurPort, len);
这个函数向tftp server发送一个packet
在上面的case中,在这个case中,设置一个即将发送的读数据请求报文:TFTP动作、tftp传输的文件名、模式“octet”、选项0“timeout”,选项0的值5.
tftp传输的文件名,模式“octet”,选项0“timeout”,选项0的值5之间有‘\0'.




. TftpHandler()
这个函数时tftp client的接收到数据时处理函数,处理数据包、OACK包、error包等。


TftpHandler (uchar * pkt, unsigned dest, unsigned src, unsigned len)
s = (ushort *)pkt;
proto = *s++; // 得到两字节的tftp动作编号
pkt = (uchar *)s;
switch (ntohs(proto)) {


case TFTP_RRQ:
case TFTP_WRQ:
case TFTP_ACK:
break;
default:
break;


case TFTP_OACK:
#ifdef ET_DEBUG
printf("Got OACK: %s %s\n", pkt, pkt+strlen(pkt)+1);
#endif
TftpState = STATE_OACK;
TftpServerPort = src;
TftpSend (); /* Send ACK */
break;
case TFTP_DATA: // 这个packet时tftp数据包
if (((TftpBlock - 1) % 10) == 0) { // TftpBlock是数据包的编号,每10个包才会输出一个#
putc ('#');
} else if ((TftpBlock % (10 * HASHES_PER_LINE)) == 0) { // 每650个包换行
puts ("\n\t ");
}
NetSetTimeout (TIMEOUT * CFG_HZ, TftpTimeout);


store_block (TftpBlock - 1, pkt + 2, len); // 将tftp数据包保存值存储器(flash或者RAM)


/*
* Acknoledge the block just received, which will prompt
* the server for the next one.
*/
TftpSend (); // 发送一个已接收到此数据包的ACK(格式:tftp动作编号ACK+这个数据包的编号)


.
void TftpStart (void)
这个函数主要做的事情如下:
1. 检查tftp传输的文件的文件名,如果是null,使用default文件名;
2. 设置tftp timeout处理函数;
NetSetTimeout (TIMEOUT * CFG_HZ, TftpTimeout);
3. 设置tftp client收到tftp包(有ACK包、OACK包、数据包等)后处理packet的函数
NetSetHandler (TftpHandler);
4. 设置tftp初始状态为读tftp server数据包请求STATE_RRQ;
TftpState = STATE_RRQ;
5. 发送这个读数据包请求的报文(格式:tftp动作编号+要读取的文件名+模式+timeout选项+timeout选项值)。
TftpSend ();




. TftpStart()的调用
tftpboot 0x1000000 u-boot
int do_tftpb (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
return netboot_common (TFTP, cmdtp, argc, argv);
}


U_BOOT_CMD( // 在cmd_net.c中
tftpboot, 3, 1, do_tftpb,
"tftpboot- boot image via network using TFTP protocol\n",
"[loadAddress] [bootfilename]\n"
);


netboot_common (proto_t proto, cmd_tbl_t *cmdtp, int argc, char *argv[])
switch (argc) {
case 3: load_addr = simple_strtoul(argv[1], NULL, 16);
copy_filename (BootFile, argv[2], sizeof(BootFile));
if ((size = NetLoop(proto)) < 0)
return 1;


. NetReceive(volatile uchar * inpkt, int len)函数解析
NetReceive(volatile uchar * inpkt, int len) // inpkt是整个packet的内容,len是大小
x = ntohs(et->et_protlen); // 得到这个packet的长度或者协议
if (x < 1514) { // 这里的x应该是指packet的长度
/*
* Got a 802 packet.  Check the other protocol field.
*/
x = ntohs(et->et_prot);


ip = (IP_t *)(inpkt + E802_HDR_SIZE);
len -= E802_HDR_SIZE;


} else if (x != PROT_VLAN) { /* normal packet */ // 这里的x应该是指协议
ip = (IP_t *)(inpkt + ETHER_HDR_SIZE); // Ethernet header size,将ip指向这个packet header后面的数据部分。
len -= ETHER_HDR_SIZE; // packet的长度减去packet header的长度,结果len就是packet数据部分的长度。


} else { /* VLAN packet */
    
    switch(x)
case PROT_IP:   // 使用ip协议
if (ip->ip_p == IPPROTO_ICMP) { // 现在的ip指向packet的Internet Protocol (IP) header
   // 检查check sum
 
* IP header OK.  Pass the packet to the current handler.
*/
// 处理packet的纯数据部分
(*packetHandler)((uchar *)ip +IP_HDR_SIZE,
ntohs(ip->udp_dst),
ntohs(ip->udp_src),
ntohs(ip->udp_len) - 8);


从上面可以总结这个packet的结构是这样的:
Ethernet header --- Internet Protocol (IP) header --- effective data
ETHER_HDR_SIZE          IP_HDR_SIZE






基于TFTP协议的远程升级设计
http://blog.csdn.net/zhzht19861011/article/details/46403617
U-boot中TFTP解释及nfs命令的小bug
http://blog.chinaunix.net/uid-20672257-id-2899526.html
TFTP协议详解
http://linux.chinaunix.net/techdoc/net/2009/05/04/1109928.shtml























你可能感兴趣的:(U-BOOT)