一、简介
这里打算从U-Boot的ping命令说起。ping命令是用于测试网络是否和目标网络畅通简单工具,
在U-Boot中ping命令的使用方法是:
ping 比如我电脑的IP地址为192.168.1.10,ping命令使用如下:
ping192.168.1.10,如果开发板和目标IP之间的通信畅通的话,将输出如下信息:
host 192.168.1.100 is alive
否则显示:
ping failed;
host 192.168.1.100 is notalive
二、ping命令介绍
U-Boot中加入ping命令的代码如下:
U_BOOT_CMD(ping,// 命令名称
2, //参数个数
1,
do_ping, //命令执行函数
"sendICMP ECHO_REQUEST to network host",//长帮助说明
"pingAddress" );//短帮助说明
显然,我们需要分析do_ping函数
三、ping函数
int do_ping (cmd_tbl_t *cmdtp,
int flag,
int argc,//参数3和参数4是和main函数一样的参数
char *argv[])//我们在使用ping命令的时候的格式如下:ping 192.168.1.10
//因此这里的argv[1]就是我们的IP地址的字符串格式了
{
if (argc < 2)该命令的参数至少应该为2,如果参数个数小于2则直接返回
return-1;
NetPingIP =string_to_ip(argv[1]);//该函数将主机的字
//符串ip地址转换成点分ip地址
if (NetPingIP ==0)//NetPingIP是一个全局变量,定义在net/net.c中,
//如:IPaddr_tNetPingIP;
//而IPaddr_t在include/net.h文件中定义,
//定义如下:typedefulongIPaddr_t;也就是说他是一个长整形变量
{
cmd_usage(cmdtp);
return -1;
}
if(NetLoop(PING)<0)//若NetLoop函数返回值小于0,则网络不通;
{
printf("pingfailed;host%sisnotaliven",argv[1]);
return1;
}
printf("host%sisaliven",argv[1]);网络通畅。
return0;
}
一个ip地址占用32位,具体怎么转换的需要看看相关书籍,推荐TCP/IP协议簇,很不错的书
我们在PC机上执行如下操作:
ping www.baidu.com
正在 PING www.a.shifen.com (61.135.169.105) 具有32字节的数据:
来自61.135.169.105 的回复:字节=32 时间=31ms TTL=55
......
后面的就不看了,
我们看到一个IP地址:61.135.169.105
由于IP地址是点分十进制格式的。比如百度的这个IP地址61.135.169.105,他的意思就是把
一个32位的数分成4个字节,每个字节八位,用三个点分开的四个数分别占据这四个字节
当中的一个。因此百度的这个IP地址实际上可以转换成下面的格式:
61 ----0x3D
135----0x87
169----0xA9
105----0x69
那么这个整数就是0x3D87A969,转换为十进制就是1032300905。
在dos命令提示符下输入:ping 1032300905
正在 ping 61.135.169.105 具有32字节的数据:
......
我们在浏览器的地址栏里面输入: http://1032300905 也能打开百度搜索网页。这其实就
说明了一个问题: NetPingIP =string_to_ip(argv[1]); 这行代码把我们输入的IP地址
解析成了后面代码需要使用的IP地址,现在记住这一条就行了。
解析了IP地址,后面就是调用具体的工作函数NetLoop了。调用的时候
给了一个参数:PING。在include/net.h文件中有如下定义:
typedef enum
{ BOOTP, RARP, ARP, TFTP, DHCP, PING, DNS, NFS, CDP, NETCONS,SNTP } proto_t;
proto_t是一个枚举型的变量,我们可以凭此猜测这个NetLoop函数还可以接受
这个枚举定义的其他参数。准备工作就做到这里,下面接着看NetLoop函数。
这个函数比较庞大,在net/net.c文件中,我们分成若干部分来看:
intNetLoop(proto_t protocol)
{
bd_t *bd =gd->bd;
#ifdefCONFIG_NET_MULTI
NetRestarted =0;
NetDevExists = 0;
#endif
NetArpWaitPacketMAC =NULL;
NetArpWaitTxPacket = NULL;
NetArpWaitPacketIP =0;
NetArpWaitReplyIP =0;
NetArpWaitTxPacket =NULL;
NetTxPacket =NULL;
NetTryCount = 1;
if (!NetTxPacket)//因为在前边这个变量定义为NULL,那么该部分肯定会执行,这里有点冗余
{
int i;// Setup packetbuffers,alignedcorrectly.
//NetTxPacket是一个unsignedchar类型的指针,通过该语句,该指针指向PktBuf的第32个位置
NetTxPacket= &PktBuf[0] + (PKTALIGN -1);
NetTxPacket -= (ulong)NetTxPacket %PKTALIGN;//32字节对齐,这两句的意思是,首先加
//31,相当于指针指向数组的第31个位置,除以32,然后减去该地址除以32的余数,这这两
//句执行完毕后NetTxPacket指向的PtkBuf地址肯定能被32整除,有可能导致数组一些位置不
//在使用之所以要先加后除是因为不过不先加的话,可能导致操作时超出数组的边界.
for (i = 0; i < PKTBUFSRX; i++)
{
NetRxPackets[i] = NetTxPacket +(i+1)*PKTSIZE_ALIGN;
}
}
NetTxPacket = &PktBuf[0] + (PKTALIGN -1); //PktBuf是一个字符数组,
// 定义如下: volatileuchar PktBuf[(PKTBUFSRX+1) * PKTSIZE_ALIGN+ PKTALIGN];
//这上面的三个宏定义分别如下:
//# define PKTBUFSRX4
//#definePKTSIZE_ALIGN1536
//#definePKTALIGN32
//所以这里定义的是一个大概5个1536字节大的数组。继续看下面:
NetTxPacket-= (ulong)NetTxPacket % PKTALIGN;
//NetTxPacket先是获得了一个地址,然后把这个地址减去一个值,减去的这个值
//是地址本身和32的余数,那么实际上就是把NetTxPacket进行32字节对齐了。
for (i = 0; i < PKTBUFSRX; i++)
{
NetRxPackets[i] = NetTxPacket +(i+1)*PKTSIZE_ALIGN;
}
//实际上就是把NetRxPackets数组进行赋值,这个数组定义如下:
//volatile uchar *NetRxPackets[PKTBUFSRX]; 说明它也是指向字符串的数组,
//可以知道这个数组都被赋予了PktBuf当中的某个地址,并且这些地址都是
//32位对其的。
if (!NetArpWaitTxPacket)//传输包不为空执行以下操作
{//以下两句仍然是32字节对齐
NetArpWaitTxPacket=&NetArpWaitPacketBuf[0]+(PKTALIGN-1);
NetArpWaitTxPacket-=(ulong)NetArpWaitTxPacket%PKTALIGN;
NetArpWaitTxPacketSize =0;
}
//同样,这里这个判断貌似也是多余,因为前面已经直接把
//NetArpWaitTxPacket设置为了NULL,这个后面的代码肯定会执行的。
//继续后面的代码:
NetArpWaitTxPacket = &NetArpWaitPacketBuf[0] + (PKTALIGN -1);
//先给它一个值,这个值就是数组当中的一个地址,数组定义如下:
//ucharNetArpWaitPacketBuf[ PKTSIZE_ALIGN + PKTALIGN];
//然后和上面的一样,进行一个地址对齐,32位:
//NetArpWaitTxPacket -= (ulong)NetArpWaitTxPacket %PKTALIGN;
//到这里,一些housekeeping的代码就完成了,然后是一些和硬件相关的:
eth_halt();
#ifdefCONFIG_NET_MULTI
eth_set_current();
#endif
if (eth_init(bd) < 0)
{
eth_halt();
return(-1);
}
首先是eth_halt()函数,定义在net/eth.c文件中:
void eth_halt(void)
{
if(!eth_current)
return;
eth_current->halt(eth_current);
eth_current->state = ETH_STATE_PASSIVE;
}
//实际上它只是调用了具体网卡驱动的halt函数,然后把网卡状态设置为
//passive。由于网卡驱动的halt函数只是进行了网卡的硬件操作,不是我们这
//里关心的重点,因此这里就不分析了。同样,后面的eth_init函数也调用
//的是网卡驱动的init函数,对网卡硬件进行一个初始化,接着看下面的代码:
restart:
#ifdefCONFIG_NET_MULTI
memcpy (NetOurEther, eth_get_dev()->enetaddr, 6);
#else
eth_getenv_enetaddr("ethaddr",NetOurEther);//该行执行完毕后,NetOurEther的值等于我在
//fs2410.h定义的MAC地址值
#endif
//实际上执行的是第一个函数,可以看出我们实际上是把本机的mac
//地址拷贝到了NetOurEther中。本机的mac地址是在调用eth_init函
//数的时候从网络控制器中读取到当前网络设备的enetaddr中的,和
//具体硬件相关。
NetState = NETLOOP_CONTINUE
//然后设置网络状态,初始化循环。
switch (protocol) {//protocol =3 =ping
#if (CONFIG_COMMANDS & CFG_CMD_NFS)
case NFS:
#endif
#if (CONFIG_COMMANDS & CFG_CMD_PING)
case PING:
#endif
#if (CONFIG_COMMANDS & CFG_CMD_SNTP)
case SNTP:
#endif
case NETCONS:
case TFTP:
NetCopyIP(&NetOurIP,&bd->bi_ip_addr);//程序执行后,NetOurIP=192.168.1.5
NetOurGatewayIP =getenv_IPaddr ("gatewayip");//NetOurGatewayIP=NULL,因为gatewayip为空
NetOurSubnetMask=getenv_IPaddr ("netmask");//该命令执行后NetOurSubnetMask=255.255.255.0
NetOurVLAN =getenv_VLAN("vlan"); //该命令执行后 NetOurVLAN的结果为NULL
NetOurNativeVLAN= getenv_VLAN("nvlan");//同上
switch(protocol) {//protocol =3 =ping
#if (CONFIG_COMMANDS & CFG_CMD_NFS)
case NFS:
#endif
caseNETCONS:
case TFTP:
NetServerIP= getenv_IPaddr ("serverip"); //该命令执行后NetServerIP=192.168.1.10.该值在
//fs2410.h中定义
break;
#if (CONFIG_COMMANDS & CFG_CMD_PING)
case PING:
break;
#endif
#if (CONFIG_COMMANDS & CFG_CMD_SNTP)
case SNTP:
break;
#endif
default:
break;
}
break;
case BOOTP:
case RARP:
NetOurIP =0;
NetServerIP =getenv_IPaddr ("serverip");
NetOurVLAN =getenv_VLAN("vlan");
NetOurNativeVLAN= getenv_VLAN("nvlan");
case CDP:
NetOurVLAN =getenv_VLAN("vlan");
NetOurNativeVLAN= getenv_VLAN("nvlan");
break;
default:
break;
}
switch (net_check_prereq (protocol)){//这个函数返回0
case 1:
eth_halt();
return (-1);
#ifdef CONFIG_NET_MULTI
case 2:
break;
#endif
case 0:
#ifdef CONFIG_NET_MULTI
NetDevExists =1;//存在一个网络设备
#endif
switch (protocol){//protocol =3 =ping执行ping命令
case TFTP:
TftpStart();
break;
#if (CONFIG_COMMANDS & CFG_CMD_DHCP)
case DHCP:
BootpTry= 0;
NetOurIP= 0;
NetServerIP= getenv_IPaddr ("serverip");
DhcpRequest();
break;
#endif
caseBOOTP:
BootpTry= 0;
BootpRequest();
break;
caseRARP:
RarpTry= 0;
RarpRequest();
break;
#if (CONFIG_COMMANDS & CFG_CMD_PING)
casePING://执行这一部分
PingStart();
break;
#endif
#if (CONFIG_COMMANDS & CFG_CMD_NFS)
case NFS:
NfsStart();
break;
#endif
#if (CONFIG_COMMANDS & CFG_CMD_CDP)
case CDP:
CDPStart();
break;
#endif
#ifdef CONFIG_NETCONSOLE
caseNETCONS:
NcStart();
break;
#endif
#if (CONFIG_COMMANDS & CFG_CMD_SNTP)
case SNTP:
SntpStart();
break;
#endif
default:
break;
}
NetBootFileXferSize= 0;
break;
}
//以下下划线之间的部分不执行,因为那些宏我们没定义
----------------------------------------------------------------------------------------------
#if defined(CONFIG_MII) || (CONFIG_COMMANDS &CFG_CMD_MII)
#if defined(CFG_FAULT_ECHO_LINK_DOWN) &&defined(CONFIG_STATUS_LED) && defined(STATUS_LED_RED)
if(miiphy_link(eth_get_dev()->name,CFG_FAULT_MII_ADDR)) {
status_led_set(STATUS_LED_RED, STATUS_LED_OFF);
} else {
status_led_set(STATUS_LED_RED, STATUS_LED_ON);
}
#endif
#endif
------------------------------------------------------------------------------------------------
//*Main packet receptionloop. Loop receiving packets until
//someonesets `NetState' to a state that terminates.
for (;;) {
WATCHDOG_RESET();
#ifdef CONFIG_SHOW_ACTIVITY
{
externvoid show_activity(int arg);
show_activity(1);
}
#endif
eth_rx();
if (ctrlc()){
eth_halt();
puts("nAbortn");
return(-1);
}
ArpTimeoutCheck();
if (timeHandler&& ((get_timer(0) - timeStart) > timeDelta)) {
thand_f*x;
#if defined(CONFIG_MII) || (CONFIG_COMMANDS &CFG_CMD_MII)
# if defined(CFG_FAULT_ECHO_LINK_DOWN)&&
defined(CONFIG_STATUS_LED)&&
defined(STATUS_LED_RED)
if(miiphy_link(eth_get_dev()->name,CFG_FAULT_MII_ADDR)) {
status_led_set(STATUS_LED_RED, STATUS_LED_OFF);
}else {
status_led_set(STATUS_LED_RED, STATUS_LED_ON);
}
# endif
#endif
x= timeHandler;
timeHandler= (thand_f *)0;
(*x)();
}
switch (NetState){
caseNETLOOP_RESTART:
#ifdef CONFIG_NET_MULTI
NetRestarted= 1;
#endif
gotorestart;
caseNETLOOP_SUCCESS:
if(NetBootFileXferSize > 0) {
charbuf[10];
printf("Bytestransferred = %ld (%lx hex)n",
NetBootFileXferSize,
NetBootFileXferSize);
sprintf(buf,"%lx", NetBootFileXferSize);
setenv("filesize",buf);
sprintf(buf,"%lX", (unsigned long)load_addr);
setenv("fileaddr",buf);
}
eth_halt();
returnNetBootFileXferSize;
caseNETLOOP_FAIL:
return(-1);
}
}
下一节,我们将分析PingStart这个函数