SylixOS 协议栈学习(二)以太网网卡接口部分初始化

SylixOS 协议栈学习(二)以太网网卡接口部分初始化

        在《SylixOS_协议栈学习(一)网络接口结构》中,介绍了netif 结构体和netdev结构体。
       下面举个例子来看一个以太网网卡接口结构是怎样被初始化,还有数据包是如何接收和发送的。
  1.     static struct netdev_funcs net_drv = {                         ①
  2.        .init      = __enetCoreInit,
  3.        .transmit  = __enetCoreTx,
  4.        .receive   = __enetCoreRecv,
  5. };
  6.    pNetDev->speed        = 0;                              ②
  7.    pNetDev->mtu          = 1500;
  8.    pNetDev->hwaddr_len   = 6;
  9.    pNetDev->drv          =&net_drv;
  10.    lib_strcpy(ip,     "192.168.3.202");                         ③
  11.    lib_strcpy(gw,     "192.168.3.1");
  12.    lib_strcpy(netmask, "255.255.255.0");
  13.    netdev_add(pNetDev, ip, netmask, gw, IFF_UP |IFF_RUNNING | IFF_BROADCAST | IFF_MULTICAST) == 0) ;  ④
①声明了网卡驱动函数,分别是以太网初始化函数,以太网发送函数,以太网接收函数。
②声明了网卡驱动参数(省略了一部分)。
③声明了三个分别用于暂存 IP 地址、子网掩码和网关地址的变量。
④网卡驱动程序调用netdev_add函数来增加一个网络接口。

netdev_add函数源码
  1. int  netdev_add (netdev_t *netdev, const char *ip, const char *netmask, const char *gw, int if_flags)
  2. {
  3. ......
  4.   netif = (struct netif *)netdev->sys;
  5.   lib_bzero(netif, sizeof(struct netif));
  6. ......
  7.   if (netifapi_netif_add(netif, &ip4, &netmask4, &gw4, netdev, netdev_netif_init, tcpip_input)) {
  8.     return (-1);
  9.   }
  10. ......
  11.   if (netdev->init_flags & NETDEV_INIT_AS_DEFAULT) {
  12.     netifapi_netif_set_default(netif);
  13.   }
  14. }
       netdev_add函数其实是netif_add的封装。最终还是通过调用netif_add函数来增加一个网络接口。(其中netdev->sys 是预留的用于存储netif结构体的成员变量),其中netdev_netif_init 是用户自己定义的底层接口初始化函数, tcpip_input 函数是向 IP 层递交数据包的函数。

 netif_add函数源码:
  1. struct netif *
  2. netif_add(struct netif *netif,
  3.           const ip4_addr_t *ipaddr, const ip4_addr_t *netmask, const ip4_addr_t *gw,
  4.           void *state, netif_init_fn init, netif_input_fn input)
  5. {
  6. ......
  7.   netif->state = state; //指向用户关心的信息,这里为 NULL
  8.   netif->num = netifnum++; //设置 num 字段,
  9.   netif->input = input; // input 函数被赋值 ,(tcpip_input向 IP 层递交数据包的函数)
  10. ......
  11.   netif_set_addr(netif, ipaddr, netmask, gw); //设置变量 enc28j60 的三个地址

  12.   if (init(netif) != ERR_OK) { //用户自己的底层接口初始化函数(netdev_netif_init自己定义的底层接口初始化函数)
  13.       return NULL;
  14.   }
  15.   netif->next = netif_list; //将初始化后的节点插入链表 netif_list
  16.   netif_list = netif; // netif_list 指向链表头
  17. ......
  18. }
       上面的初始化函数调用了用户自己定义的底层接口初始化函数,这里为netdev_netif_init函数,再来看看它的源代码:
  1. /* lwip netif add call back function */
  2. static err_t  netdev_netif_init (struct netif *netif)
  3. {
  4. ......
  5.   netif->output = etharp_output;  //IP 层发送数据包函数
  6. ......
  7.   netif->linkoutput = netdev_netif_linkoutput; //ARP 模块发送数据包函数
  8. ......
  9. }
