uboot ping doesn’t work

Ping doesn‘t work

Ping from U-Boot to a host should work. Ping from a host to U-Boot should not.

U-Boot uses a polling interface for networking - if you have not run a command, it will not respond to any packets.

 

 

uboot-ping代码学习笔记

2011-02-20, root

最近这两天学习了uboot的ping源代码,现在做一下笔记。

    uboot :v1.1.6

    uboot从start.s启动后会跳转到lib_arm/board.c里的start_armboot函数,从这以后都

         是C语言代码。start_armboot做了一些初始化化然后在死循环里调用main_loop函数 :

/* main_loop() can return to retry autoboot, if so just run it again. */

for (;;) {

main_loop ();

}

main_loop是在;common/main.c中定义的,下面是从串中读取命令然后执行的一部分代码:

for (;;) {

len = readline (CFG_PROMPT); //从串口读入命令

flag = 0; /* assume no special flags for now */

if (len > 0)

strcpy (lastcommand, console_buffer);

else if (len == 0)

flag |= CMD_FLAG_REPEAT;

}

if (len == -1)

puts ("<INTERRUPT>/n");

else

rc = run_command (lastcommand, flag); // 执行命令

if (rc <= 0) {

/* invalid command or not repeatable, forget it */

lastcommand[0] = 0;

}

}

run_command首先调用find_command在命令列表里查找到输入的命令:

/* Look up command in command table */

if ((cmdtp = find_cmd(argv[0])) == NULL) {

printf ("Unknown command ‘%s‘ - try ‘help‘/n", argv[0]);

rc = -1; /* give up after bad command */

continue;

}

    find_cmd返回的是cmd_tbl_t类型,cmd_tbl_t里有命令对应的执行函数,再调用具体的

          执行函数来执行命令具体的操作:

/* OK - call function to do the command */

if ((cmdtp->cmd) (cmdtp, flag, argc, argv) != 0) {

rc = -1;

}

    uboot所有的命令都定义在commom目录下,ping命令在cmd_net.c文件里定义,定义如下:   

    U_BOOT_CMD(

ping, 2, 1, do_ping,

"ping/t- send ICMP ECHO_REQUEST to network host/n",

"pingAddress/n"

    ); 

U_BOOT_CMD定义如下:

/*

* Monitor Command

*

* All commands use a common argument format:

*

* void function (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);

*/

struct cmd_tbl_s {

char *name; // Command Name

int maxargs; // maximum number of arguments

int repeatable; // autorepeat allowed?

// Implementation function

int (*cmd)(struct cmd_tbl_s *, int, int, char *[]);

char *usage; // Usage message (short)

#ifdef CFG_LONGHELP

char *help; // Help  message (long)

#endif

#ifdef CONFIG_AUTO_COMPLETE

// do auto completion on the arguments

int (*complete)(int argc, char *argv[], char last_char, int maxv, char *cmdv[]);

#endif

};

typedef struct cmd_tbl_s cmd_tbl_t;

#define Struct_Section  __attribute__ ((unused,section (".u_boot_cmd")))

#define U_BOOT_CMD(name,maxargs,rep,cmd,usage,help) /

cmd_tbl_t __u_boot_cmd_##name Struct_Section = {#name, maxargs, rep, cmd, usage}

ping命令定义的展开:

cmd_tbl_t __u_boot_cmd_ping __attribute__ ((unused, section (".u_boot_cmd"))) = {

"ping", // name

2,      // maxargs

1, // repeatable

do_ping,// (*cmd)(struct cmd_tbl_s *, int, int, char *[]);

"ping/t- send ICMP ECHO_REQUEST to network host/n", // *usage

"pingAddress/n", // *help

}

从这里可以看出,ping命令其实是调用的do_ping函数来实行具体的ping操作,do_ping的定义如下:

int do_ping (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])

{

if (argc < 2)

return -1;

NetPingIP = string_to_ip(argv[1]);

if (NetPingIP == 0) {

printf ("Usage:/n%s/n", cmdtp->usage);

return -1;

}

if (NetLoop(PING) < 0) {

printf("ping failed; host %s is not alive/n", argv[1]);

return 1;

}

printf("host %s is alive/n", argv[1]);

return 0;

}

执行ping命令:

EmbedSky> ping 192.168.1.1

dm9000 i/o: 0x20000300, id: 0x90000a46

MAC: 0a:1b:2c:3d:4e:5f

ping failed; host 192.168.1.1 is not alive

do_ping首先将192.168.1.1存在NetPingIP变量里边,然后调用NetLoop函数,如果执行成功

显示:

host 192.168.1.1 is alive

如果不成功显示:

host 192.168.1.1 is not alive

