LwIP協議棧(2):網絡接口

  在LwIP中,物理網絡硬件接口結構保存在一個全局鏈表中,它們通過結構體中的 next 指針連接。

struct netif {
  /// pointer to next in linked list */
  struct netif *next;

  /// IP address configuration in network byte order */
  ip_addr_t ip_addr; //IP地址
  ip_addr_t netmask; //子網掩碼
  ip_addr_t gw;      //網關地址


  netif_input_fn input; //設備驅動調用該函數傳遞一個包給TCP/IP協議棧

  //IP模塊調用該函數傳遞一個包給網卡,output 函數的第三個參數 ipaddr 是應該接收實際的鏈路層幀的主機的 IP 地址。
  //它不必與 IP 信息包的目的地址相同。特別地,當要發送 IP 信息包到一個並不在本地網絡裏的主機上時,鏈路層幀會被髮送到網絡裏的一個路由器上。
  //在這種情況下給output函數的IP地址將是這個路由器的地址。
  netif_output_fn output; 

  netif_linkoutput_fn linkoutput; //ARP模塊調用該函數傳遞一個包給網卡

  void *state; //由設備驅動設置,指向設備狀態信息
#if LWIP_DHCP
  /// the DHCP client state information for this netif */
  struct dhcp *dhcp;
#endif // LWIP_DHCP */
#if LWIP_AUTOIP
  /// the AutoIP client state information for this netif */
  struct autoip *autoip;
#endif
#if LWIP_NETIF_HOSTNAME
  // the hostname for this netif, NULL is a valid value */
  char*  hostname;
#endif // LWIP_NETIF_HOSTNAME */

  u16_t mtu; //一次傳送的最大字節數,以太網一般爲1500

  u8_t hwaddr_len; //物理地址長度,一般是以太網MAC地址長度,6字節

  u8_t hwaddr[NETIF_MAX_HWADDR_LEN]; //物理地址,一般是以太網MAC地址
  /// flags (see NETIF_FLAG_ above) */
  u8_t flags; //使能標誌符,比如設置NETIF_FLAG_LINK_UP,接收到數據包纔會向上傳
  /// descriptive abbreviation */
  char name[2]; //設備驅動類型
  /// number of this interface */
  u8_t num;

    // List of packets to be queued for ourselves. */
  struct pbuf *loop_first; //環回,指向發給自己數據包的第一個pbuf
  struct pbuf *loop_last;  //環回,指向發給自己數據包的最後一個pbuf
};
/*
 * Add a network interface to the list of lwIP netifs.
 *
 * @param netif a pre-allocated netif structure
 * @param ipaddr IP address for the new netif
 * @param netmask network mask for the new netif
 * @param gw default gateway IP address for the new netif
 * @param state opaque data passed to the new netif
 * @param init callback function that initializes the interface
 * @param input callback function that is called to pass
 * ingress packets up in the protocol layer stack.
 *
 * @return netif, or NULL if failed.
 */
struct netif *
netif_add(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask,
  ip_addr_t *gw, void *state, netif_init_fn init, netif_input_fn input)
{
  static u8_t netifnum = 0;

  // reset new interface configuration state */
  ip_addr_set_zero(&netif->ip_addr);
  ip_addr_set_zero(&netif->netmask);
  ip_addr_set_zero(&netif->gw);
  netif->flags = 0;

  // remember netif specific state information data */
  netif->state = state;
  netif->num = netifnum++;
  netif->input = input;

  netif_set_addr(netif, ipaddr, netmask, gw);

  // call user specified initialization function for netif */
  if (init(netif) != ERR_OK) { //用戶自定義初始化函數
    return NULL;
  }

  // add this netif to the list */
  netif->next = netif_list;
  netif_list = netif;
  snmp_inc_iflist();

  return netif;
}

//用戶自定義初始化函數
err_t ethernetif_init(struct netif *netif) 
{
  netif->name[0] = IFNAME0;   //比如藍牙設備(bluetooth)的網絡接口可以是bt,隨便啦
  netif->name[1] = IFNAME1; 
  netif->output = etharp_output;  //IP模塊發送數據包函數
  netif->linkoutput = low_level_output; // //ARP模塊發送數據包函數
  low_level_init(netif); //底層硬件初始化函數
  return ERR_OK;
}

static void low_level_init(struct netif *netif)
{
  netif->hwaddr_len = ETHARP_HWADDR_LEN; //設置MAC地址長度

  netif->hwaddr[0] = 'F'; //設置網卡MAC地址
  netif->hwaddr[1] = 'O'; 
  netif->hwaddr[2] = 'R'; 
  netif->hwaddr[3] = 'E';
  netif->hwaddr[4] = 'S';
  netif->hwaddr[5] = 'T';

  netif->mtu = 1500; //最大允許傳輸單元

  //允許該網卡的廣播和ARP功能,並且該網卡允許有硬件鏈路連接
  netif->flags = NETIF_FLAG_BROADCAST | \
  NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;

  E1280_init(netif->hwaddr); //具體網卡初始化函數
}

