LwIP 代码分析(etharp_output再深入) – 第五集

/ 0评 / 0

之前说etharp_output远远不是终点,听起来很吓人啊,不过确实的,终点其实是low_level_output,不对,其实是ETH->DMATPDR = 0,但是我们只要看到low_level_output就行了,那里数据包已经全部构建完成了.
简化后就是这样:

err_t
etharp_output(struct netif *netif, struct pbuf *q, const ip4_addr_t *ipaddr)
{
    const struct eth_addr *dest;
    struct eth_addr mcastaddr;
    const ip4_addr_t *dst_addr = ipaddr;
    if (ip4_addr_isbroadcast(ipaddr, netif))
    {
        /* 如果是广播包.MAC设置成全0xFF就行. */
    }
    else if (ip4_addr_ismulticast(ipaddr))
    {
        /* 多播处理,OUI前三位设置成多播用就行. */
    }
    else     /* 否则正常包. */
    {
        s8_t i;
        /* 从ARP缓存找. */
        if ((arp_table[etharp_cached_entry].state >= ETHARP_STATE_STABLE) &&
                (ip4_addr_cmp(dst_addr, &arp_table[etharp_cached_entry].ipaddr)))
        {
            ETHARP_STATS_INC(etharp.cachehit);
            return etharp_output_to_arp_index(netif, q, etharp_cached_entry);
        }
        /* 从所有ARP列表再找(第一步找不到) */
        for (i = 0; i < ARP_TABLE_SIZE; i++)
        {
            if ((arp_table[i].state >= ETHARP_STATE_STABLE) &&
                    (ip4_addr_cmp(dst_addr, &arp_table[i].ipaddr)))
            {
                ETHARP_SET_HINT(netif, i);
                return etharp_output_to_arp_index(netif, q, i);
            }
        }
        /* 如果不行,只能去公网问了. */
        return etharp_query(netif, dst_addr, q);
    }
    /* 除了广播和多播,都不会来这里.因为早return了. */
    return ethernet_output(netif, q, (struct eth_addr *)(netif->hwaddr), dest, ETHTYPE_IP);
}

除了第一次查询,其后缓存中都会有,我们就假设都有缓存把.这就说明无论如何都会到etharp_output_to_arp_index.并且假设他们在ARP表中都是靠谱的.那么直接到ethernet_output.

一下子攻破了两个函数,最后红框处添加以太网头.

以太网头很简单,就是SRC和DST,然后和类型.然后整个帧就OK了.到netif->linkoutput(netif, p),也就是lowlevel_input.
如图,以太网帧.

IP帧

UDP帧

一个包,就这么发出去了.后面的00,是补充,这个后话再说了.
 

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注