然后 退出。

NetLoop主要的工作是打包各命令对应的数据包,通过eth_send函数发送数据包,然后在死循

环里调用eth_rx来接收一个完整的ethernet帧,eth_rx收到的帧会传给NetRecive函数分析处

理。

对于ping命令,NetLoop调用PingStart

static void PingStart(void)

{

#if defined(CONFIG_NET_MULTI)

printf ("Using %s device/n", eth_get_name());

#endif /* CONFIG_NET_MULTI */

NetSetTimeout (10 * CFG_HZ, PingTimeout);

NetSetHandler (PingHandler);

PingSend();

}

PingStart首先设置接收到Ping数据包后调用的处理函数,然后调用PingSeng

发送ICMP数据包。

NetReceive处理接收到的ICMP数据包最后会调用PingHandler函数来结束Ping

操作,PingHandler只是将NetState改为NETLOOP_SUCCESS,在NetLoop里会一直

检测NetState的状态(刚进入NetLoop函数的时候NetState为NETLOOP_CONTINUE),

如果为 NETLOOP_SUCCESS 或NETLOOP_FAIL则NetLoop就会退出:

switch (NetState) {

case NETLOOP_RESTART:

#ifdef CONFIG_NET_MULTI

NetRestarted = 1;

#endif

goto restart;

case NETLOOP_SUCCESS:

if (NetBootFileXferSize > 0) {

char buf[10];

printf("Bytes transferred = %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();

return NetBootFileXferSize;

case NETLOOP_FAIL:

return (-1);

}

PingHandler (uchar * pkt, unsigned dest, unsigned src, unsigned len)

{

IPaddr_t tmp;

volatile IP_t *ip = (volatile IP_t *)pkt;

tmp = NetReadIP((void *)&ip->ip_src);

if (tmp != NetPingIP)

return;

NetState = NETLOOP_SUCCESS;

}

int PingSend(void)

{

static uchar mac[6];

volatile IP_t *ip;

volatile ushort *s;

uchar *pkt;

/* XXX always send arp request */

memcpy(mac, NetEtherNullAddr, 6);

#ifdef ET_DEBUG

printf("sending ARP for %08lx/n", NetPingIP);

#endif

NetArpWaitPacketIP = NetPingIP;

NetArpWaitPacketMAC = mac;

pkt = NetArpWaitTxPacket;

pkt += NetSetEther(pkt, mac, PROT_IP);

ip = (volatile IP_t *)pkt;

/*

* Construct an IP and ICMP 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_NO_UDP + 8);

ip->ip_id    = htons(NetIPID++);

ip->ip_off   = htons(0x4000); /* No fragmentation */

ip->ip_ttl   = 255;

ip->ip_p     = IPPROTO_ICMP; /* ICMP */

ip->ip_sum   = 0;

NetCopyIP((void*)&ip->ip_src, &NetOurIP); /* already in network byte order */

NetCopyIP((void*)&ip->ip_dst, &NetPingIP);   /* - "" - */

ip->ip_sum   = ~NetCksum((uchar *)ip, IP_HDR_SIZE_NO_UDP / 2);

s = &ip->udp_src; /* ICMP starts here */

s[0] = htons(0x0800); /* echo-request, code */

s[1] = 0; /* checksum */

s[2] = 0; /* identifier */

s[3] = htons(PingSeqNo++); /* sequence number */

s[1] = ~NetCksum((uchar *)s, 8/2);

/* size of the waiting packet */

NetArpWaitTxPacketSize = (pkt - NetArpWaitTxPacket) + IP_HDR_SIZE_NO_UDP + 8;

/* and do the ARP request */

NetArpWaitTry = 1;

NetArpWaitTimerStart = get_timer(0);

ArpRequest();

return 1; /* waiting */

}

PingSend调用NetSetEther封装ethernet帧的头部,NetSetEther参数:

mac    :为目的host的mac,在这里全为0,因为我们只知道目的主机的ip,

            现在还不知道它的mac地址

PROT_IP: 说明该ethernet帧里封装的是IP包。ethernet帧分三种类型,根据

ethernet的type来判断是哪种类型。

ethernet帧的封装:

|destination addr| source addr |type| data |crc|

6         6       2 46-1500  4 bytes

type:

PROT_IP 0x0800 /* IP protocol */

PROT_ARP 0x0806 /* IP ARP protocol */

PROT_RARP 0x8035 /* IP ARP protocol */

PingSend再将IP包封装成ICMP包:

ip->ip_p     = IPPROTO_ICMP; /* ICMP */

IP包跟ethernet帧一样,也是复用的数据包,所有IP头部用1字节的proto标示来说明

IP包是哪类:

IPPROTO_ICMP 1 /* Internet Control Message Protocol */

IPPROTO_UDP 17 /* User Datagram Protocol */

IPPROTO_TCP 6 /* Transmission Control Protocol */

IPPROTO_IGMP 2 /* Internet Group Message Protocol */

ICMP将该ICMP包类型设置为echo request:

s[0] = htons(0x0800); /* echo-request, code */

封装完IP包和ICMP包后,没有立即将该ethernet帧发出去,因为现在我们只知道目的主机的

IP地址,并不知道它的ethernet地址,所以先调用ArpRequest函数取得目的主机的ethernet

地址,再ping封装的ethernet帧发送出去。

ArpRequest函数将ethernet帧封装为ARP request帧,然后广播该帧。

void ArpRequest (void)

{

int i;

volatile uchar *pkt;

ARP_t *arp;

#ifdef ET_DEBUG

printf ("ARP broadcast %d/n", NetArpWaitTry);

#endif

pkt = NetTxPacket;

pkt += NetSetEther (pkt, NetBcastAddr, PROT_ARP); // PORT_ARP说明该

// 帧为ARP帧

arp = (ARP_t *) pkt;

arp->ar_hrd = htons (ARP_ETHER);// 物理地址类型,在此为ethernet地址

arp->ar_pro = htons (PROT_IP);  // 逻辑地址类型,在此为IP地址

arp->ar_hln = 6; // 物理地址类型的长度

arp->ar_pln = 4; // 逻辑地址类型的长度

arp->ar_op = htons (ARPOP_REQUEST);

memcpy (&arp->ar_data[0], NetOurEther, 6); /* source ET addr */

NetWriteIP ((uchar *) & arp->ar_data[6], NetOurIP); /* source IP addr */

for (i = 10; i < 16; ++i) {

arp->ar_data[i] = 0; /* dest ET addr = 0 */ //广播该帧

}

if ((NetArpWaitPacketIP & NetOurSubnetMask) !=

   (NetOurIP & NetOurSubnetMask)) {

if (NetOurGatewayIP == 0) {

puts ("## Warning: gatewayip needed but not set/n");

NetArpWaitReplyIP = NetArpWaitPacketIP;

} else {

NetArpWaitReplyIP = NetOurGatewayIP;

}

} else {

NetArpWaitReplyIP = NetArpWaitPacketIP;

}

NetWriteIP ((uchar *) & arp->ar_data[16], NetArpWaitReplyIP); /* dest ip addr */

(void) eth_send (NetTxPacket, (pkt - NetTxPacket) + ARP_HDR_SIZE); //通过底层硬件发送该ethernet帧

}

接收ARP Replay帧和icmp echo replay帧是在NetLoop里的eth_rx进行的,eth_rx收到一个完整的帧后将该帧

传送给NetReceive处理。

NetReceive处理ARP Replay帧:

case ARPOP_REPLY: /* arp reply */

/* are we waiting for a reply */

if (!NetArpWaitPacketIP || !NetArpWaitPacketMAC)

break;

tmp = NetReadIP(&arp->ar_data[6]);

/* matched waiting packet‘s address */

if (tmp == NetArpWaitReplyIP) {

/* save address for later use */

memcpy(NetArpWaitPacketMAC, &arp->ar_data[0], 6);

/* modify header, and transmit it */

// 将返回的目标主机的mac地址放入PingSend封装的ethernet帧,然后发送该ping帧

memcpy(((Ethernet_t *)NetArpWaitTxPacket)->et_dest, NetArpWaitPacketMAC, 6);

(void) eth_send(NetArpWaitTxPacket, NetArpWaitTxPacketSize);

/* no arp request pending now */

NetArpWaitPacketIP = 0;

NetArpWaitTxPacketSize = 0;

NetArpWaitPacketMAC = NULL;

}

return;

NetReceive处理icmp echo replay帧:

case ICMP_ECHO_REPLY:

/*

* IP header OK.  Pass the packet to the current handler.

*/

/* XXX point to ip packet */

(*packetHandler)((uchar *)ip, 0, 0, 0);

return;

只是调用PingHandler函数将NetState设置为NETLOOP_SUCCESS,结束NetLoop循环,

打印ping结果,然后退出do_ping函数。

时间: 2024-11-13 09:02:49

uboot ping doesn’t work的相关文章

S5P210-uboot源码分析-uboot如何启动内核

uboot如何启动内核 7.1.uboot和内核到底是什么? 1.uboot是一个裸机程序 (1)uboot的本质就是一个复杂点的裸机程序,和我们arm裸机中写的程序没有什么本质上的区别. (2)uboot最像我们在arm裸机中的最后写的那个shell,它其实就是一个迷你型的uboot. 2.linux内核本身也是一个"裸机程序" (1)操作系统内核本身就是一个裸机程序,和uboot并没有本质区别. (2)区别在于,操作系统运行起来后在软件层次上可以分为内核层和应用层,分层后两层的权限

20150430 调试分析之 根据内核报错信息PC指针分析错误

20150430 调试分析之 根据内核报错信息PC指针分析错误 2015-04-30 Lover雪儿 大家写驱动的时候不知道有没有发现,当我们驱动写错了,发生内核奔溃时,会打印一大堆的报错信息, 如果再返回我们的程序中一行一行代码的检查,既耗费时间,并且有些逻辑上的错误,我们是很难看的出来的, 那我们能不能再这一大堆的报错信息中发现问题的所在呢? 此处我们来模拟一个错误,还是沿用上一篇文章中的驱动代码err_led.c的驱动程序中的代码修改错误,当然大家用其他的驱动代码做测试也可以. 博客地址:

OMAPL138调试笔记

title: Linux 嵌入式使用 tags: 新建,模板,小书匠 grammar_cjkRuby: true Copyright (C) @2018 Widic Filename: File-function: Cre_ID: @ Widic 2018-1-23 Mod_ID: 三 学习过程 20170617 uart2 作为调试串口 band rate 115200 串口调试终端采用ZOC 3.开发板启动开官如下: SD卡挂载boot分区挂载在/media/mmcblk0p1 u盘挂载的方

u-boot可ping通PC,PC不可ping通u-boot

http://blog.csdn.net/ce123_zhouwei/article/details/7339134 开发板运行U-Boot,在终端下使用Ping命令是能Ping通PC机,但PC机Ping不同U-Boot. 在开发行U-Boo下的Ethernet 驱动时,只能在Target上去Ping 外面的主机能检测以太网是否连通,如果在外面的主机上去ping目标板,则即使目标板上的Ethernet一切OK,也是ping 不通的.这是因为行U-Boo是一个单线程main_loop函数+中断处理

主机、虚拟机、开发板(u-boot)之间的连接 - ping测试

1.设置主机的IP地址(这里注意,设置一定要设置网线宽带IP,不要选成无线网络的) 查看重点是否本地以太网卡(Realtek PCIe……) 2.修改本地连接3个IP地址,一定主机.虚拟机.开发板 三者一定要匹配,网段要一致.       3.设置虚拟机的操作系统网络设置 4.设置虚拟机的虚拟网络.

2017.2.28学习笔记------------uboot 与linux内核的打补丁,编译,烧写

三者ping通是为了可以传文件. 第0课第5节_刚接触开发板之u-boot打补丁编译使用及建sourceinsight工程: Uboot打补丁:uboot源码是不能在2440用的,打了补丁后可以在2440中使用(在虚拟机里面配置,具体用到ls,cd,tar xjf u-boot-1.1.6等指令),解压出来等等,忘了可以看视频. Source insight工程:操作软件,方便看uboot源码等等,没什么可说的. 编译:cd u-boot-1.1.6 make 100ask_24x0.confi

04.移植u-boot

1.读readme获取信息    1.1 由Building the Software可知,需修改顶层makefile,指定架构和编译器    ifeq ($(HOSTARCH),$(ARCH))    CROSS_COMPILE ?= arm-linux-    endif ARCH = arm    CROSS_COMPILE = arm-linux-2.新建一个单板    cd board/samsung/ cp smdk2410 smdk2440 -rf  cd ../../includ

(十)uboot源码分析

一.九鼎官方uboot和三星原版uboot对比(1)以九鼎官方的uboot为蓝本来学习的,以三星官方的这份为对照.(2)不同版本的uboot或者同一版本不同人移植的uboot,可能目录结构和文件内容都有所不同.将来大家懂了后也可以自己根据需要去添加/删除/更改目录结构.(3)九鼎在以三星的uboot为原材料进行移植时,把三星版本的uboot中很多不必要的文件夹.文件给删除掉了.这个删除把很多完全用不到的文件清除出去,减少了整体的文件数量,便于工作. 二.各文件介绍(1).gitignore.gi

uboot 从sd卡加载文件并烧写到nand flash

uboot下可以从用tftp和nfs加载文件. 但是现在有个开发板配套uboot网络功能出现异常,执行ping命令就会导致开发板重启,只能选择先从sd卡加载文件 启动开发板,任意键进入uboot,然后执行下面的命令扫描sd卡设备: mmc rescan 然后获取sd卡信息: hwgw # fatinfo mmc Interface: MMC Device 0: Vendor: Man 035344 Snr 20d2c703 Rev: 8.0 Prod: SD01G Type: Removable