/*
 * Send an IP packet to be received on the same netif (loopif-like).
 * The pbuf is simply copied and handed back to netif->input.
 * In multithreaded mode, this is done directly since netif->input must put
 * the packet on a queue.
 * In callback mode, the packet is put on an internal queue and is fed to
 * netif->input by netif_poll().
 *
 * @param netif the lwip network interface structure
 * @param p the (IP) packet to 'send'
 * @param ipaddr the ip address to send the packet to (not used)
 * @return ERR_OK if the packet has been sent
 *         ERR_MEM if the pbuf used to copy the packet couldn't be allocated
 */
err_t
netif_loop_output(struct netif *netif, struct pbuf *p,
       ip_addr_t *ipaddr)
{
  struct pbuf *r;
  err_t err;
  struct pbuf *last;


  SYS_ARCH_DECL_PROTECT(lev);
  LWIP_UNUSED_ARG(ipaddr);

  // Allocate a new pbuf */
  r = pbuf_alloc(PBUF_LINK, p->tot_len, PBUF_RAM);
  if (r == NULL) {
    return ERR_MEM;
  }

  // Copy the whole pbuf queue p into the single pbuf r */
  if ((err = pbuf_copy(r, p)) != ERR_OK) { //拷貝要發送的數據到r中
    pbuf_free(r);
    return err;
  }

  // Put the packet on a linked list which gets emptied through calling
     netif_poll(). */ 
  //可以調用netif_poll函數將當前loop鏈表上所有數據提交給IP層

  // let last point to the last pbuf in chain r */
  for (last = r; last->next != NULL; last = last->next); 

  SYS_ARCH_PROTECT(lev);
  if(netif->loop_first != NULL) { //原來的loop中還有數據
    netif->loop_last->next = r;   //接到原來數據的後面
    netif->loop_last = last;
  } else {
    netif->loop_first = r;
    netif->loop_last = last;
  }
  SYS_ARCH_UNPROTECT(lev);


  return ERR_OK;
}

/*
 * This function should be called when a packet is ready to be read
 * from the interface. It uses the function low_level_input() that
 * should handle the actual reception of bytes from the network
 * interface. Then the type of the received packet is determined and
 * the appropriate input function is called.
 *
 * @param netif the lwip network interface structure for this ethernetif
 */
static void
ethernetif_input(struct netif *netif)
{
  struct ethernetif *ethernetif;
  struct eth_hdr *ethhdr;
  struct pbuf *p;

  ethernetif = netif->state;

  // move received packet into a new pbuf */
  p = low_level_input(netif);
  // no packet could be read, silently ignore this */
  if (p == NULL) return;
  // points to packet payload, which starts with an Ethernet header */
  ethhdr = p->payload;

  switch (htons(ethhdr->type)) {
  // IP or ARP packet? */
  case ETHTYPE_IP:
  case ETHTYPE_ARP:
#if PPPOE_SUPPORT
  // PPPoE packet? */
  case ETHTYPE_PPPOEDISC:
  case ETHTYPE_PPPOE:
#endif // PPPOE_SUPPORT */
    // full packet send to tcpip_thread to process */
    if (netif->input(p, netif)!=ERR_OK)
     { LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n"));
       pbuf_free(p);
       p = NULL;
     }
    break;

  default:
    pbuf_free(p);
    p = NULL;
    break;
  }
}

/*
 * This function should be called when a packet is ready to be read
 * from the interface. It uses the function low_level_input() that
 * should handle the actual reception of bytes from the network
 * interface. Then the type of the received packet is determined and
 * the appropriate input function is called.
 *
 * @param netif the lwip network interface structure for this ethernetif
 */
static void
ethernetif_input(struct netif *netif)
{
  struct ethernetif *ethernetif;
  struct eth_hdr *ethhdr;
  struct pbuf *p;

  ethernetif = netif->state;

  // move received packet into a new pbuf */
  p = low_level_input(netif); //拷貝接收到的數據到一個新的pbuf
  // no packet could be read, silently ignore this */
  if (p == NULL) return;
  // points to packet payload, which starts with an Ethernet header */
  ethhdr = p->payload;

  switch (htons(ethhdr->type)) {
  // IP or ARP packet? */
  case ETHTYPE_IP:
  case ETHTYPE_ARP:
    // full packet send to tcpip_thread to process */
    if (netif->input(p, netif)!=ERR_OK) //調用上層(IP/ARP)函數進行處理
     { 
       pbuf_free(p);
       p = NULL;
     }
    break;

  default:
    pbuf_free(p);
    p = NULL;
    break;
  }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章