Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1879284
  • 博文数量: 376
  • 博客积分: 2147
  • 博客等级: 大尉
  • 技术积分: 3642
  • 用 户 组: 普通用户
  • 注册时间: 2012-02-06 10:47
文章分类

全部博文(376)

文章存档

2019年(3)

2017年(28)

2016年(15)

2015年(17)

2014年(182)

2013年(16)

2012年(115)

我的朋友

分类: 嵌入式

2014-01-06 16:41:39

为了用户方便查看 brcm设备的工作状态,使用proc文件系统是很好的方式。一个网络协议模块可以注册到网络空间中register_pernet_subsys(), 这个函数会为子空间分配一个id号,通过id可以在网络空间中找到分配给该子空间的内存:init_net->gen->ptr[id - 1]。而我们正是利用这块内存去存储proc中的相关信息:struct brcm_net,它记录了brcm设备在proc文件系统中的位置。
  1. struct brcm_net {  
  2.     /* /proc/net/brcm */  
  3.     struct proc_dir_entry *proc_brcm_dir;  
  4.     /* /proc/net/brcm/config */  
  5.     struct proc_dir_entry *proc_brcm_conf;  
  6. };  

        在加载brcm模块时会注册子空间,brcm_init_net创建在proc中的相关项,并记录路径在brcm_net中;brcm_exit_net 删除在proc中的相关项;brcm_net_id记录分配给子空间的id,这样通过 init_net->gen->ptr[brcm_net_id - 1]就可以操作brcm_net了。

  1. err = register_pernet_subsys(&brcm_net_ops);  
  2. static struct pernet_operations brcm_net_ops = {  
  3.     .init = brcm_init_net,  
  4.     .exit = brcm_exit_net,  
  5.     .id = &brcm_net_id,  
  6.     .size = sizeof(struct brcm_net),  
  7. };  

        注意到在brcm_init_net和brcm_exit_net中添加和删除的仅仅是/proc/net/brcm目录和config文件,而在使用中 brcm设备是可以动态创建的,因此这部分代码应该发生在添加和删除brcm设备时,而不是在brcm模块注册和删除时。最简单的是直接添加在 register方法或unregister方法中,但内核提供了更好的机制:事件,将对proc的操作分离出来,因为proc的操作实际上属于附加的操 作而不是必须的操作。下面就来看event机制。
        前面几篇已经有描述过event机制,这里的事件都是关于设备的事件,使用的是register_netdevice_notifier()来,注册 notifier到netdev_chain链表上。在加载brcm模块时注册notifier,brcm_notifier_block包含了brcm 设备对所关心的事件作出的反应。

  1. err = register_netdevice_notifier(&brcm_notifier_block);  
  2. static struct notifier_block brcm_notifier_block __read_mostly = {  
  3.     .notifier_call = brcm_device_event,  
  4. };  

        设备对哪些事件会感兴趣,首先,brcm设备对注册和注销是感兴趣的,要操作proc文件系统;其次,对于发往brcm下层设备的事件,要考虑这些事件造 成的连带影响(比如eth1被down掉,则其上的brcm设备也应该被down掉),一般是下层设备的事件对其上的所有brcm设备都进行相应操作。
        所以在brcm_device_event有两类进入的设备dev会进行操作,一类是brcm设备,它仅仅是操作proc文件系统。判断是否为brcm设备,是的话则由__brcm_device_event() 处理。 

  1. if (is_brcm_dev(dev))  
  2.     __brcm_device_event(dev, event);  
  3.   
  4. static void __brcm_device_event(struct net_device *dev, unsigned long event)  
  5. {  
  6.     switch (event) {  
  7.     case NETDEV_CHANGENAME:  
  8.         brcm_proc_rem_dev(dev);  
  9.         if (brcm_proc_add_dev(dev) < 0)  
  10.             pr_warning("BRCM: failed to change proc name for %s\n",  
  11.                     dev->name);  
  12.         break;  
  13.     case NETDEV_REGISTER:  
  14.         if (brcm_proc_add_dev(dev) < 0)  
  15.             pr_warning("BRCM: failed to add proc entry for %s\n",  
  16.                     dev->name);  
  17.         break;  
  18.     case NETDEV_UNREGISTER:  
  19.         brcm_proc_rem_dev(dev);  
  20.         break;  
  21.     }  
  22. }  

        如何是brcm的下层设备,如根据brcm_group_hash中的映射关系,对下层设备相关的所有brcm设备进行操作:

  1. switch (event) {  
  2. case NETDEV_CHANGE:  
  3.     /* Propagate real device state to vlan devices */  
  4.     for (i = 0; i < BRCM_GROUP_ARRAY_LEN; i++) {  
  5.         brcmdev = brcm_group_get_device(grp, i);  
  6.         if (!brcmdev)  
  7.             continue;  
  8.   
  9.         netif_stacked_transfer_operstate(dev, brcmdev);  
  10.     }  
  11.     break;  
  12.   
  13. case NETDEV_CHANGEADDR:  
  14.     /* Adjust unicast filters on underlying device */  
  15.     for (i = 0; i < BRCM_GROUP_ARRAY_LEN; i++) {  
  16.         brcmdev = brcm_group_get_device(grp, i);  
  17.         if (!brcmdev)  
  18.             continue;  
  19.   
  20.         flgs = brcmdev->flags;  
  21.         if (!(flgs & IFF_UP))  
  22.             continue;  
  23.   
  24.         brcm_sync_address(dev, brcmdev);  
  25.     }  
  26.     break;  
  27.   
  28. case NETDEV_CHANGEMTU:  
  29.     for (i = 0; i < BRCM_GROUP_ARRAY_LEN; i++) {  
  30.         brcmdev = brcm_group_get_device(grp, i);  
  31.         if (!brcmdev)  
  32.             continue;  
  33.   
  34.         if (brcmdev->mtu <= dev->mtu)  
  35.             continue;  
  36.   
  37.         dev_set_mtu(brcmdev, dev->mtu);  
  38.     }  
  39.     break;  
  40.   
  41. case NETDEV_DOWN:  
  42.     /* Put all VLANs for this dev in the down state too.  */  
  43.     for (i = 0; i < BRCM_GROUP_ARRAY_LEN; i++) {  
  44.         brcmdev = brcm_group_get_device(grp, i);  
  45.         if (!brcmdev)  
  46.             continue;  
  47.   
  48.         flgs = brcmdev->flags;  
  49.         if (!(flgs & IFF_UP))  
  50.             continue;  
  51.   
  52.         brcm = brcm_dev_info(brcmdev);  
  53.         dev_change_flags(brcmdev, flgs & ~IFF_UP);  
  54.         netif_stacked_transfer_operstate(dev, brcmdev);  
  55.     }  
  56.     break;  
  57.   
  58. case NETDEV_UP:  
  59.     /* Put all VLANs for this dev in the up state too.  */  
  60.     for (i = 0; i < BRCM_GROUP_ARRAY_LEN; i++) {  
  61.         brcmdev = brcm_group_get_device(grp, i);  
  62.         if (!brcmdev)  
  63.             continue;  
  64.   
  65.         flgs = brcmdev->flags;  
  66.         if (flgs & IFF_UP)  
  67.             continue;  
  68.   
  69.         brcm = brcm_dev_info(brcmdev);  
  70.         dev_change_flags(brcmdev, flgs | IFF_UP);  
  71.         netif_stacked_transfer_operstate(dev, brcmdev);  
  72.     }  
  73.     break;  
  74.   
  75. case NETDEV_UNREGISTER:  
  76.     /* Delete all BRCMs for this dev. */  
  77.     grp->killall = 1;  
  78.   
  79.     for (i = 0; i < BRCM_GROUP_ARRAY_LEN; i++) {  
  80.         brcmdev = brcm_group_get_device(grp, i);  
  81.         if (!brcmdev)  
  82.             continue;  
  83.   
  84.         /* unregistration of last brcm destroys group, abort 
  85.          * afterwards */  
  86.         if (grp->nr_ports == 1)  
  87.             i = BRCM_GROUP_ARRAY_LEN;  
  88.   
  89.         unregister_brcm_dev(brcmdev, &list);  
  90.     }  
  91.     unregister_netdevice_many(&list);  
  92.     break;  
  93. }  

        到这里,协议的添加就大致完成了,当然还包括一些头文件的修改,宏变量的添加等就不一一详述,具体可见最后的附件。
        为了编译进内核,还需要修改以下文件:
              $(linux)/net/Kconfig  $(linux)/net/Makefile

        最后,在make menuconfig选择添加brcm协议
              Networking Support -> Networking options     
  

        同时,需要一个简单的用户空间工具来配置我们的brcm设备,就像vconfig用来配置vlan设备一样;编写的简单的bconfig工具,命令格式:
                "Usage: add [interface-name] [brcm_port]\n"
                "       rem [dev-name]";

        内核编译完成后就该进行测试了,如果开启了内核调试信息,启动内核就看到以下信息: 

        然后启用网卡,可以查看到添加了brcm设备后的状态: 

        可以使用原生套接字自己打上brcm头后发送报文让协议栈接收,或者用wireshark等捕获协议栈发出的报文,下图即是捕获到的报文: 

        这是主机发出的arp报文,可以看到,在源mac后接的不是vlan报头,而是我们添加的brcm报文,协议号是8744。
        查看proc中信息:
 

        :patch补丁 && 重要的源文件 && bconfig工具源码

阅读(719) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~