浅析uboot网络程序结构

这篇文章主要讲解uboo/net目录下的部分源代码。主要是 net.c,eth.c,ip3912.c 中的代码。本例用的是xxxx公司yyyy系列的zzzzCPU, 网卡是IP173(和IP3912兼容)。

 

本文主要分三部分  网口设备的检测,网口设备的注册,应用程序(ping)的执行流程

(检测网口设备

先从Arch/arm/lib/board.c讲起,uboot执行完汇编程序后,会跳转到该文件中的start_armboot函数。该函数先会为全局变量gd分配空间,并清零。然后执行函数指针数组init_sequence里的各种初始化函数。初始化函数一般都是和具体的开发板相关联的,所以这些函数的源码是在board目录下,本例就是在borad/xxxx/yyyy下。

 

init_sequence数组中有个指针指向board_init,一般可以board_init函数内,初始化CPUIP173相连的引脚,reset网卡后,可以通过读写CPU的相关寄存器向IP173发送读写命令来检测IP173是否正常。

 

例如:IP173寄存器23是芯片ID寄存器(5PHY共用)(见图一),可以通过读写寄存器 23来判断IP173是否存在。

具体检测函数如下:

[objc]  view plain  copy
  1.    
  2. #define CONFIG_IP3912_ETN1_BASE  0xC1600000   //见图二  
  3. #define CONFIG_IP3912_ETN2_BASE  0xC1700000  
  4.    
  5. #define ETN1_BASE    CONFIG_IP3912_ETN1_BASE  
  6. #define ETN2_BASE    CONFIG_IP3912_ETN2_BASE  
  7.    
  8. #define ETN_MAC1     0x0000  
  9. #define ETN_MAC2     0x0004  
  10. #define ETN_IPGT         0x0008  
  11. #define ETN_IPGR         0x000c  
  12. #define ETN_CLRT     0x0010  
  13. #define ETN_MAXF     0x0014  
  14. #define ETN_SUPP     0x0018  
  15. #define ETN_TEST     0x001c  
  16. #define ETN_MCFG     0x0020  
  17. #define ETN_MCMD     0x0024  
  18. #define ETN_MADR     0x0028  
  19.    
  20.    
  21. #define VEGA_IP173_PHY_ADDR  0x01  
  22. #define ICPLUS_IP173T_PHYID1     0x02  
  23. #define ICPLUS_IP173T_PHYID2     0x03  
  24. #define ICPLUS_OUI_MASK  0x0000ffff  
  25. #define ICPLUS_OUI   0x90c3  
  26.    
  27. int board_init(void)  
  28. {  
  29.     ...  
  30.     board_detect();  
  31.     ...  
  32. }  
  33. void board_detect(void)  
  34. {  
  35.     init_etn0();  
  36.     detect_IC_PLUS_173T(VEGA_IP173_PHY_ADDR);  
  37. }  
  38.    
  39. static int detect_IC_PLUS_173T(int addr)  
  40. {  
  41.     u32 phyid = 0;  
  42.     u16 reg = 0;  
  43.    
  44.     clear_gpioc(28); //IP173 reset引脚  
  45.     udelay(12000);  
  46.     udelay(12000);  
  47.     udelay(12000);  
  48.    
  49.     set_gpioc(28);  //IP173 reset引脚  
  50.     udelay(1000);  
  51.     udelay(1000);  
  52.     udelay(1000);  
  53.    
  54.     reg = detect_phy_read(addr,ICPLUS_IP173T_PHYID1); // 读ID1寄存器  
  55.     phyid = (u32)reg << 6;  
  56.     reg = detect_phy_read(addr, ICPLUS_IP173T_PHYID2); // 读ID2寄存器  
  57.     phyid |= ((u32)reg)>>10;  
  58.     phyid &= ICPLUS_OUI_MASK;  
  59.     /* IC+ IP173T */  
  60.     printf("phyid = 0x%x\n",phyid );  
  61.     if (phyid == ICPLUS_OUI)  
  62.         return 1;  
  63.     return 0;  
  64. }  
  65. static void detect_phy_wait(void)  
  66. {  
  67.         int i, status;  
  68.         for (i = 0; i < 1000; i++) {  
  69.         status = readl((voidvoid *)(ETN1_BASE + ETN_MIND)) & 0x7//  
  70.         if (!status)  
  71.             return;  
  72.         udelay(1);  
  73.     }  
  74. }  
  75.    
  76. static u16 detect_phy_read(u8 address, u8 reg)  
  77. {  
  78.     u16 value;  
  79.     writel((address << 8) | reg, (voidvoid *)(ETN1_BASE + ETN_MADR)); //PHY地址右移或上  
  80.                                                             //reg地址  
  81.     writel(0x00000001, (voidvoid *)(ETN1_BASE + ETN_MCMD));  
  82.     detect_phy_wait();  
  83.    
  84.     value = readl((voidvoid *)(ETN1_BASE + ETN_MRDD));  
  85.     writel(0x00000000, (voidvoid *)(ETN1_BASE + ETN_MCMD));  
  86.     return value;  
  87. }  
  88.  int detect_phy_write(u8 address, u8 reg,int value)  
  89. {  
  90.     writel(address << 8 | reg,(voidvoid *)(ETN1_BASE + ETN_MADR));  
  91.     __raw_writel(value, (voidvoid *)(ETN1_BASE + ETN_MWTD));  
  92.     detect_phy_wait();  
  93. }  

解释

 init_etn0();主要工作是初始化CPU Ethernet Mac模块,GPIO口等等.

 detect_IC_PLUS_173T检测IP173,成功返回1,反之返回0.

 读寄存器流程:

    将PHY地址右移或上地址写入地址寄存器(见图三),因为zzzz有两种读,循环读和单次读,所以需要写1到命令寄存器。等待读完成。从读寄存器读出值。

 写寄存器流程:

    将PHY地址右移或上地址写入地址寄存器,将要写的值写入写寄存器。等待写完成。

 

                                                          图(一)

  

                                     图(二) CPU Ethernet Mac 模块的寄存器(部分)

  

 

      

                                                                           图(三)

    

(向网口设备虚拟层eth_device注册各类操作函数和数据。

检测到IP173之后,start_armboot会继续完成其他初始化工作,如FLASHSDRAM,串口、中断、环境变量等等,期间会设置IP地址

gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");

然后调用eth_initialize()函数。之后等待用户输入命令或者启动kernel 

 

eth_initialize()大致流程是调用具体的网卡驱动程序(ip3912_send,ip3912_recv)来初始化网口设备虚拟层的框架(eth_device->send,eth_device->recv),这些程序为应用程序如pingtftpboot提供服务(如PingSendTftpSend等)

 

 

eth_initialize()位于net/eth.c文件内,eth.c就是网口设备虚拟层的源码,其提供eth_initializeeth_registereth_get_deveth_initeth_halteth_sendeth_rxeth_receiveeth_try_another

eth_set_current等函数。

 

eth.c文件被#ifdef CONFIG_NET_MULTI分成两部分,关于CONFIG_NET_MULTI的含义参考附录一。

eth.c的主要数据结构如下:

[objc]  view plain  copy
  1. struct eth_device {  
  2.     char name[NAMESIZE]; //设备名  
  3.     unsigned char enetaddr[6];  // mac 地址  
  4.     int iobase;  
  5.     int state;   
  6.     int  (*init) (struct eth_device*, bd_t*);  
  7.     int  (*send) (struct eth_device*, volatile void* packet, int length);  
  8.     int  (*recv) (struct eth_device*);  
  9.     void (*halt) (struct eth_device*);  
  10.     #ifdef CONFIG_MCAST_TFTP  
  11.         int (*mcast) (struct eth_device*, u32 ip, u8 set);  
  12.     #endif  
  13.     int  (*write_hwaddr) (struct eth_device*);  //设置MAC的函数  
  14.     struct eth_device *next; // 指向下一个网口设备  
  15.     voidvoid *priv;  
  16. };  


当要支持多播TFTP时,必须开启CONFIG_MCAST_TFTP,并定义mcast()函数(见readme)。 

下面来具体看下 eth_initialize函数

[objc]  view plain  copy
  1. int eth_initialize(bd_t *bis)  
  2. {  
  3.     unsigned char env_enetaddr[6];  
  4.     int eth_number = 0;  
  5.    
  6.     eth_devices = NULL;  
  7.     eth_current = NULL;  //注释1  
  8.    
  9.     show_boot_progress (64);  
  10.       
  11.     miiphy_init(); //注释2  
  12.    
  13.     //设置 eth_devices =eth_current = netdev, netdev含有IP3912的 init,send ,recv ,priv等    
  14.     //信息,也会设置 mii_devs和 current_mii   
  15.     if (board_eth_init(bis) < 0)  //注释3   
  16.         cpu_eth_init(bis);  
  17.     if (!eth_devices) {  
  18.         puts ("No ethernet found.\n");  
  19.         show_boot_progress (-64);  
  20.     } else {  
  21.         struct eth_device *dev = eth_devices;  
  22.         charchar *ethprime = getenv ("ethprime");   
  23.         show_boot_progress (65);  
  24.     do {   
  25.          // 比较dev->enetaddr中MAC地址和environment中的MAC地址是否一致,  
  26.          // 不一致则调用dev->write_hwaddr 函数来修改MAC地址,以environment中的    
  27.          // 为准,如果dev->write_hwaddr 为空,或者设置了环境变量ethmacskip就会跳   
  28.          //过该步骤。如果有多个网口设备,会循环执行上述步骤。  
  29.          if (eth_number)  
  30.              puts (", ");  
  31.          printf("%s", dev->name);  
  32.          if (ethprime && strcmp (dev->name, ethprime) == 0) {  
  33.             eth_current = dev;  
  34.             puts (" [PRIME]");  
  35.         }  
  36.         if (strchr(dev->name, ' '))  
  37.             puts("\nWarning: eth device name has a space!\n");  
  38.    
  39.         eth_getenv_enetaddr_by_index(eth_number, env_enetaddr);  
  40.    
  41.         if (memcmp(env_enetaddr, "\0\0\0\0\0\0"6)) {  
  42.             if (memcmp(dev->enetaddr, "\0\0\0\0\0\0"6) &&  
  43.                memcmp(dev->enetaddr, env_enetaddr, 6))  
  44.             {  
  45.                 printf ("\nWarning: %s MAC addresses don't match:\n",dev->name);  
  46.                 printf ("Address in SROM is         %pM\n",dev->enetaddr);  
  47.                 printf ("Address in environment is  %pM\n",env_enetaddr);  
  48.             }  
  49.             memcpy(dev->enetaddr, env_enetaddr, 6);  
  50.         }  
  51.         if (dev->write_hwaddr &&  
  52.             !eth_mac_skip(eth_number) &&  
  53.             is_valid_ether_addr(dev->enetaddr)) {  
  54.                  dev->write_hwaddr(dev);  
  55.         }  
  56.         eth_number++;  
  57.         dev = dev->next;  
  58.     } while(dev != eth_devices);  
  59.     /* update current ethernet name */  
  60.     if (eth_current) {  
  61.         charchar *act = getenv("ethact");  
  62.         if (act == NULL || strcmp(act, eth_current->name) != 0)  
  63.             setenv("ethact", eth_current->name);  
  64.         } else  
  65.             setenv("ethact"NULL);  
  66.          putc ('\n');  
  67.     }  
  68.     return eth_number;  
  69. }  


执行完该函数后,eth_current指向正在使用的eth_device,该结构体里有init,send,recv 等函数以及MAC地址enetaddr,状态state,设备名name等等。如果有多个网口设备,则他们的eth_device会依次存放在eth_device->next所指向的链表里。

 

浏览IP3912.c会发现若要编写网口的驱动程序,需要编写ip3912_eth_initialize初始化函数,用来向网口设备虚拟层注册,编写ip3912_haltip3912_recvip3912_sendip3912_init

网口设备虚拟层eth_device所需要的函数。若需要注册MII设备,则还需要编写ip3912_miiphy_write ip3912_miiphy_read等函数。

 

 

注释1

eth_current比较重要,因为tftpsend等函数最终会调用该变量指向的eth_device中的函数。

[objc]  view plain  copy
  1. int eth_send(volatile voidvoid *packet, int length)  
  2. {  
  3.     if (!eth_current)  
  4.         return -1;  
  5.     return eth_current->send(eth_current, packet, length);  
  6. }  


注释2

[objc]  view plain  copy
  1. void miiphy_init(void)  
  2. {  
  3.     INIT_LIST_HEAD (&mii_devs);  
  4.     current_mii = NULL;  
  5. }  
  6. struct mii_dev {  
  7.     struct list_head link;  
  8.     const charchar *name;  
  9.     int (*read) (const charchar *devname, unsigned char addr,unsigned char reg, unsigned shortshort *value);  
  10.     int (*write) (const charchar *devname, unsigned char addr,  
  11. };  

IP3912 属于 PHY 层,其驱动程序会调用 miiphy_register  注册一个 mii_dev

注释3

board_eth_init() 是属于具体开发板范畴,本例位于board/dspg/firetux/firetux.c内,

主要工作是调用板子所用网口芯片(IP3912)的初始化函数。

[objc]  view plain  copy
  1. int board_eth_init(bd_t *bis)  
  2. {  
  3.     ...  
  4.     ip3912_miiphy_initialize(gd->bd);  
  5.     ...  
  6.     ip3912_eth_initialize(0,CONFIG_IP3912_ETN1_BASE,CONFIG_IP3912_ETN1_BASE, 0x01);  
  7.     ...  
  8.     setenv("ethact""ETN1");  
  9.     eth_set_current(); //一般会在ip3912_eth_initialize这些具体设备的初始化函数中调用。  
  10. }  

int ip3912_miiphy_initialize(bd_t *bis)

[objc]  view plain  copy
  1. {  
  2.     miiphy_register("ip3912", ip3912_miiphy_read, ip3912_miiphy_write);  
  3.     return 0;  
  4. }  

[objc]  view plain  copy
  1. void miiphy_register(const charchar *name,  
  2.       int (*read) (const charchar *devname, unsigned char addr,  
  3.    unsigned char reg, unsigned shortshort *value),  
  4.       int (*write) (const charchar *devname, unsigned char addr,  
  5.     unsigned char reg, unsigned short value))  
  6. {  
  7.     ...  
  8.     //检查是否已经注册了一个同名的mii设备  
  9.     new_dev = miiphy_get_dev_by_name(name, 1);  
  10.     // 是则直接退出  
  11.     if (new_dev) {   
  12.         printf("miiphy_register: non unique device name '%s'\n", name);  
  13.         return;  
  14.     }  
  15.     // 反之,分配一个新的MII设备  
  16.     name_len = strlen (name);  
  17.     new_dev =  (struct mii_dev *)malloc (sizeof (struct mii_dev) + name_len + 1);  
  18.     //随后初始化这个新的MII设备, 如read ,write函数  
  19.     memset (new_dev, 0sizeof (struct mii_dev) + name_len);  
  20.    
  21.     /* initalize mii_dev struct fields */  
  22.     INIT_LIST_HEAD (&new_dev->link);  
  23.     new_dev->read = read;  
  24.     new_dev->write = write;  
  25.     new_dev->name = new_name = (charchar *)(new_dev + 1);  
  26.     strncpy (new_name, name, name_len);  
  27.     new_name[name_len] = '\0';  
  28.     // 将新的MII设备 添加到 mii_devs 列表中,并设置current_mii   
  29.     // mii_devs 和current_mii 在eth_initialize()中初始化  
  30.     list_add_tail (&new_dev->link, &mii_devs);  
  31.     if (!current_mii)  
  32.     current_mii = new_dev;  
  33. }  

接着分析函数 ip3912_eth_initialize (),其主要数据结构是

[objc]  view plain  copy
  1. struct ip3912_device {  
  2.     unsigned int     etn_base;  
  3.     unsigned int     phy_base;  
  4.     unsigned char    nr;  
  5.     unsigned char    phy_addr;  
  6.     unsigned char    autonegotiate;  
  7.     unsigned char    speed;  
  8.     unsigned char    duplex;  
  9.     unsigned char    rmii;  
  10.    
  11.     const struct device *  dev;  
  12.     struct eth_device *    netdev;  
  13. };  


可以看到ip3912_device包含了基本的eth_device结构。

 

[objc]  view plain  copy
  1. int ip3912_eth_initialize(unsigned char nr, unsigned int etn_base, unsigned int phy_base, unsigned char phy_addr, unsigned char rmii)  
  2. {  
  3.     struct ip3912_device *ip3912;   
  4.     struct eth_device *netdev;  
  5.    
  6.     // 分配 eth_device 和 ip3912_device设备所需内存,并初始化。  
  7.     netdev = malloc(sizeof(struct eth_device));  
  8.     ip3912 = malloc(sizeof(struct ip3912_device));  
  9.     if ((!ip3912) || (!netdev)) {  
  10.         printf("Error: Failed to allocate memory for ETN%d\n", nr + 1);  
  11.         return -1;  
  12.     }  
  13.    
  14.     memset(ip39120sizeof(struct ip3912_device));  
  15.     memset(netdev, 0sizeof(struct eth_device));  
  16.    
  17.     //初始化具体网口设备的私有数据  
  18.     ip3912->nr = nr;  
  19.     ip3912->etn_base = etn_base;  
  20.     ip3912->phy_base = phy_base;  
  21.     ip3912->phy_addr = phy_addr;  
  22.     ip3912->autonegotiate = 0;  
  23.     ip3912->rmii = rmii;  
  24.     ip3912->speed = 0;  
  25.     ip3912->duplex = 0;  
  26.     ip3912->netdev = netdev;  
  27.    
  28.     // 用具体网口设备IP3912的操作函数来初始化网口设备虚拟层netdev,  
  29.     // 注意最后一项  
  30.     sprintf(netdev->name, "ETN%d", nr + 1);  
  31.     netdev->init = ip3912_init;  
  32.     netdev->send = ip3912_send;  
  33.     netdev->recv = ip3912_recv;  
  34.     netdev->halt = ip3912_halt;  
  35.     netdev->priv = (voidvoid *)ip3912;   
  36.    
  37.     //将eth_current 设置为新的netdev,并设置“ethact”,并设置状态state = ETH_STATE_INIT  
  38.     eth_register(netdev); // 注释3.1   
  39.     eth_set_current();  
  40.     ip3912_macreset(); // 初始化CPU Ethernet Mac模块   
  41.     /* we have to set the mac address, because we have no SROM */  
  42.     //读取环境变量,设置MAC地址  
  43.     ip3912_setmac(netdev); // 注释3.2    
  44.     return 0;  
  45. }  


注释3.1

[objc]  view plain  copy
  1. int eth_register(struct eth_device* dev)  
  2. {  
  3.     struct eth_device *d;  
  4.    
  5.     if (!eth_devices) {  
  6.         eth_current = eth_devices = dev;  
  7.         {  
  8.         charchar *act = getenv("ethact");  
  9.         if (act == NULL || strcmp(act, eth_current->name) != 0)  
  10.         setenv("ethact", eth_current->name);  
  11.         }  
  12.     } else {  
  13.         for (d=eth_devices; d->next!=eth_devices; d=d->next)  
  14.         ;  
  15.         d->next = dev;  
  16.     }  
  17.    
  18.     dev->state = ETH_STATE_INIT;  
  19.     dev->next  = eth_devices;  
  20.     return 0;  
  21. }  

注释3.2

[objc]  view plain  copy
  1. void ip3912_setmac(struct eth_device *netdev)  
  2. {  
  3.     struct ip3912_device *ip3912;  
  4.     unsigned char i, use_etn1addr = 0;  
  5.     charchar *mac_string, *pmac, *end;  
  6.     char tmp[18];  
  7.    
  8.     ip3912 = netdev->priv;  
  9.    
  10.     mac_string = getenv("ethaddr");  
  11.     if (ip3912->nr) {  
  12.         /* we use ETN2 */  
  13.         mac_string = getenv("eth1addr");  
  14.         if (!mac_string) {  
  15.             mac_string = getenv("ethaddr");  
  16.             use_etn1addr = 1;  
  17.         }  
  18.     }  
  19.     pmac = mac_string;  
  20.     for (i = 0; i < 6; i++) {  
  21.         netdev->enetaddr[i] = pmac ? simple_strtoul(pmac, &end, 16) : 0;  
  22.         if (pmac)  
  23.             pmac = (*end) ? end + 1 : end;  
  24.     }  
  25.    
  26.     if (use_etn1addr) {  
  27.         /* flip last bit of mac address */  
  28.         debug("ip3912_setmac %s flipping last bit\n", netdev->name);  
  29.         if (netdev->enetaddr[5] & 1)  
  30.             netdev->enetaddr[5] &= 0xfe;  
  31.         else  
  32.             netdev->enetaddr[5] |= 0x01;  
  33.             sprintf(tmp, "%02X:%02X:%02X:%02X:%02X:%02X",  
  34.             netdev->enetaddr[0], netdev->enetaddr[1],  
  35.             netdev->enetaddr[2], netdev->enetaddr[3],  
  36.             netdev->enetaddr[4], netdev->enetaddr[5]);  
  37.             setenv("eth1addr", tmp);  
  38.             mac_string = tmp;  
  39.     }  
  40.     debug("ip3912_setmac set %s to address %s\n", netdev->name, mac_string);  
  41.    
  42.     writel((netdev->enetaddr[5] << 8) | netdev->enetaddr[4],  
  43.         (voidvoid *)(ip3912->etn_base + ETN_SA0));  
  44.     writel((netdev->enetaddr[3] << 8) | netdev->enetaddr[2],  
  45.         (voidvoid *)(ip3912->etn_base + ETN_SA1));  
  46.     writel((netdev->enetaddr[1] << 8) | netdev->enetaddr[0],  
  47.         (voidvoid *)(ip3912->etn_base + ETN_SA2));  
  48. }  

 

 

(三)应用层执行流程分析

Uboot支持的网络协议有以下几种

typedef enum 

{ BOOTP, RARP, ARP, TFTP, DHCP, PING, DNS, NFS, CDP, NETCONS, SNTP } proto_t;

 

 

先看下比较简单的ping

[objc]  view plain  copy
  1. U_BOOT_CMD(  
  2.     ping,   2,  1,  do_ping,  
  3.     "send ICMP ECHO_REQUEST to network host",  
  4.     "pingAddress"  
  5. );  

[objc]  view plain  copy
  1. int do_ping (cmd_tbl_t *cmdtp, int flag, int argc, charchar * const argv[])  
  2. {  
  3.     if (argc < 2)  
  4.         return -1;  
  5.     NetPingIP = string_to_ip(argv[1]);  
  6.     if (NetPingIP == 0)  
  7.         return cmd_usage(cmdtp);  
  8.     if (NetLoop(PING) < 0) {  
  9.         printf("ping failed; host %s is not alive\n", argv[1]);  
  10.         return 1;  
  11.     }  
  12.     printf("host %s is alive\n", argv[1]);  
  13. return 0;  
  14. }  


NetLoop像是一个应用层和网口设备虚拟层之间的一个接口,很多协议的处理都要经过该函数,如do_ping()函数中的NetLoop(PING)do_cdp()函数中的NetLoop(CDP), do_sntp()函数中的NetLoop(SNTP),.do_dns()函数中的NetLoop(DNS)。另外do_bootp() 会调用 netboot_common (BOOTP, cmdtp, argc, argv); do_tftpb() 会调用 netboot_common (TFTP, cmdtp, argc, argv);do_rarpb() 会调用netboot_common (RARP, cmdtp, argc, argv);do_dhcp()会调用netboot_common(DHCP, cmdtp, argc, argv);do_nfs ()会调用 netboot_common(NFS, cmdtp, argc, argv);netboot_common( (proto_t proto ,.....)仍会调用 NetLoop(proto)

 

do_ping()函数从命令行读取IP地址后,存放在NetPingIP中。

接着执行NetLoop(PING)函数

 

下面分析int NetLoop(proto_t protocol)函数。

 

[objc]  view plain  copy
  1. #ifdef CONFIG_SYS_RX_ETH_BUFFER  
  2. # define PKTBUFSRX  CONFIG_SYS_RX_ETH_BUFFER  
  3. #else  
  4. # define PKTBUFSRX  4  
  5. #endif  
  6. #define PKTALIGN    32  
  7. #define PKTSIZE  1518  
  8. #define PKTSIZE_ALIGN    1536  
  9.    
  10. //静态分配一个buffer  
  11. volatile uchar  PktBuf[(PKTBUFSRX+1) * PKTSIZE_ALIGN + PKTALIGN];  
  12.    
  13. volatile uchar *NetRxPackets[PKTBUFSRX]; /* Receive packets  */  
  14.    
  15. volatile uchar *NetTxPacket = 0;    /* THE transmit packet   */  
  16.    
  17.    
  18.    
  19. Int NetLoop(proto_t protocol)  
  20. {  
  21.     bd_t *bd = gd->bd;  
  22.    
  23. <pre code_snippet_id="270100" snippet_file_name="blog_20140402_15_3725530" name="code" class="objc"><span style="font-family: Arial, Helvetica, sans-serif;">    #ifdef CONFIG_NET_MULTI</span></pre> NetRestarted = 0; NetDevExists = 0; #endif /* XXX problem with bss workaround */ NetArpWaitPacketMAC = NULL; NetArpWaitTxPacket = NULL; NetArpWaitPacketIP = 0; NetArpWaitReplyIP = 0; NetArpWaitTxPacket = NULL; NetTxPacket = NULL; NetTryCount  
  24.  = 1// 初始化各类发送,接收buffer指针。 if (!NetTxPacket) { int i; /* * Setup packet buffers, aligned correctly. */ NetTxPacket = &PktBuf[0] + (PKTALIGN - 1); NetTxPacket -= (ulong)NetTxPacket % PKTALIGN; for (i = 0; i < PKTBUFSRX; i++) { NetRxPackets[i] = NetTxPacket  
  25.  + (i+1)*PKTSIZE_ALIGN; } } if (!NetArpWaitTxPacket) { NetArpWaitTxPacket = &NetArpWaitPacketBuf[0] + (PKTALIGN - 1); NetArpWaitTxPacket -= (ulong)NetArpWaitTxPacket % PKTALIGN; NetArpWaitTxPacketSize = 0; } eth_halt(); //注释1 #ifdef CONFIG_NET_MULTI eth_set_current();  
  26.  //设置环境变量"ethact"。如果已经设置,就直接退出。 #endif if (eth_init(bd) < 0) { //注释2 eth_halt(); return(-1); } restart: #ifdef CONFIG_NET_MULTI memcpy (NetOurEther, eth_get_dev()->enetaddr, 6); // 设置 NetOurEther #else eth_getenv_enetaddr("ethaddr", NetOurEther); #endif NetState  
  27.  = NETLOOP_CONTINUE; // 设置 NetOurEther /* * Start the ball rolling with the given start function. From * here on, this code is a state machine driven by received * packets and timer events. */ // 设置 NetOurIP NetOurGatewayIP NetOurSubnetMask NetServerIP NetOurNativeVLAN  
  28.  // NetOurVLAN NetOurDNSIP NetInitLoop(protocol); switch (net_check_prereq (protocol)) { // 检查所需要的参数是否都有合适的值 case 1: /* network not configured */ eth_halt(); return (-1); #ifdef CONFIG_NET_MULTI case 2: /* network device not configured */ break; #endif /* CONFIG_NET_MULTI  
  29.  */ case 0: #ifdef CONFIG_NET_MULTI NetDevExists = 1; #endif switch (protocol) { case TFTP/* always use ARP to get server ethernet address */ TftpStart(); break; #if defined(CONFIG_CMD_DHCP) case DHCP: BootpTry = 0; NetOurIP = 0; DhcpRequest(); /* Basically 
  30.  same as BOOTP */ break; #endif case BOOTP: BootpTry = 0; NetOurIP = 0; BootpRequest (); breakcase RARP: RarpTry = 0; NetOurIP = 0; RarpRequest (); break; #if defined(CONFIG_CMD_PING) case PING// 注释3,执行ping 的实质函数。会发送ECHO REQUEST 数据包,并设置接收数据包时的处理函数和超时函数。  
  31.  PingStart(); break; #endif #if defined(CONFIG_CMD_NFS) case NFS: NfsStart(); break; #endif #if defined(CONFIG_CMD_CDP) case CDP: CDPStart(); break; #endif #ifdef CONFIG_NETCONSOLE case NETCONS: NcStart(); break; #endif #if defined(CONFIG_CMD_SNTP) case SNTP:  
  32.  SntpStart(); break; #endif #if defined(CONFIG_CMD_DNS) case DNS: DnsStart(); break; #endif defaultbreak; } NetBootFileXferSize = 0break; } /* * Main packet reception loop. Loop receiving packets until * someone sets `NetState' to a state that terminates. 
  33.  */ for (;;) { WATCHDOG_RESET();/* * Check the ethernet for a new packet. The ethernet * receive routine will process it. */ eth_rx(); // 循环接受数据包,注释4/* * Abort if ctrl-c was pressed. */ if (ctrlc()) { eth_halt(); puts ("\nAbort\n"); return (-1); } ArpTimeoutCheck();  
  34.  /* * Check for a timeout, and run the timeout handler * if we have one. */ if (timeHandler && ((get_timer(0) - timeStart) > timeDelta)) { thand_f *x; x = timeHandler; timeHandler = (thand_f *)0; (*x)(); } switch (NetState) { case NETLOOP_RESTART: #ifdef CONFIG_NET_MULTI  
  35.  NetRestarted = 1; #endif goto restart; case NETLOOP_SUCCESS//若有接收文件,则打印文件大小,并设置环境变量filesize,fileaddr if (NetBootFileXferSize > 0) { char buf[20]; printf("Bytes transferred = %ld (%lx hex)\n", NetBootFileXferSize, NetBootFileXferSize); sprintf(buf, "%lX",  
  36.  NetBootFileXferSize); setenv("filesize", buf); sprintf(buf, "%lX", (unsigned long)load_addr); setenv("fileaddr", buf); } eth_halt(); return NetBootFileXferSize; case NETLOOP_FAILreturn (-1); } }}<p></p>  
  37. <pre></pre>  
  38. <br>  
  39. <br>  
  40. <p></p>  
  41. <p>注释<span style="font-family:'Times New Roman'">1</span></p>  
  42. <p></p><pre code_snippet_id="270100" snippet_file_name="blog_20140402_16_8643763" name="code" class="objc">void eth_halt(void)  
  43. {  
  44.     if (!eth_current)  
  45.         return;  
  46.     eth_current->halt(eth_current);  
  47.     eth_current->state = ETH_STATE_PASSIVE;  
  48. }</pre><br>  
  49. <p></p>  
  50. <p>调用网口设备虚拟层的<span style="font-family:Times New Roman">halt</span><span style="font-family:宋体">函数,该函数实际是具体网口设备</span><span style="font-family:Times New Roman">IP3912</span><span style="font-family:宋体">的</span><span style="font-family:Times New Roman">halt</span><span style="font-family:宋体">函数,</span></p>  
  51. <p></p><pre code_snippet_id="270100" snippet_file_name="blog_20140402_17_738098" name="code" class="objc">static void ip3912_halt(struct eth_device *netdev)  
  52. {  
  53.     struct ip3912_device *ip3912 = netdev->priv;  
  54.    
  55. /* disable rx-path, tx-path, host registers reset 
  56.  * set FullDuplex, enable RMMI, disable rx+tx 
  57.  * no flow control, no frames<64b 
  58.  */  
  59.     writel(0x000006b8, (voidvoid *)(ip3912->etn_base + ETN_COMMAND));  
  60. }</pre><br>  
  61.  注释<span style="font-family:'Times New Roman'">2</span><p></p>  
  62. <p>同理,<span style="font-family:Times New Roman">eth_init()</span><span style="font-family:宋体">会调用 </span><span style="font-family:Times New Roman">ip3912_init</span><span style="font-family:宋体">。 </span><span style="font-family:Times New Roman">ip3912_init</span><span style="font-family:宋体">主要完成数据包发送和接受之前的初始化工作,要参考</span><span style="font-family:Times New Roman">CPU</span><span style="font-family:宋体">数据手册中</span><span style="font-family:Times New Roman">Ethernet Mac</span><span style="font-family:宋体">模块如何收发数据包的文档。其中,</span><span style="font-family:Times New Roman">ip3912_init_descriptors() </span><span style="font-family:宋体">和 </span><span style="font-family:Times New Roman">ip3912_mii_negotiate_phy()</span><span style="font-family:宋体">比较重要。</span></p>  
  63. <p>注释<span style="font-family:Times New Roman">2</span><span style="font-family:宋体">、注释</span><span style="font-family:Times New Roman">3.3</span><span style="font-family:宋体">和注释</span><span style="font-family:Times New Roman">4</span><span style="font-family:宋体">的一部分 都是和具体网口设备相关的,可以先不看</span><span style="font-family:Times New Roman">,</span><span style="font-family:宋体">先把注意力放在上层程序</span><span style="font-family:Times New Roman">Netloop</span><span style="font-family:宋体">的执行流程和框架上。</span></p>  
  64. <p></p><pre code_snippet_id="270100" snippet_file_name="blog_20140402_18_4194852" name="code" class="objc">int eth_init(bd_t *bis)  
  65. {  
  66.     ...  
  67.     eth_current->init(eth_current,bis)  
  68.     ...   
  69. }</pre><br>  
  70. <br>  
  71. <p></p>  
  72. <p></p><pre code_snippet_id="270100" snippet_file_name="blog_20140402_19_2352472" name="code" class="objc">static int ip3912_init(struct eth_device *netdev, bd_t *bd)  
  73. {  
  74.     struct ip3912_device *ip3912 = netdev->priv;  
  75.    
  76.     /* update mac address in boardinfo */  
  77.     ip3912_setmac(netdev);  
  78.    
  79.     /* before enabling the rx-path we need to set up rx-descriptors */  
  80.     if (ip3912_init_descriptors(netdev))  
  81.         return -1;  
  82.    
  83.     /* set max packet length to 1536 bytes */  
  84.     writel(MAX_ETH_FRAME_SIZE, (voidvoid *)(ip3912->etn_base + ETN_MAXF));  
  85.     /* full duplex */  
  86.     writel(0x00000023, (voidvoid *)(ip3912->etn_base + ETN_MAC2));  
  87.     /* inter packet gap register */  
  88.     writel(0x15, (voidvoid *)(ip3912->etn_base + ETN_IPGT));  
  89.     writel(0x12, (voidvoid *)(ip3912->etn_base + ETN_IPGR));  
  90.     /* enable rx, receive all frames */  
  91.     writel(0x00000003, (voidvoid *)(ip3912->etn_base + ETN_MAC1));  
  92.     /* accept all multicast, broadcast and station packets */  
  93.     writel(0x00000026, (voidvoid *)(ip3912->etn_base + ETN_RXFILTERCTRL));  
  94.    
  95.     if (!l2_switch_present()) {  
  96.         /* reset MII mgmt, set MII clock */  
  97.         writel(0x0000801c, (voidvoid *)(ip3912->etn_base + ETN_MCFG));  
  98.         writel(0x0000001c, (voidvoid *)(ip3912->etn_base + ETN_MCFG));  
  99.     }  
  100.    /* release rx-path, tx-path, host registers reset 
  101.     * set FullDuplex, enable RMMI, enable rx+tx 
  102.     * no flow control, no frames<64b 
  103.     */  
  104.     writel(0x00000683, (voidvoid *)(ip3912->etn_base + ETN_COMMAND));  
  105.     ip3912_init_descriptors(netdev);  
  106.    
  107.     #ifdef CONFIG_DISCOVER_PHY  
  108.     mii_discover_phy();  
  109.     #endif  
  110.    
  111.     if (!l2_switch_present())            
  112.         /* init phy */  
  113.         mii_init_phy(ip3912->phy_addr);  
  114.     /* check autonegotiation */  
  115.     ip3912_i2cl2switch_negotiate_phy();  
  116.    
  117.     #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)  
  118.     /* check autonegotiation */  
  119.     if (!l2_switch_present())                   
  120.         ip3912_mii_negotiate_phy();  // 用于协商传输速率  
  121.     #endif  
  122.    
  123.     return 0;  
  124. }  
  125. static int ip3912_init_descriptors(struct eth_device *netdev)  
  126. {  
  127.     struct ip3912_device *ip3912;  
  128.     static voidvoid *rxbuf;  
  129.     int i;  
  130.    
  131.     ip3912 = netdev->priv;  
  132.    
  133.     /* fill in pointer in regs */  
  134.     writel((unsigned long)etn_rxdescriptor, (voidvoid *)(ip3912->etn_base + ETN_RXDESCRIPTOR));  
  135.     writel((unsigned long)etn_rxstatus, (voidvoid *)(ip3912->etn_base + ETN_RXSTATUS));  
  136.     writel(0x00000000, (voidvoid *)(ip3912->etn_base + ETN_RXCONSUMEINDEX));  
  137.     writel(CONFIG_SYS_ETN_RX_DESCRIPTOR_NUMBER - 1,(voidvoid *)(ip3912->etn_base + ETN_RXDESCRIPTORNUMBER));  
  138.    
  139.     writel((unsigned long)etn_txdescriptor, (voidvoid *)(ip3912->etn_base + ETN_TXDESCRIPTOR));  
  140.     writel((unsigned long)etn_txstatus, (voidvoid *)(ip3912->etn_base + ETN_TXSTATUS));  
  141.     writel(0x00000000, (voidvoid *)(ip3912->etn_base + ETN_TXPRODUCEINDEX));  
  142.     writel(CONFIG_SYS_ETN_TX_DESCRIPTOR_NUMBER - 1,(voidvoid *)(ip3912->etn_base + ETN_TXDESCRIPTORNUMBER));  
  143.    
  144.     /* allocate rx-buffers, but only once, we're called multiple times! */  
  145.     if (!rxbuf)  
  146.        rxbuf = malloc(MAX_ETH_FRAME_SIZE * CONFIG_SYS_ETN_RX_DESCRIPTOR_NUMBER);  
  147.     if (!rxbuf) {  
  148.        puts("ERROR: couldn't allocate rx buffers!\n");  
  149.        return -1;  
  150.     }  
  151.    
  152.     for (i = 0; i < CONFIG_SYS_ETN_RX_DESCRIPTOR_NUMBER; i++) {  
  153.         etn_rxdescriptor[i].packet = rxbuf + i * MAX_ETH_FRAME_SIZE;  
  154.         etn_rxdescriptor[i].control = MAX_ETH_FRAME_SIZE - sizeof(unsigned long);  
  155.         etn_rxstatus[i].info = 0;  
  156.         etn_rxstatus[i].hashCRC = 0;  
  157.     }  
  158.     for (i = 0; i < CONFIG_SYS_ETN_TX_DESCRIPTOR_NUMBER; i++) {  
  159.         etn_txdescriptor[i].packet = 0;  
  160.         etn_txdescriptor[i].control = 0;  
  161.         etn_txstatus[i].info = 0;  
  162.    }  
  163.    return 0;  
  164. }</pre><br>  
  165. <br>  
  166. <p></p>  
  167. <p> </p>  
  168. <p>注释<span style="font-family:Times New Roman">3 </span></p>  
  169. <p></p><pre code_snippet_id="270100" snippet_file_name="blog_20140402_20_1415163" name="code" class="objc">static void PingStart(void)  
  170. {  
  171.     #if defined(CONFIG_NET_MULTI)  
  172.     printf ("Using %s device\n", eth_get_name());  
  173.     #endif  /* CONFIG_NET_MULTI */  
  174.     NetSetTimeout (10000UL, PingTimeout); //设置超时处理函数  
  175.     NetSetHandler (PingHandler);设置数据包接收处理函数  
  176.    
  177.     PingSend(); //注释3.1  
  178. }  
  179. Void NetSetTimeout(ulong iv, thand_f * f)  
  180. {  
  181.     if (iv == 0) {  
  182.         timeHandler = (thand_f *)0;  
  183.     } else {  
  184.         timeHandler = f;  
  185.         timeStart = get_timer(0);  
  186.         timeDelta = iv;  
  187.     }  
  188. }  
  189. Void NetSetHandler(rxhand_f * f)  
  190. {  
  191.     packetHandler = f;  
  192. }</pre><br>  
  193. <br>  
  194. <p></p>  
  195. <p> //<span style="font-family:宋体">注释</span><span style="font-family:Times New Roman">3.1</span></p>  
  196. <p>发送<span style="font-family:Times New Roman">Echo request</span><span style="font-family:宋体">之前需要知道对方的</span><span style="font-family:Times New Roman">MAC</span><span style="font-family:宋体">地址,这需要发送</span><span style="font-family:Times New Roman">ARP</span><span style="font-family:宋体">数据包。所以</span><span style="font-family:Times New Roman">ARP</span><span style="font-family:宋体">数据包放在</span><span style="font-family:Times New Roman">NetTxPacket</span><span style="font-family:宋体">所指向的</span><span style="font-family:Times New Roman">buffer</span><span style="font-family:宋体">里,而</span><span style="font-family:Times New Roman">Echo request </span><span style="font-family:宋体">数据包放在</span><span style="font-family:Times New Roman">NetArpWaitTxPacket</span><span style="font-family:宋体">所指向的</span><span style="font-family:Times New Roman">buffer</span><span style="font-family:宋体">里,等查询到对方的</span><span style="font-family:Times New Roman">MAC</span><span style="font-family:宋体">地址后,再发送出去。</span></p>  
  197. <p></p><pre code_snippet_id="270100" snippet_file_name="blog_20140402_21_2221959" name="code" class="objc">int PingSend(void)   
  198. {  
  199.     static uchar mac[6];  
  200.     volatile IP_t *ip;  
  201.     volatile ushort *s;  
  202.     uchar *pkt;  
  203.     
  204.     /* XXX always send arp request */  
  205.    
  206.     /* 构造Echo  request  数据包,该数据包不会马上发出,因为目标硬件地址还是空的,   
  207.      * 会先发送ARP request数据包,当收到ARP reply 数据包后,再发送  Echo  request   
  208.      * 数据包 
  209.      */  
  210.     memcpy(mac, NetEtherNullAddr, 6);  
  211.     debug("sending ARP for %08lx\n", NetPingIP);  
  212.     NetArpWaitPacketIP = NetPingIP;  
  213.     NetArpWaitPacketMAC = mac;  
  214.    
  215.     /* 
  216.     *构造Ethernet II 协议头部,目标硬件地址暂定为00:00:00:00:00:00 
  217.     *源MAC地址是NetOurEther,是在NetLOOP()中初始化的。 
  218.     *帧类型是0x0806,PROT_ARP 
  219.     */  
  220.    
  221.     pkt = NetArpWaitTxPacket;  
  222.     pkt += NetSetEther(pkt, mac, PROT_IP);  
  223.    
  224.     ip = (volatile IP_t *)pkt;  
  225.    
  226.     /* 
  227.     * 构造IP协议和ICMP 数据包, 
  228.     */  
  229.    
  230.     /* 
  231.      *  Construct an IP and ICMP header.  (need to set no fragment bit - XXX) 
  232.      */  
  233.     ip->ip_hl_v  = 0x45;  /*版本号和 IP_HDR_SIZE / 4 (not including UDP) */  
  234.     ip->ip_tos   = 0;     //服务类型  
  235.     ip->ip_len   = htons(IP_HDR_SIZE_NO_UDP + 8); // 总长度  
  236.     ip->ip_id    = htons(NetIPID++); // 标示  
  237.     ip->ip_off   = htons(IP_FLAGS_DFRAG);    /* Don't fragment */ //片偏移  
  238.     ip->ip_ttl   = 255//生存时间  
  239.     ip->ip_p     = 0x01;  /* ICMP */ //协议类型  
  240.     ip->ip_sum   = 0;   
  241.     /*源IP地址和目的IP地址*/  
  242.     NetCopyIP((void*)&ip->ip_src, &NetOurIP); /* already in network byte order */  
  243.     NetCopyIP((void*)&ip->ip_dst, &NetPingIP);      /* - "" - */  
  244.     ip->ip_sum   = ~NetCksum((uchar *)ip, IP_HDR_SIZE_NO_UDP / 2); 校验和  
  245.    
  246.     s = &ip->udp_src;     /* XXX ICMP starts here */  
  247.     s[0] = htons(0x0800);    /* echo-request, code *///请求回显  
  248.     s[1] = 0;    /* checksum */  //校验和  
  249.     s[2] = 0;    /* identifier */  //标示符  
  250.     s[3] = htons(PingSeqNo++);  /* sequence number */  // 序列号  
  251.     s[1] = ~NetCksum((uchar *)s, 8/2);   
  252.    
  253.     /* size of the waiting packet */  
  254.     NetArpWaitTxPacketSize = (pkt - NetArpWaitTxPacket) + IP_HDR_SIZE_NO_UDP + 8;  
  255.    
  256.    /* 
  257.     *  设置Arp的超时时间的起始点,ArpTimeoutCheck()会处理ARP超时的问题 
  258.     */  
  259.     /* and do the ARP request */  
  260.     NetArpWaitTry = 1;  
  261.     NetArpWaitTimerStart = get_timer(0);  
  262.    /* 
  263.     *发送ARP request,退出pingsend(),程序会在NetLOOP中循环接收数据包,并调用处     
  264.     *理函数。 
  265.     */  
  266.     ArpRequest(); // 注释3.2  
  267.     return 1;   /* waiting */  
  268. }</pre><img src="https://img-blog.csdn.net/20140402111638250?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbmFuYW94dWU=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt=""><br>  
  269. <br>  
  270. <p></p>  
  271. <p>                                                         图      将要发送的<span style="font-family:'Times New Roman'">ping echo request </span><span style="font-family:宋体">数据包</span></p>  
  272. <p>注释<span style="font-family:Times New Roman">3.2</span></p>  
  273. <p>//<span style="font-family:宋体">发送</span><span style="font-family:Times New Roman">ARP request</span></p>  
  274. <p></p><pre code_snippet_id="270100" snippet_file_name="blog_20140402_22_9125059" name="code" class="objc">void ArpRequest (void)  
  275. {  
  276.     int i;  
  277.     volatile uchar *pkt;  
  278.     ARP_t *arp;  
  279.    
  280.     debug("ARP broadcast %d\n", NetArpWaitTry);  
  281.    
  282.     pkt = NetTxPacket;  
  283.     /* 
  284.      *构造Ethernet II 协议头部,NetBcastAddr是广播地址,FF:FF:FF:FF:FF:FF 
  285.      *源MAC地址是NetOurEther,是在NetLOOP()中初始化的。 
  286.      *帧类型是0x0806,PROT_ARP 
  287.      */  
  288.     pkt += NetSetEther (pkt, NetBcastAddr, PROT_ARP);  
  289.     /* 
  290.     * 构造ARP协议数据包, 
  291.     */  
  292.     arp = (ARP_t *) pkt;  
  293.     
  294.     arp->ar_hrd = htons (ARP_ETHER); //硬件类型ARP_ETHER = 1  表示以太网  
  295.     arp->ar_pro = htons (PROT_IP);    // 协议类型 表示要映射的协议地址类型  
  296.     arp->ar_hln = 6;  //硬件地址长度 MAC地址字节数  
  297.     arp->ar_pln = 4;  //协议地址长度 IP地址字节数  
  298.     arp->ar_op = htons (ARPOP_REQUEST); //操作类型ARPOP_REQUEST=1表示ARP请求  
  299.    
  300.     memcpy (&arp->ar_data[0], NetOurEther, 6);    /* source ET addr  */  
  301.     NetWriteIP ((uchar *) & arp->ar_data[6], NetOurIP);  /* source IP addr   */  
  302.     for (i = 10; i < 16; ++i) {   
  303.         arp->ar_data[i] = 0;  /* dest ET addr = 0     */  
  304.     }  
  305.     // 接收方的IP地址,若不在同一网段,需要设置环境变量gatewayip  
  306.     if ((NetArpWaitPacketIP & NetOurSubnetMask) != (NetOurIP & NetOurSubnetMask)) {  
  307.         if (NetOurGatewayIP == 0) {  
  308.             puts ("## Warning: gatewayip needed but not set\n");  
  309.             NetArpWaitReplyIP = NetArpWaitPacketIP;  
  310.         } else {  
  311.             NetArpWaitReplyIP = NetOurGatewayIP;  
  312.         }  
  313.     } else {  
  314.         NetArpWaitReplyIP = NetArpWaitPacketIP;  
  315.     }  
  316.    
  317.     NetWriteIP ((uchar *) & arp->ar_data[16], NetArpWaitReplyIP);  
  318.     //调用发送函数,  
  319.     (void) eth_send (NetTxPacket, (pkt - NetTxPacket) + ARP_HDR_SIZE);注释3.3  
  320. }</pre><br>  
  321. <img src="https://img-blog.csdn.net/20140402112024453?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbmFuYW94dWU=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt=""><br>  
  322. <p></p>  
  323. <p>                                                 图         发送的<span style="font-family:'Times New Roman'">ARP</span><span style="font-family:宋体">数据包</span></p>  
  324. <p>     </p>  
  325. <p> 注释<span style="font-family:'Times New Roman'">3.3</span></p>  
  326. <p>//IP3912<span style="font-family:宋体">发送函数的原理,可以参照</span><span style="font-family:Times New Roman">CPU Ethernet </span><span style="font-family:宋体">模块章节</span></p>  
  327. <p></p><pre code_snippet_id="270100" snippet_file_name="blog_20140402_23_2647853" name="code" class="objc">int eth_send(volatile voidvoid *packet, int length)  
  328. {  
  329.     if (!eth_current)  
  330.         return -1;  
  331.     return eth_current->send(eth_current, packet, length);  
  332. }</pre><span style="background-color:rgb(240,240,240)">static int ip3912_send(struct eth_device *netdev, volatile voidvoid *packet, int length)</span><p></p>  
  333. <p></p><pre code_snippet_id="270100" snippet_file_name="blog_20140402_24_6519310" name="code" class="objc">{  
  334.    略  
  335. }</pre><p></p>  
  336. <p> </p>  
  337. <p>注释<span style="font-family:'Times New Roman'">4</span></p>  
  338. <p>可以只看注释<span style="font-family:Times New Roman">4.1</span></p>  
  339. <p></p><pre code_snippet_id="270100" snippet_file_name="blog_20140402_25_5058614" name="code" class="objc">int eth_rx(void)  
  340. {  
  341.     if (!eth_current)  
  342.         return -1;  
  343.    
  344.     return eth_current->recv(eth_current);  
  345. }</pre><br>  
  346. <br>  
  347. <p></p>  
  348. <p>//IP3912<span style="font-family:宋体">接收函数的原理,可以参照</span><span style="font-family:Times New Roman">CPU Ethernet </span><span style="font-family:宋体">模块章节</span></p>  
  349. <p></p><pre code_snippet_id="270100" snippet_file_name="blog_20140402_26_5865409" name="code" class="objc">/* Check for received packets */  
  350. static int ip3912_recv(struct eth_device *netdev)  
  351. {  
  352. 略  
  353. }</pre><br>  
  354. <p></p>  
  355. <p>注释<span style="font-family:Times New Roman">4.1</span></p>  
  356. <p></p><pre code_snippet_id="270100" snippet_file_name="blog_20140402_27_1896458" name="code" class="objc">void NetReceive(volatile uchar * inpkt, int len)  
  357. {  
  358.     Ethernet_t *et;  
  359.     IP_t    *ip;  
  360.     ARP_t   *arp;  
  361.     IPaddr_t tmp;  
  362.     int    x;  
  363.     uchar *pkt;  
  364.    
  365.     ushort cti = 0, vlanid = VLAN_NONE, myvlanid, mynvlanid;  
  366.    
  367.     debug("packet received\n");  
  368.    
  369.     NetRxPacket = inpkt;  
  370.     NetRxPacketLen = len;  
  371.     et = (Ethernet_t *)inpkt;  
  372.    
  373.     /* too small packet? */  
  374.     if (len < ETHER_HDR_SIZE)  
  375.         return;  
  376.    
  377.     myvlanid = ntohs(NetOurVLAN);  
  378.     if (myvlanid == (ushort)-1)  
  379.         myvlanid = VLAN_NONE;  
  380.     mynvlanid = ntohs(NetOurNativeVLAN);  
  381.     if (mynvlanid == (ushort)-1)  
  382.         mynvlanid = VLAN_NONE;  
  383.    
  384.     x = ntohs(et->et_protlen);  
  385.    
  386.     debug("packet received\n");  
  387.    
  388.     if (x < 1514) {  
  389.         /* 
  390.          *  Got a 802 packet.  Check the other protocol field. 
  391.          */  
  392.         x = ntohs(et->et_prot);  
  393.    
  394.         ip = (IP_t *)(inpkt + E802_HDR_SIZE);  
  395.         len -= E802_HDR_SIZE;  
  396.    
  397.     } else if (x != PROT_VLAN) {    /* normal packet */  
  398.         ip = (IP_t *)(inpkt + ETHER_HDR_SIZE);  
  399.         len -= ETHER_HDR_SIZE;  
  400.    
  401.     } else {     /* VLAN packet */  
  402.         VLAN_Ethernet_t *vet = (VLAN_Ethernet_t *)et;  
  403.    
  404.         debug("VLAN packet received\n");  
  405.         /* too small packet? */  
  406.         if (len < VLAN_ETHER_HDR_SIZE)  
  407.             return;  
  408.         /* if no VLAN active */  
  409.         if ((ntohs(NetOurVLAN) & VLAN_IDMASK) == VLAN_NONE)  
  410.             return;  
  411.         cti = ntohs(vet->vet_tag);  
  412.         vlanid = cti & VLAN_IDMASK;  
  413.         x = ntohs(vet->vet_type);  
  414.    
  415.         ip = (IP_t *)(inpkt + VLAN_ETHER_HDR_SIZE);  
  416.         len -= VLAN_ETHER_HDR_SIZE;  
  417.     }  
  418.    
  419.     debug("Receive from protocol 0x%x\n", x);  
  420.    
  421.     if ((myvlanid & VLAN_IDMASK) != VLAN_NONE) {  
  422.         if (vlanid == VLAN_NONE)  
  423.             vlanid = (mynvlanid & VLAN_IDMASK);  
  424.             /* not matched? */  
  425.         if (vlanid != (myvlanid & VLAN_IDMASK))  
  426.             return;  
  427.     }  
  428.    
  429.     switch (x) {  
  430.         case PROT_ARP:  
  431.             /* 
  432.              * We have to deal with two types of ARP packets: 
  433.              * - REQUEST packets will be answered by sending  our 
  434.              *   IP address - if we know it. 
  435.              * - REPLY packates are expected only after we asked 
  436.              *   for the TFTP server's or the gateway's ethernet 
  437.              *   address; so if we receive such a packet, we set 
  438.              *   the server ethernet address 
  439.              */  
  440.             debug("Got ARP\n");  
  441.    
  442.             arp = (ARP_t *)ip;  
  443.             if (len < ARP_HDR_SIZE) {  
  444.                 printf("bad length %d < %d\n", len, ARP_HDR_SIZE);  
  445.                 return;  
  446.             }  
  447.             if (ntohs(arp->ar_hrd) != ARP_ETHER) {  
  448.                 return;  
  449.             }  
  450.             if (ntohs(arp->ar_pro) != PROT_IP) {  
  451.                 return;  
  452.             }  
  453.             if (arp->ar_hln != 6) {  
  454.                 return;  
  455.             }  
  456.             if (arp->ar_pln != 4) {  
  457.                 return;  
  458.             }  
  459.    
  460.             if (NetOurIP == 0) {  
  461.                 return;  
  462.             }  
  463.    
  464.             if (NetReadIP(&arp->ar_data[16]) != NetOurIP) {  
  465.                 return;  
  466.             }  
  467.             switch (ntohs(arp->ar_op)) {  
  468.                 case ARPOP_REQUEST:  /* reply with our IP address   */  
  469.                     debug("Got ARP REQUEST, return our IP\n");  
  470.                     pkt = (uchar *)et;  
  471.                     pkt += NetSetEther(pkt, et->et_src, PROT_ARP);  
  472.                     arp->ar_op = htons(ARPOP_REPLY);  
  473.                     memcpy   (&arp->ar_data[10], &arp->ar_data[0], 6);  
  474.                     NetCopyIP(&arp->ar_data[16], &arp->ar_data[6]);  
  475.                     memcpy   (&arp->ar_data[ 0], NetOurEther, 6);  
  476.                     NetCopyIP(&arp->ar_data[ 6], &NetOurIP);  
  477.                     (void) eth_send((uchar *)et, (pkt - (uchar *)et) + ARP_HDR_SIZE);  
  478.                     return;  
  479.                 case ARPOP_REPLY:    /* arp reply */  
  480.                     /* are we waiting for a reply */  
  481.                     if (!NetArpWaitPacketIP || !NetArpWaitPacketMAC)  
  482.                         break;  
  483.    
  484.                     debug("Got ARP REPLY, set server/gtwy eth addr (%pM)\n",arp->ar_data);  
  485.                     tmp = NetReadIP(&arp->ar_data[6]);  
  486.    
  487.                     /* matched waiting packet's address */  
  488.                     /* 
  489.                      * 如果收到ARP reply消息,就从里面获取到目标硬件地址, 
  490.                      * 并填写到正在等待发送的Ping Echo request数据包内,并发送 
  491.                      *  Ping Echo request数据包。之后会收到ping echo reply 消息, 
  492.                      *  仍会执行NetReceive()函数。 
  493.                      */  
  494.                      if (tmp == NetArpWaitReplyIP) {   
  495.                          debug("Got it\n");  
  496.                          /* save address for later use */  
  497.                          memcpy(NetArpWaitPacketMAC, &arp->ar_data[0], 6);  
  498.    
  499.                          #ifdef CONFIG_NETCONSOLE  
  500.                              (*packetHandler)(0,0,0,0);  
  501.                          #endif  
  502.                          /* modify header, and transmit it */  
  503.                          memcpy(((Ethernet_t *)NetArpWaitTxPacket)->et_dest, NetArpWaitPacketMAC, 6);  
  504.                          (void) eth_send(NetArpWaitTxPacket, NetArpWaitTxPacketSize);  
  505.    
  506.                          /* no arp request pending now */  
  507.                          NetArpWaitPacketIP = 0;  
  508.                          NetArpWaitTxPacketSize = 0;  
  509.                          NetArpWaitPacketMAC = NULL;  
  510.                      }  
  511.                      return;  
  512.                  default:  
  513.                      debug("Unexpected ARP opcode 0x%x\n", ntohs(arp->ar_op));  
  514.                      return;  
  515.              }  
  516.              break;  
  517.          case PROT_RARP:  
  518.              debug("Got RARP\n");  
  519.              arp = (ARP_t *)ip;  
  520.              if (len < ARP_HDR_SIZE) {  
  521.                  printf("bad length %d < %d\n", len, ARP_HDR_SIZE);  
  522.                  return;  
  523.              }  
  524.    
  525.              if ((ntohs(arp->ar_op) != RARPOP_REPLY) ||  
  526.                    (ntohs(arp->ar_hrd) != ARP_ETHER)   ||  
  527.                        (ntohs(arp->ar_pro) != PROT_IP)     ||  
  528.                           (arp->ar_hln != 6) || (arp->ar_pln != 4)) {  
  529.                  puts ("invalid RARP header\n");  
  530.              } else {  
  531.                  NetCopyIP(&NetOurIP,    &arp->ar_data[16]);  
  532.                  if (NetServerIP == 0)  
  533.                      NetCopyIP(&NetServerIP, &arp->ar_data[ 6]);  
  534.                  memcpy (NetServerEther, &arp->ar_data[ 0], 6);  
  535.    
  536.                  (*packetHandler)(0,0,0,0);  
  537.              }  
  538.              break;  
  539.          case PROT_IP:  
  540.              debug("Got IP\n");  
  541.              /* Before we start poking the header, make sure it is there */  
  542.              if (len < IP_HDR_SIZE) {  
  543.                  debug("len bad %d < %lu\n", len, (ulong)IP_HDR_SIZE);  
  544.                  return;  
  545.              }  
  546.              /* Check the packet length */  
  547.              if (len < ntohs(ip->ip_len)) {  
  548.                  printf("len bad %d < %d\n", len, ntohs(ip->ip_len));  
  549.                  return;  
  550.              }  
  551.              len = ntohs(ip->ip_len);  
  552.              debug("len=%d, v=%02x\n", len, ip->ip_hl_v & 0xff);  
  553.    
  554.              /* Can't deal with anything except IPv4 */  
  555.              if ((ip->ip_hl_v & 0xf0) != 0x40) {  
  556.                  return;  
  557.              }  
  558.              /* Can't deal with IP options (headers != 20 bytes) */  
  559.              if ((ip->ip_hl_v & 0x0f) > 0x05) {  
  560.                  return;  
  561.              }  
  562.              /* Check the Checksum of the header */  
  563.              if (!NetCksumOk((uchar *)ip, IP_HDR_SIZE_NO_UDP / 2)) {  
  564.                  puts ("checksum bad\n");  
  565.              return;  
  566.          }  
  567.          /* If it is not for us, ignore it */  
  568.          tmp = NetReadIP(&ip->ip_dst);  
  569.          if (NetOurIP && tmp != NetOurIP && tmp != 0xFFFFFFFF) {  
  570.              return;  
  571.          }  
  572.          /* 
  573.           * The function returns the unchanged packet if it's not 
  574.           * a fragment, and either the complete packet or NULL if 
  575.           * it is a fragment (if !CONFIG_IP_DEFRAG, it returns NULL) 
  576.           */  
  577.          if (!(ip = NetDefragment(ip, &len)))  
  578.              return;  
  579.           /* 
  580.            * watch for ICMP host redirects 
  581.            * 
  582.            * There is no real handler code (yet). We just watch 
  583.            * for ICMP host redirect messages. In case anybody 
  584.            * sees these messages: please contact me 
  585.            * (wd@denx.de), or - even better - send me the 
  586.            * necessary fixes :-) 
  587.            * 
  588.            * Note: in all cases where I have seen this so far 
  589.            * it was a problem with the router configuration, 
  590.            * for instance when a router was configured in the 
  591.            * BOOTP reply, but the TFTP server was on the same 
  592.            * subnet. So this is probably a warning that your 
  593.            * configuration might be wrong. But I'm not really 
  594.            * sure if there aren't any other situations. 
  595.            */  
  596.            if (ip->ip_p == IPPROTO_ICMP) {  
  597.                ICMP_t *icmph = (ICMP_t *)&(ip->udp_src);  
  598.    
  599.            switch (icmph->type) {  
  600.                case ICMP_REDIRECT:  
  601.                    if (icmph->code != ICMP_REDIR_HOST)  
  602.                        return;  
  603.                    printf (" ICMP Host Redirect to %pI4 ", &icmph->un.gateway);  
  604.                    return;  
  605.                case ICMP_ECHO_REPLY:  
  606.                    /* 收到ping echo reply 消息,执行pingStart()函数中注册的处理函数                                                                                        *  PingHandler()。 PingHandler()判断是否ping成功。若成功,流程返  
  607.                     *  回 Netloop中while循环,接着返回do_ping(),打印成功消息后, 
  608.                     *  流程结束 
  609.                     *  static void 
  610.                     * PingHandler (uchar * pkt, unsigned dest, unsigned src, unsigned len) 
  611.                     * { 
  612.                     *   IPaddr_t tmp; 
  613.                     *  volatile IP_t *ip = (volatile IP_t *)pkt; 
  614.                     *  tmp = NetReadIP((void *)&ip->ip_src); 
  615.                     *  if (tmp != NetPingIP) 
  616.                     *    return; 
  617.                     *   NetState = NETLOOP_SUCCESS; 
  618.                     * } 
  619.                     */  
  620.    
  621.                     /* 
  622.                      *  IP header OK.  Pass the packet to the current handler. 
  623.                      */  
  624.                     /* XXX point to ip packet */  
  625.                     (*packetHandler)((uchar *)ip, 000);  
  626.                     return;  
  627.                 case ICMP_ECHO_REQUEST:  
  628.                     debug("Got ICMP ECHO REQUEST, return %d bytes \n",ETHER_HDR_SIZE + len);  
  629.    
  630.                     memcpy (&et->et_dest[0], &et->et_src[0], 6);  
  631.                     memcpy (&et->et_src[ 0], NetOurEther, 6);  
  632.                     ip->ip_sum = 0;  
  633.                     ip->ip_off = 0;  
  634.                     NetCopyIP((void*)&ip->ip_dst, &ip->ip_src);  
  635.                     NetCopyIP((void*)&ip->ip_src, &NetOurIP);  
  636.                     ip->ip_sum = ~NetCksum((uchar *)ip, IP_HDR_SIZE_NO_UDP >> 1);  
  637.    
  638.                     icmph->type = ICMP_ECHO_REPLY;  
  639.                     icmph->checksum = 0;  
  640.                     icmph->checksum = ~NetCksum((uchar *)icmph,(len - IP_HDR_SIZE_NO_UDP) >> 1);  
  641.                     (void) eth_send((uchar *)et, ETHER_HDR_SIZE + len);  
  642.                     return;  
  643.                 default:  
  644.                     return;  
  645.             }  
  646.         } else if (ip->ip_p != IPPROTO_UDP) {    /* Only UDP packets */  
  647.             return;  
  648.         }  
  649.    
  650.    
  651.         /* 
  652.          *  IP header OK.  Pass the packet to the current handler. 
  653.          */  
  654.         (*packetHandler)((uchar *)ip +IP_HDR_SIZE,  
  655.             ntohs(ip->udp_dst),  
  656.             ntohs(ip->udp_src),  
  657.             ntohs(ip->udp_len) - 8);  
  658.         break;  
  659.     }  
  660. }  
  661.  </pre><br>  
  662. <br>  
  663. <p></p>  
  664. <p> </p>  
  665. <p>                附录一  CONFIG_NET_MULTI</p>  
  666. <p> </p>  
  667. <p>搜素整个源码,可以找个很多关于CONFIG_NET_MULTI的注释, </p>  
  668. <p>#define CONFIG_NET_MULTI  /* Multi ethernet cards support */</p>  
  669. <p>或者</p>  
  670. <p>#define CONFIG_NET_MULTI  /*specify more that one ports available */</p>  
  671. <p>或者</p>  
  672. <p>#define CONFIG_NET_MULTI /* Support for multiple network interfaces */</p>  
  673. <p>从上面的注释可以猜出当有多个网口设备时,需要定义<span style="font-family:Times New Roman">CONFIG_NET_MULTI</span> 。</p>  
  674. <p>一个<span style="font-family:Times New Roman">IP173</span><span style="font-family:宋体">有</span><span style="font-family:Times New Roman">5</span><span style="font-family:宋体">个</span><span style="font-family:Times New Roman">PHY</span><span style="font-family:宋体">,算一个设备,还是多个设备?</span></p>  
  675. <p>Readme<span style="font-family:宋体">文档中也讲到两个和</span><span style="font-family:Times New Roman">CONFIG_NET_MULTI </span><span style="font-family:宋体">有关的环境变量。</span></p>  
  676. <p>  ethprime - When CONFIG_NET_MULTI is enabled controls which</p>  
  677. <p>  interface is used first.</p>  
  678. <p>  ethact - When CONFIG_NET_MULTI is enabled controls which</p>  
  679. <p>  interface is currently active. For example you</p>  
  680. <p>  can do the following</p>  
  681. <p> </p><pre code_snippet_id="270100" snippet_file_name="blog_20140402_28_751407" name="code" class="objc">void  
  682. NetReceive(volatile uchar * inpkt, int len)  
  683. {  
  684. Ethernet_t *et;  
  685. IP_t    *ip;  
  686. ARP_t   *arp;  
  687. IPaddr_t tmp;  
  688. int x;  
  689. uchar *pkt;  
  690.    
  691. ushort cti = 0, vlanid = VLAN_NONE, myvlanid, mynvlanid;  
  692.    
  693. debug("packet received\n");  
  694.    
  695. NetRxPacket = inpkt;  
  696. NetRxPacketLen = len;  
  697. et = (Ethernet_t *)inpkt;  
  698.    
  699. /* too small packet? */  
  700. if (len < ETHER_HDR_SIZE)  
  701. return;  
  702.    
  703.    
  704.    
  705. myvlanid = ntohs(NetOurVLAN);  
  706. if (myvlanid == (ushort)-1)  
  707. myvlanid = VLAN_NONE;  
  708. mynvlanid = ntohs(NetOurNativeVLAN);  
  709. if (mynvlanid == (ushort)-1)  
  710. mynvlanid = VLAN_NONE;  
  711.    
  712. x = ntohs(et->et_protlen);  
  713.    
  714. debug("packet received\n");  
  715.    
  716. if (x < 1514) {  
  717. /* 
  718.  *  Got a 802 packet.  Check the other protocol field. 
  719.  */  
  720. x = ntohs(et->et_prot);  
  721.    
  722. ip = (IP_t *)(inpkt + E802_HDR_SIZE);  
  723. len -= E802_HDR_SIZE;  
  724.    
  725. else if (x != PROT_VLAN) {    /* normal packet */  
  726. ip = (IP_t *)(inpkt + ETHER_HDR_SIZE);  
  727. len -= ETHER_HDR_SIZE;  
  728.    
  729. else {     /* VLAN packet */  
  730. VLAN_Ethernet_t *vet = (VLAN_Ethernet_t *)et;  
  731.    
  732. debug("VLAN packet received\n");  
  733.    
  734. /* too small packet? */  
  735. if (len < VLAN_ETHER_HDR_SIZE)  
  736. return;  
  737.    
  738. /* if no VLAN active */  
  739. if ((ntohs(NetOurVLAN) & VLAN_IDMASK) == VLAN_NONE  
  740. )  
  741. return;  
  742.    
  743. cti = ntohs(vet->vet_tag);  
  744. vlanid = cti & VLAN_IDMASK;  
  745. x = ntohs(vet->vet_type);  
  746.    
  747. ip = (IP_t *)(inpkt + VLAN_ETHER_HDR_SIZE);  
  748. len -= VLAN_ETHER_HDR_SIZE;  
  749. }  
  750.    
  751. debug("Receive from protocol 0x%x\n", x);  
  752.    
  753. if ((myvlanid & VLAN_IDMASK) != VLAN_NONE) {  
  754. if (vlanid == VLAN_NONE)  
  755. vlanid = (mynvlanid & VLAN_IDMASK);  
  756. /* not matched? */  
  757. if (vlanid != (myvlanid & VLAN_IDMASK))  
  758. return;  
  759. }  
  760.    
  761. switch (x) {  
  762.    
  763. case PROT_ARP:  
  764. /* 
  765.  * We have to deal with two types of ARP packets: 
  766.  * - REQUEST packets will be answered by sending  our 
  767.  *   IP address - if we know it. 
  768.  * - REPLY packates are expected only after we asked 
  769.  *   for the TFTP server's or the gateway's ethernet 
  770.  *   address; so if we receive such a packet, we set 
  771.  *   the server ethernet address 
  772.  */  
  773. debug("Got ARP\n");  
  774.    
  775. arp = (ARP_t *)ip;  
  776. if (len < ARP_HDR_SIZE) {  
  777. printf("bad length %d < %d\n", len, ARP_HDR_SIZE);  
  778. return;  
  779. }  
  780. if (ntohs(arp->ar_hrd) != ARP_ETHER) {  
  781. return;  
  782. }  
  783. if (ntohs(arp->ar_pro) != PROT_IP) {  
  784. return;  
  785. }  
  786. if (arp->ar_hln != 6) {  
  787. return;  
  788. }  
  789. if (arp->ar_pln != 4) {  
  790. return;  
  791. }  
  792.    
  793. if (NetOurIP == 0) {  
  794. return;  
  795. }  
  796.    
  797. if (NetReadIP(&arp->ar_data[16]) != NetOurIP) {  
  798. return;  
  799. }  
  800.    
  801. switch (ntohs(arp->ar_op)) {  
  802. case ARPOP_REQUEST:  /* reply with our IP address   */  
  803. debug("Got ARP REQUEST, return our IP\n");  
  804. pkt = (uchar *)et;  
  805. pkt += NetSetEther(pkt, et->et_src, PROT_ARP);  
  806. arp->ar_op = htons(ARPOP_REPLY);  
  807. memcpy   (&arp->ar_data[10], &arp->ar_data[0], 6);  
  808. NetCopyIP(&arp->ar_data[16], &arp->ar_data[6]);  
  809. memcpy   (&arp->ar_data[ 0], NetOurEther, 6);  
  810. NetCopyIP(&arp->ar_data[ 6], &NetOurIP);  
  811. (void) eth_send((uchar *)et, (pkt - (uchar *)et) + ARP_HDR_SIZE);  
  812. return;  
  813.    
  814. case ARPOP_REPLY:    /* arp reply */  
  815. /* are we waiting for a reply */  
  816. if (!NetArpWaitPacketIP || !NetArpWaitPacketMAC)  
  817. break;  
  818.    
  819. debug("Got ARP REPLY, set server/gtwy eth addr (%pM)\n",  
  820. arp->ar_data);  
  821.    
  822. tmp = NetReadIP(&arp->ar_data[6]);  
  823.    
  824. /* matched waiting packet's address */  
  825. /* 
  826. * 如果收到ARP reply消息,就从里面获取到目标硬件地址, 
  827. * 并填写到正在等待发送的Ping Echo request数据包内,并发送 
  828.             *  Ping Echo request数据包。之后会收到ping echo reply 消息, 
  829. *  仍会执行NetReceive()函数。 
  830. */  
  831. if (tmp == NetArpWaitReplyIP) {   
  832. debug("Got it\n");  
  833. /* save address for later use */  
  834. memcpy(NetArpWaitPacketMAC, &arp->ar_data[0], 6);  
  835.    
  836. #ifdef CONFIG_NETCONSOLE  
  837. (*packetHandler)(0,0,0,0);  
  838. #endif  
  839. /* modify header, and transmit it */  
  840. memcpy(((Ethernet_t *)NetArpWaitTxPacket)->et_dest, NetArpWaitPacketMAC, 6);  
  841. (void) eth_send(NetArpWaitTxPacket, NetArpWaitTxPacketSize);  
  842.    
  843. /* no arp request pending now */  
  844. NetArpWaitPacketIP = 0;  
  845. NetArpWaitTxPacketSize = 0;  
  846. NetArpWaitPacketMAC = NULL;  
  847.    
  848. }  
  849. return;  
  850. default:  
  851. debug("Unexpected ARP opcode 0x%x\n", ntohs(arp->ar_op));  
  852. return;  
  853. }  
  854. break;  
  855.    
  856. case PROT_RARP:  
  857. debug("Got RARP\n");  
  858. arp = (ARP_t *)ip;  
  859. if (len < ARP_HDR_SIZE) {  
  860. printf("bad length %d < %d\n", len, ARP_HDR_SIZE);  
  861. return;  
  862. }  
  863.    
  864. if ((ntohs(arp->ar_op) != RARPOP_REPLY) ||  
  865. (ntohs(arp->ar_hrd) != ARP_ETHER)   ||  
  866. (ntohs(arp->ar_pro) != PROT_IP)     ||  
  867. (arp->ar_hln != 6) || (arp->ar_pln != 4)) {  
  868.    
  869. puts ("invalid RARP header\n");  
  870. else {  
  871. NetCopyIP(&NetOurIP,    &arp->ar_data[16]);  
  872. if (NetServerIP == 0)  
  873. NetCopyIP(&NetServerIP, &arp->ar_data[ 6]);  
  874. memcpy (NetServerEther, &arp->ar_data[ 0], 6);  
  875.    
  876. (*packetHandler)(0,0,0,0);  
  877. }  
  878. break;  
  879.    
  880. case PROT_IP:  
  881. debug("Got IP\n");  
  882. /* Before we start poking the header, make sure it is there */  
  883. if (len < IP_HDR_SIZE) {  
  884. debug("len bad %d < %lu\n", len, (ulong)IP_HDR_SIZE);  
  885. return;  
  886. }  
  887. /* Check the packet length */  
  888. if (len < ntohs(ip->ip_len)) {  
  889. printf("len bad %d < %d\n", len, ntohs(ip->ip_len));  
  890. return;  
  891. }  
  892. len = ntohs(ip->ip_len);  
  893. debug("len=%d, v=%02x\n", len, ip->ip_hl_v & 0xff);  
  894.    
  895. /* Can't deal with anything except IPv4 */  
  896. if ((ip->ip_hl_v & 0xf0) != 0x40) {  
  897. return;  
  898. }  
  899. /* Can't deal with IP options (headers != 20 bytes) */  
  900. if ((ip->ip_hl_v & 0x0f) > 0x05) {  
  901. return;  
  902. }  
  903. /* Check the Checksum of the header */  
  904. if (!NetCksumOk((uchar *)ip, IP_HDR_SIZE_NO_UDP / 2)) {  
  905. puts ("checksum bad\n");  
  906. return;  
  907. }  
  908. /* If it is not for us, ignore it */  
  909. tmp = NetReadIP(&ip->ip_dst);  
  910. if (NetOurIP && tmp != NetOurIP && tmp != 0xFFFFFFFF) {  
  911. return;  
  912. }  
  913. /* 
  914.  * The function returns the unchanged packet if it's not 
  915.  * a fragment, and either the complete packet or NULL if 
  916.  * it is a fragment (if !CONFIG_IP_DEFRAG, it returns NULL) 
  917.  */  
  918. if (!(ip = NetDefragment(ip, &len)))  
  919. return;  
  920. /* 
  921.  * watch for ICMP host redirects 
  922.  * 
  923.  * There is no real handler code (yet). We just watch 
  924.  * for ICMP host redirect messages. In case anybody 
  925.  * sees these messages: please contact me 
  926.  * (wd@denx.de), or - even better - send me the 
  927.  * necessary fixes :-) 
  928.  * 
  929.  * Note: in all cases where I have seen this so far 
  930.  * it was a problem with the router configuration, 
  931.  * for instance when a router was configured in the 
  932.  * BOOTP reply, but the TFTP server was on the same 
  933.  * subnet. So this is probably a warning that your 
  934.  * configuration might be wrong. But I'm not really 
  935.  * sure if there aren't any other situations. 
  936.  */  
  937. if (ip->ip_p == IPPROTO_ICMP) {  
  938. ICMP_t *icmph = (ICMP_t *)&(ip->udp_src);  
  939.    
  940. switch (icmph->type) {  
  941. case ICMP_REDIRECT:  
  942. if (icmph->code != ICMP_REDIR_HOST)  
  943. return;  
  944. printf (" ICMP Host Redirect to %pI4 ", &icmph->un.gateway);  
  945. return;  
  946. case ICMP_ECHO_REPLY:  
  947. /* 收到ping echo reply 消息,执行pingStart()函数中注册的处理函数   *  PingHandler()。 PingHandler()判断是否ping成功。若成功,流程返  
  948.  *  回 Netloop中while循环,接着返回do_ping(),打印成功消息后, 
  949.      *  流程结束 
  950.                  *  static void 
  951.                  * PingHandler (uchar * pkt, unsigned dest, unsigned src, unsigned len) 
  952.                  * { 
  953.                  *  IPaddr_t tmp; 
  954.              *  volatile IP_t *ip = (volatile IP_t *)pkt; 
  955.              *  tmp = NetReadIP((void *)&ip->ip_src); 
  956.              *  if (tmp != NetPingIP) 
  957.          *    return; 
  958.                  *  NetState = NETLOOP_SUCCESS; 
  959.                  * } 
  960.  */  
  961.    
  962. /* 
  963.  *  IP header OK.  Pass the packet to the current handler. 
  964.  */  
  965. /* XXX point to ip packet */  
  966. (*packetHandler)((uchar *)ip, 000);  
  967. return;  
  968. case ICMP_ECHO_REQUEST:  
  969. debug("Got ICMP ECHO REQUEST, return %d bytes \n",  
  970. ETHER_HDR_SIZE + len);  
  971.    
  972. memcpy (&et->et_dest[0], &et->et_src[0], 6);  
  973. memcpy (&et->et_src[ 0], NetOurEther, 6);  
  974.    
  975. ip->ip_sum = 0;  
  976. ip->ip_off = 0;  
  977. NetCopyIP((void*)&ip->ip_dst, &ip->ip_src);  
  978. NetCopyIP((void*)&ip->ip_src, &NetOurIP);  
  979. ip->ip_sum = ~NetCksum((uchar *)ip, IP_HDR_SIZE_NO_UDP >> 1);  
  980.    
  981. icmph->type = ICMP_ECHO_REPLY;  
  982. icmph->checksum = 0;  
  983. icmph->checksum = ~NetCksum((uchar *)icmph,  
  984. (len - IP_HDR_SIZE_NO_UDP) >> 1);  
  985. (void) eth_send((uchar *)et, ETHER_HDR_SIZE + len);  
  986. return;  
  987. default:  
  988. return;  
  989. }  
  990. else if (ip->ip_p != IPPROTO_UDP) {    /* Only UDP packets */  
  991. return;  
  992. }  
  993.    
  994.    
  995. /* 
  996.  *  IP header OK.  Pass the packet to the current handler. 
  997.  */  
  998. (*packetHandler)((uchar *)ip +IP_HDR_SIZE,  
  999. ntohs(ip->udp_dst),  
  1000. ntohs(ip->udp_src),  
  1001. ntohs(ip->udp_len) - 8);  
  1002. break;  
  1003. }  
  1004. }  
  1005.  </pre><br>  
  1006.  => setenv ethact FEC<p></p>  
  1007. <p>  => setenv ethact FEC</p>  
  1008. <p>  => ping 192.168.0.1 # traffic sent on FEC</p>  
  1009. <p>  => setenv ethact SCC</p>  
  1010. <p>  => ping 10.0.0.1 # traffic sent on SCC</p>  
  1011. <p> </p>  
  1012. <p> </p>  
  1013. <p> </p>  
  1014.     
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值