Chinaunix首页 | 论坛 | 博客
  • 博客访问: 713761
  • 博文数量: 104
  • 博客积分: 4320
  • 博客等级: 上校
  • 技术积分: 1948
  • 用 户 组: 普通用户
  • 注册时间: 2010-05-30 14:42
文章分类

全部博文(104)

文章存档

2012年(4)

2011年(65)

2010年(35)

分类: LINUX

2010-07-21 17:04:44

  结构体net_device代表了一个网络设备接口,它是我们理解网络设备驱动程序的关键。这里,我们选择其中的一些重要成员,一一作详细分析,并结合以太网设备,看看Linux内核是如何为以太网设备提供结构体中某些成员的缺省值的。
    在Linux内核源代码中是这样为这个结构体作注释的:实际上,这个结构体是一个很大的错误,它把I/O数据和更高层的数据混合在一起,而且它几乎必须知道INET模块中的每个数据结构。
    毫无疑问,这是一个巨型结构体。但我们为编写网络设备驱动程序,只需要了解其中的一部分,下面选择其中的一些作分析,并给出以太网设备的缺省值。
   
unsigned short  flags;
void (*set_multicast_list)(struct net_device *dev);
    这是一个接口标志,包含了很多值的位掩码。在以太网的缺省初始化函数中,该标志被设置为:IFF_BROADCAST|IFF_MULTICAST,表示以太网卡是可广播的,并且是能够进行组播发送的。另外,该标志接口还有一些只读标志,如IFF_UP,当接口被激活并可以开始传输数据包时,内核设置该标志。而IFF_PROMISC被设置或清除时,会调用set_multicast_list函数通知板卡上的硬件过滤器。

unsigned short hard_header_len;
unsigned short type;
    hard_header_len是硬件头的长度,在以太网设备的初始化函数中,该成员被赋为ETH_HLEN,即以太网头的长度,该值为14,下面是以太网头的定义:
struct ethhdr {
    unsigned char   h_dest[ETH_ALEN];   /* destination eth addr */
    unsigned char   h_source[ETH_ALEN]; /* source ether addr    */
    unsigned short  h_proto;        /* packet type ID field */
} __attribute__((packed));
    ETH_ALEN被定义为6,即以太网MAC地址的长度。h_proto保存type的值。type是接口的硬件类型,以太网设备的初始化函数中将其赋值为ARPHRD_ETHER,即10Mb以太网。

int (*hard_header) (struct sk_buff *skb, struct net_device *dev,
                unsigned short type, void *daddr,void *saddr,
                unsigned len);
    该函数在数据被传输之前被调用,它根据先前检索到的源和目标地址建立硬件头。以太网设备的默认函数是eth_header:
int eth_header(struct sk_buff *skb, struct net_device *dev,
                unsigned short type, void *daddr,
                void *saddr, unsigned len)
{
    struct ethhdr *eth = (struct ethhdr *)skb_push(skb,ETH_HLEN);

    /*
     *  Set the protocol type. For a packet of
     *  type ETH_P_802_3 we put the length
     *  in here instead. It is up to the 802.2
     *  layer to carry protocol information.
     */
    if(type!=ETH_P_802_3)
        eth->h_proto = htons(type);
    else
        eth->h_proto = htons(len);

    //Set the source hardware address.
    if(!saddr)
        saddr = dev->dev_addr;
    memcpy(eth->h_source,saddr,dev->addr_len);
    //Anyway, the loopback-device should never
    //use this function...
    if (dev->flags & (IFF_LOOPBACK|IFF_NOARP)){
        memset(eth->h_dest, 0, dev->addr_len);
        return ETH_HLEN;
    }

    if(daddr){
        memcpy(eth->h_dest,daddr,dev->addr_len);
        return ETH_HLEN;
    }
    return -ETH_HLEN;
}
    它根据传入的参数建立以太网头,如果传入的源地址为空,则使用设备的地址作为源地址。与之相关的还有一个int (*rebuild_header)(struct sk_buff *skb)函数,在以太网设备中,它是用于在ARP地址解析完成以后,重新建立以太网头,主要是更新目标MAC地址,因为在前一次建立时,由于没有经过 ARP协议,有可能目标MAC地址是错误的(未完,待续)。
阅读(748) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~