dm9000

static void
dm9000_rx(struct net_device *dev)
{
    board_info_t *db = netdev_priv(dev);
    struct dm9000_rxhdr rxhdr;     /* 该结构体按照DM9000的接收格式封装了dm9000接收的数据包信息 */ 
    struct sk_buff *skb;
    u8 rxbyte, *rdptr;
    bool GoodPacket;
    int RxLen;
 
    /* Check packet ready or not 
    判断包是否已经接收过来了。需要用到MRCMDX寄存器。*/
    do {
        ior(db, DM9000_MRCMDX);    /* Dummy read. MRCMDX : memory data read command without address increment register*/
                                                         //MRCMDX寄存器是存储数据读命令寄存器(地址不增加)
        /* Get most updated data */
        rxbyte = readb(db->io_data);
 
        /* Status check: this byte must be 0 or 1 */              //0、1为正确,2表示接收出错
        if (rxbyte & DM9000_PKT_ERR) {
            dev_warn(db->dev, "status check fail: %d
", rxbyte);
            iow(db, DM9000_RCR, 0x00);    /* Stop Device */
            iow(db, DM9000_ISR, IMR_PAR);    /* Stop INT request */
            return;
        }
 
        if (!(rxbyte & DM9000_PKT_RDY))           //0x01 没有准备好,直接返回*/ 
            return;
 
        /* A packet ready now  & Get status/length */
        GoodPacket = true;
        writeb(DM9000_MRCMD, db->io_addr);    /* MRCMD是地址增加的数据读取命令 读指针自动增加*/ 
 
        (db->inblk)(db->io_data, &rxhdr, sizeof(rxhdr));      //一次性读入四个字节的内容到rxhdr变量
                                                                                          //这四个字节是存储在RX_SRAM中的每个包的信息头
        RxLen = le16_to_cpu(rxhdr.RxLen);
 
        if (netif_msg_rx_status(db))
            dev_dbg(db->dev, "RX: status %02x, length %04x
",
                rxhdr.RxStatus, RxLen);
 
        /* Packet Status check */            //检查包的完整性,需要用到MRCMD寄存器,
        if (RxLen < 0x40) {                     //因为数据读取到struct dm9000_rxhdr rxhdr;中,RXLEn为其成员
            GoodPacket = false;
            if (netif_msg_rx_err(db))
                dev_dbg(db->dev, "RX: Bad Packet (runt)
");
        }
 
        if (RxLen > DM9000_PKT_MAX) {               //同上,检查包的大小如果数据长度大于DM9000_PKT_MAX ,即 1536 
            dev_dbg(db->dev, "RST: RX Len:%x
", RxLen);
        }
 
        /* rxhdr.RxStatus is identical to RSR register. */     //也是检查包
        if (rxhdr.RxStatus & (RSR_FOE | RSR_CE | RSR_AE |               //这里是RSR寄存器中各位对接收的校验
                      RSR_PLE | RSR_RWTO |
                      RSR_LCS | RSR_RF)) {
            GoodPacket = false;
            if (rxhdr.RxStatus & RSR_FOE) {
                if (netif_msg_rx_err(db))
                    dev_dbg(db->dev, "fifo error
");
                dev->stats.rx_fifo_errors++;
            }
            if (rxhdr.RxStatus & RSR_CE) {
                if (netif_msg_rx_err(db))
                    dev_dbg(db->dev, "crc error
");
                dev->stats.rx_crc_errors++;
            }
            if (rxhdr.RxStatus & RSR_RF) {
                if (netif_msg_rx_err(db))
                    dev_dbg(db->dev, "length error
");
                dev->stats.rx_length_errors++;
            }
        }
 
        /* Move data from DM9000 */
         /*关键的代码就是这里。使用到了上面提到的sk_buff。将RX SRAM中的
         data段数据放入sk_buff,然后发送给上层,至于怎么发送,不用去驱动
         操心了。sk_buff的protocol全部搞定*/  
 
        if (GoodPacket &&
            ((skb = netdev_alloc_skb(dev, RxLen + 4)) != NULL)) {          //分配一个skbuff给网络设备的接收
            skb_reserve(skb, 2);                                                  
            rdptr = (u8 *) skb_put(skb, RxLen - 4);          
 
            /* Read received packet from RX SRAM */
                   //读取数据 从RX SRAM 到sk_buff中
            (db->inblk)(db->io_data, rdptr, RxLen);
            dev->stats.rx_bytes += RxLen;
 
            /* Pass to upper layer */          //获取上层协议类型
            skb->protocol = eth_type_trans(skb, dev);        //eth_type_trans判断数据帧的类型,及协议类型
            if (dev->features & NETIF_F_RXCSUM) {
                if ((((rxbyte & 0x1c) << 3) & rxbyte) == 0)
                    skb->ip_summed = CHECKSUM_UNNECESSARY;
                else
                    skb_checksum_none_assert(skb);
            }
            netif_rx(skb);                      //将skbuff结构体交给上层
            dev->stats.rx_packets++;   //计数加1
 
        }
        else {
         // 坏包,丢弃
            /* need to dump the packet's data */
                      
            (db->dumpblk)(db->io_data, RxLen);
        }
    } while (rxbyte & DM9000_PKT_RDY);
}
 

单播MAC地址

单播MAC地址保存在net_device结构体的uc链表中,函数dev_uc_add负责添加单播MAC地址。由其在内核代码的调用可以看到目前vlan设备、macvlan设备、ipvlan设备与macsec设备等在添加单播MAC地址。

无论是单播MAC还是多播MAC都是用作MAC地址的接收过滤来使用,具体由函数__dev_set_rx_mode进行设置。将需要过滤的MAC地址下发到网驱动处理,例如e1000驱动中的e1000_set_rx_mode函数。但是,对于不支持单播过滤的网卡,有两种处理情况:1)如果存在MAC地址需要过滤,打开设备的混杂接收模式;2)如果没有MAC地址需过滤,关闭混杂模式。

非混杂模式下,仅接收目的MAC与net_device结构中dev_addr值相同的数据包。

int dev_uc_add(struct net_device *dev, const unsigned char *addr)
{
    err = __hw_addr_add(&dev->uc, addr, dev->addr_len, NETDEV_HW_ADDR_T_UNICAST);
    if (!err)
        __dev_set_rx_mode(dev);
}

多播MAC地址

多播MAC地址保存在net_device结构体的mc链表中,由函数dev_mc_add负责添加多播MAC地址。与单播MAC地址相同,通过__dev_set_rx_mode函数可以设置网卡的多播地址接收过滤功能。

static int __dev_mc_add(struct net_device *dev, const unsigned char *addr, bool global)
{
    err = __hw_addr_add_ex(&dev->mc, addr, dev->addr_len, NETDEV_HW_ADDR_T_MULTICAST, global, false, 0);
    if (!err)
        __dev_set_rx_mode(dev);
}

网络设备的MAC地址

原文地址:https://www.cnblogs.com/dream397/p/15124651.html