以 u-boot_sources_for_tp-link_AR9331_by_pepe2k 为蓝本。
将net目录下的Makefile、httpd.c 和 uip-0.9目录复制覆盖到mt7620目录,Makefile可以直接覆盖。
最关键的文件是net.c,需要对照蓝本文件好好进行修改,大致修改的地方有这些:
net.c的前部,加入必须的包含文件和相关变量定义,
#include "httpd.h" #include "uip-0.9/uipopt.h" #include "uip-0.9/uip.h" #include "uip-0.9/uip_arp.h" #if (CONFIG_COMMANDS & CFG_CMD_NET) DECLARE_GLOBAL_DATA_PTR; #define ARP_TIMEOUT 5 /* Seconds before trying ARP again */ #ifndef CONFIG_NET_RETRY_COUNT # define ARP_TIMEOUT_COUNT 5 /* # of timeouts before giving up */ #else # define ARP_TIMEOUT_COUNT (CONFIG_NET_RETRY_COUNT) #endif unsigned char *webfailsafe_data_pointer = NULL; int webfailsafe_is_running = 0; int webfailsafe_ready_for_upgrade = 0; int webfailsafe_upgrade_type = WEBFAILSAFE_UPGRADE_TYPE_FIRMWARE;
此函数不能完全照搬蓝本代码,因为NetLoop初始化网卡的部分不一样,所以,前半部分的代码可以从NetLoop部分复制过来。
但是出现一个奇怪的问题,正常的网卡初始化,应该打印出如下内容:
NetTxPacket = 0x83FE5300 KSEG1ADDR(NetTxPacket) = 0xA3FE5300 NetLoop,call eth_halt ! NetLoop,call eth_init ! Trying Eth0 (10/100-M) Waitting for RX_DMA_BUSY status Start... done ETH_STATE_ACTIVE!!
NetTxPacket = 0x00400000 Packet Buffer is empty !
直接调用NetLoop,发现也是同样的问题,看来调用该方法之前,应该有个初始化的过程。
通过mt7620原有的tftp过程来分析,仔细分析cmd_net.c,发现少掉了一个非常关键的初始化函数!
eth_initialize(gd->bd);
加入之后,终于看到了变化的信息:
NetTxPacket = 0x83FE4F60 KSEG1ADDR(NetTxPacket) = 0xA3FE4F60 NetLoop,call eth_halt ! NetLoop,call eth_init ! Trying Eth0 (10/100-M) Waitting for RX_DMA_BUSY status Start... done ETH_STATE_ACTIVE!! HTTP server is starting at IP: 1.1.168.192 HTTP server is ready!
等等!怎么IP地址是倒过来的?地址192.168.1.1不能联通!!!通过计算机运行arp -a,发现192.168.1.1不在列表
C:\Users\Administrator>arp -a 接口: 192.168.1.100 --- 0xb Internet 地址 物理地址 类型 192.168.1.255 ff-ff-ff-ff-ff-ff 静态 224.0.0.22 01-00-5e-00-00-16 静态 224.0.0.251 01-00-5e-00-00-fb 静态 224.0.0.252 01-00-5e-00-00-fc 静态 239.192.152.143 01-00-5e-40-98-8f 静态
现在要从哪里入手呢?在关键的代码上加上输出语句,用来确定代码的执行顺序。
在net.c文件中,NetReceive 调用了 NetReceiveHttpd
if(webfailsafe_is_running) { NetReceiveHttpd(inpkt, len); return; }
NetReceiveHttpd代码如下:
void NetReceiveHttpd(volatile uchar * inpkt, int len) { memcpy(uip_buf, (const void *) inpkt, len); uip_len = len; #ifdef ET_DEBUG printf("NetReceiveHttpd buf->type = %04X\n", ntohs(BUF->type)); #endif if (BUF->type == htons(UIP_ETHTYPE_IP)) { #ifdef ET_DEBUG printf("buf type is UIP_ETHTYPE_IP\n"); #endif uip_arp_ipin(); uip_input(); if (uip_len > 0) { uip_arp_out(); NetSendHttpd(); } } else if (BUF->type == htons(UIP_ETHTYPE_ARP)) { #ifdef ET_DEBUG printf("buf type is UIP_ETHTYPE_ARP\n"); #endif uip_arp_arpin(); if (uip_len > 0) { NetSendHttpd(); } } }
继续分析uip_arp_ipin()函数(位于uip-0.9目录下的uip_arp.c文件中):
void uip_arp_ipin(void) { uip_len -= sizeof(struct uip_eth_hdr); printf("uip_host_addr = %04X-%04X\n", uip_hostaddr[0],uip_hostaddr[1]); printf("uip_arp_netmask = %04X-%04X\n", uip_arp_netmask[0],uip_arp_netmask[1]); printf("ipbuf scripaddr = %04X-%04X\n", IPBUF->srcipaddr[0],IPBUF->srcipaddr[1]); printf("IPBUF->ethhdr.src = %08X\n", IPBUF->ethhdr.src); /* Only insert/update an entry if the source IP address of the incoming IP packet comes from a host on the local network. */ if((IPBUF->srcipaddr[0] & uip_arp_netmask[0]) != (uip_hostaddr[0] & uip_arp_netmask[0])) { return; } if((IPBUF->srcipaddr[1] & uip_arp_netmask[1]) != (uip_hostaddr[1] & uip_arp_netmask[1])) { return; } uip_arp_update(IPBUF->srcipaddr, &(IPBUF->ethhdr.src)); return; }
buf type is UIP_ETHTYPE_IP uip_host_addr = C0A8-0101 uip_arp_netmask = FFFF-FF00 ipbuf scripaddr = A8C0-6401 IPBUF->ethhdr.src = D3B65A70
注意:uip_host_addr是我们路由器的IP地址:192.168.1.1,正确。
但是,从网络上来的ip显然存在字节序问题,这应该是网络字节序,而代码当中却没有进行转换!
要修改的地方很多,而蓝本代码应该在它自己的目标机上运行正确,难道在某个地方有个统一转换的?功夫不负有心人!在 include\asm\byteorder.h 中,有这样的定义:
#if defined (__MIPSEB__) # include <linux/byteorder/big_endian.h> #elif defined (__MIPSEL__) # include <linux/byteorder/little_endian.h> #else # error "MIPS, but neither __MIPSEB__, nor __MIPSEL__???" #endif
找到网上这个地址:http://www.gaisler.com/doc/net/uip-0.9/doc/html/a00093.html
Detailed Description The CPU architecture configuration is where the endianess of the CPU on which uIP is to be run is specified. Most CPUs today are little endian, and the most notable exception are the Motorolas which are big endian. The BYTE_ORDER macro should be changed to reflect the CPU architecture on which uIP is to be run. Defines #define BYTE_ORDER The byte order of the CPU architecture on which uIP is to be run. Define Documentation #define BYTE_ORDER The byte order of the CPU architecture on which uIP is to be run. This option can be either BIG_ENDIAN (Motorola byte order) or LITTLE_ENDIAN (Intel byte order).
原来uip的字节序是可以自定义的!修改为LITTLE_ENDIAN之后,重新编译,也没有用!
看来还要仔细的思考一番。对比TTL console的诊断输出
ipbuf scripaddr = A8C0-6401
这是网络字节序,故思考所有的host端内容,要转成网络序才行。
思索再三,觉得在NetLoopHttpd中,几处设置网络地址参数的地方有点问题,遂进行了如下修改:
// 修改1,网络字节序要先转成host字节序 IPaddr_t x = ntohl(bd->bi_ip_addr); // start server... char tmp[22]; ip_to_string(bd->bi_ip_addr,tmp); printf("HTTP server is starting at IP : %s\n",tmp); //TftpStart(); HttpdStart(); // set local host ip address,修改2,所有的host字节序,要转成网络字节序,下同 ip[0] = htons(((x & 0xFFFF0000) >> 16)); ip[1] = htons((x & 0x0000FFFF)); uip_sethostaddr(ip); // set network mask (255.255.255.0 -> local network) ip[0] = htons(0xFFFF); //((0xFFFFFF00 & 0xFFFF0000) >> 16); ip[1] = htons(0xFF00); //(0xFFFFFF00 & 0x0000FFFF); uip_setnetmask(ip); // should we also set default router ip address? ip[0] = 0xFFFF; ip[1] = 0xFFFF; uip_setdraddr(ip);
C:\Users\Administrator>arp -a 接口: 192.168.1.100 --- 0xb Internet 地址 物理地址 类型 192.168.1.1 00-00-aa-bb-cc-dd 动态 192.168.1.255 ff-ff-ff-ff-ff-ff 静态 224.0.0.22 01-00-5e-00-00-16 静态 224.0.0.251 01-00-5e-00-00-fb 静态 224.0.0.252 01-00-5e-00-00-fc 静态 239.192.152.143 01-00-5e-40-98-8f 静态
至此,移植工作已经取得了阶段性的胜利!
整个过程,大概耗费了2天的时间。多数时间在这个网络与host字节序上转圈!