至此,以太网网卡接口部分初始化结束。

在SylixOS中对LWIP进行了一次封装,最终使用的还是netif结构体和netif_add函数。
netif_add函数中填充了input、output、linkoutput等函数用于IP层从网卡上取得一个数据包、IP层向网卡发送一个数据包  、ARP 模块向网卡发送一个数据包。
以太网帧格式:


解析:
以太网目的地址:接收方设备的硬件地址(48bit,目的地址全为1的特殊地址是广播地址)。
以太网源地址:发送方的硬件地址
帧类型:表示后面数据的类型(其中,0x0806表示后面的数据是属于ARP包的,0x8035表示后面的数据属于RARP包,0x0800表示后面的数据是属于IP包)。
数据:(以太网帧数据要求最小为46字节,若小于该值,在不足的空间填充pad字节)。
CRC:用于帧内后续字节差错的循环冗余码检验(它也被称为FCS或帧检验序列)。
以太网帧传输最小长度要求64字节(6+6+2+46+4),在TCP/IP详解中提到的最小长度60字节包括以太网帧头但没包括以太网帧尾。
以太网帧传输最大长度要求1518字节(6+6+2+1500+4),最大值1500 称为以太网的最大传输单元(MTU),不同网络类型有不同MTU。
ARP报文仅28字节,所以通过以太网帧封装时,会填充18字节的PAD,达到数据段46字节的最小要求。

    • Related Articles

    • SylixOS 协议栈学习(三)ICMP 处理

           ICMP(Internet control message protocol)是网络控制报文协议,用于在IP主机跟路由器之间传输控制信息的。 控制信息指网络不通、主机是否可达、路由是否有用等。  之前在将ip4_input时,涉及到三次ICMP的东西:         1、在转发过程中,如果TTL变为0,则要用icmp_time_exceeded函数向源主机发送一份超时ICMP信息。         2、会通过ip报头,判断是否是ICMP报文,如果是,则调用icmp_input函数。 ...
    • SylixOS 协议栈学习(四)ping 工作流程

      Ping工作流程: 1、涉及协议介绍       运行ping程序时,会用到以下协议:       ICMP(因特网控制报文协议):用于IP主机、路由器直接传递控制消息(一般是差错信息,如TCP/UDP传输失败,会构建ICMP报文返回)。       IP协议:一种不可靠、无连接的传输协议(目的是为了更好的提供传输服务)。(对于TCP传输,已十分可靠,不需要在IP层再链接;UDP本身就是不可靠、无连接的协议,使用IP协议能更快传输)。     ...
    • SylixOS使用的网络协议栈是?

      Q:SylixOS使用的网络协议栈是? SylixOS使用的网络协议栈是 lwip 版本为 v2.1.0。 /** X.x.x: Major version of the stack */ #define LWIP_VERSION_MAJOR 2 /** x.X.x: Minor version of the stack */ #define LWIP_VERSION_MINOR 1 /** x.x.X: Revision of the stack */ #define ...
    • 支持伺服电机周期最低多少?最大支持几个轴?协议栈是内置的吗?

      问:SylixOS 支持伺服电机周期最低多少? 答:伺服周期不限,一般伺服的 250 us ,125 us 我们都支持。 问:SylixOS 最大支持几个轴? 答:轴数理论上是 65535 个 ,我们现在客户最多用了 20 几个。 问:SylixOS 协议栈是内置的吗? 答:协议栈直接是主站内置 ,不需要扩展板卡。
    • SylixOS 协议栈学习(一)网络接口结构

             1) netif 的结构体来描述一个硬件网络接口的。     struct netif {                                                         struct netif *next;    // 指向下一个 netif 结构的指针         struct ip_addr ip_addr;    // IP 地址相关配置         struct ip_addr netmask;         struct ...