Linux Wireless架构总结

1、无线网络驱动(ath9k_htc)

     ath9k_htc是一个基于USB接口的SoftMAC无线网络适配器。为了其驱动能正常工作,首先必须调用usb_register来注册驱动定义的usb_driver,以借助USB Core的力量来处理与USB协议相关的事件。其代码如下:
static struct usb_driver ath9k_hif_usb_driver = {  
    .name = KBUILD_MODNAME,  
    .probe = ath9k_hif_usb_probe,  
    .disconnect = ath9k_hif_usb_disconnect,  
#ifdef CONFIG_PM  
    .suspend = ath9k_hif_usb_suspend,  
    .resume = ath9k_hif_usb_resume,  
    .reset_resume = ath9k_hif_usb_resume,  
#endif  
    .id_table = ath9k_hif_usb_ids,  
    .soft_unbind = 1,  
};  


2. 关键数据结构

1) struct ieee80211_hw: 它包含802.11 PHY的配置和硬件信息





2.1 各层间关键数据接口




3、USB无线适配器枚举过程 

     当此基于USB接口的无线网络适配器被枚举时,ath9k_hif_usb_probe将被调用。其调用流程如下图所示:




3.1 struct ieee80211_ops 实例 ath9k_htc_ops(驱动实现)

       ath9k_htc_ops: mac80211通过这些回调函数回调driver的处理函数。ath9k_htc为了接受mac80211的管理,它必须首先向mac80211注册,以申明自己的存在,从而可以接受mac80211的调用。

struct ieee80211_ops ath9k_htc_ops = {  
    .tx                 = ath9k_htc_tx,  // 发送mac80211要求发送的帧  
    .start              = ath9k_htc_start, // 第一个被attach到此硬件的net_device被enable之前被调用,之后,可以接收帧数据  
    .stop               = ath9k_htc_stop,  // 最后一个被attach到此硬件的net_device被disable之后被调用,之后,不可以接收帧数据  
    .add_interface      = ath9k_htc_add_interface, // 当一个被attach到此硬件的net_device被enable时被调用  
    .remove_interface   = ath9k_htc_remove_interface, // 通知driver一个接口将要going down  
    .config             = ath9k_htc_config,           // mac802.11调用它修改硬件配置  
    .configure_filter   = ath9k_htc_configure_filter, // 配置设备的接收过滤器  
    .sta_add            = ath9k_htc_sta_add,  
    .sta_remove         = ath9k_htc_sta_remove,  
    .conf_tx            = ath9k_htc_conf_tx,  
    .bss_info_changed   = ath9k_htc_bss_info_changed,  
    .set_key            = ath9k_htc_set_key,  
    .get_tsf            = ath9k_htc_get_tsf,  
    .set_tsf            = ath9k_htc_set_tsf,  
    .reset_tsf          = ath9k_htc_reset_tsf,  
    .ampdu_action       = ath9k_htc_ampdu_action,  
    .sw_scan_start      = ath9k_htc_sw_scan_start,  
    .sw_scan_complete   = ath9k_htc_sw_scan_complete,  
    .set_rts_threshold  = ath9k_htc_set_rts_threshold,  
    .rfkill_poll        = ath9k_htc_rfkill_poll_state,  
    .set_coverage_class = ath9k_htc_set_coverage_class,  
    .set_bitrate_mask   = ath9k_htc_set_bitrate_mask,  
};  


3.2 struct cfg80211_ops 实例 mac80211_config_ops(mac80211实现)  

   cfg80211_ops定义了无线配置的操作,在它的增加虚拟接口(ieee80211_add_iface)中,它将创建并注册net_device。在mac80211中,其定义如下所示:

struct cfg80211_ops mac80211_config_ops = {  
    .add_virtual_intf = ieee80211_add_iface, //使用给定的名字创建一个"虚拟接口",在wiphy的命名空间中创建net_device并返回  
    .del_virtual_intf = ieee80211_del_iface, //删除由ifindex指定的"虚拟接口"  
    .change_virtual_intf = ieee80211_change_iface,  
    .add_key = ieee80211_add_key,  
    .del_key = ieee80211_del_key,  
    .get_key = ieee80211_get_key,  
    .set_default_key = ieee80211_config_default_key,  
    .set_default_mgmt_key = ieee80211_config_default_mgmt_key,  
    .add_beacon = ieee80211_add_beacon,  
    .set_beacon = ieee80211_set_beacon,  
    .del_beacon = ieee80211_del_beacon,  
    .add_station = ieee80211_add_station,  
    .del_station = ieee80211_del_station,  
    .change_station = ieee80211_change_station,  
    .get_station = ieee80211_get_station,  
    .dump_station = ieee80211_dump_station,  
    .dump_survey = ieee80211_dump_survey,  
#ifdef CONFIG_MAC80211_MESH  
    .add_mpath = ieee80211_add_mpath,  
    .del_mpath = ieee80211_del_mpath,  
    .change_mpath = ieee80211_change_mpath,  
    .get_mpath = ieee80211_get_mpath,  
    .dump_mpath = ieee80211_dump_mpath,  
    .update_mesh_config = ieee80211_update_mesh_config,  
    .get_mesh_config = ieee80211_get_mesh_config,  
    .join_mesh = ieee80211_join_mesh,  
    .leave_mesh = ieee80211_leave_mesh,  
#endif  
    .change_bss = ieee80211_change_bss,  
    .set_txq_params = ieee80211_set_txq_params,  
    .set_channel = ieee80211_set_channel,  
    .suspend = ieee80211_suspend,  
    .resume = ieee80211_resume,  
    .scan = ieee80211_scan,  
    .sched_scan_start = ieee80211_sched_scan_start,  
    .sched_scan_stop = ieee80211_sched_scan_stop,  
    .auth = ieee80211_auth,  
    .assoc = ieee80211_assoc,  
    .deauth = ieee80211_deauth,  
    .disassoc = ieee80211_disassoc,  
    .join_ibss = ieee80211_join_ibss,  
    .leave_ibss = ieee80211_leave_ibss,  
    .set_wiphy_params = ieee80211_set_wiphy_params,  
    .set_tx_power = ieee80211_set_tx_power,  
    .get_tx_power = ieee80211_get_tx_power,  
    .set_wds_peer = ieee80211_set_wds_peer,  
    .rfkill_poll = ieee80211_rfkill_poll,  
    CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd)  
    .set_power_mgmt = ieee80211_set_power_mgmt,  
    .set_bitrate_mask = ieee80211_set_bitrate_mask,  
    .remain_on_channel = ieee80211_remain_on_channel,  
    .cancel_remain_on_channel = ieee80211_cancel_remain_on_channel,  
    .mgmt_tx = ieee80211_mgmt_tx,  
    .mgmt_tx_cancel_wait = ieee80211_mgmt_tx_cancel_wait,  
    .set_cqm_rssi_config = ieee80211_set_cqm_rssi_config,  
    .mgmt_frame_register = ieee80211_mgmt_frame_register,  
    .set_antenna = ieee80211_set_antenna,  
    .get_antenna = ieee80211_get_antenna,  
    .set_ringparam = ieee80211_set_ringparam,  
    .get_ringparam = ieee80211_get_ringparam,  
}  


3.3 struct iw_handler_def  实例 cfg80211_wext_handler(wireless实现)

      cfg80211_wext_handler实现了wext要求的ioctl操作,将通过net_device->wireless_handlers->standard[ioctl cmd- SIOCIWFIRST]来进行调用。在net/wireless/wext-compat.c中的定义如下所示:

tatic const iw_handler cfg80211_handlers[] = {  
    [IW_IOCTL_IDX(SIOCGIWNAME)] = (iw_handler) cfg80211_wext_giwname,  
    [IW_IOCTL_IDX(SIOCSIWFREQ)] = (iw_handler) cfg80211_wext_siwfreq,  
    [IW_IOCTL_IDX(SIOCGIWFREQ)] = (iw_handler) cfg80211_wext_giwfreq,  
    [IW_IOCTL_IDX(SIOCSIWMODE)] = (iw_handler) cfg80211_wext_siwmode,  
    [IW_IOCTL_IDX(SIOCGIWMODE)] = (iw_handler) cfg80211_wext_giwmode,  
    [IW_IOCTL_IDX(SIOCGIWRANGE)]    = (iw_handler) cfg80211_wext_giwrange,  
    [IW_IOCTL_IDX(SIOCSIWAP)]   = (iw_handler) cfg80211_wext_siwap,  
    [IW_IOCTL_IDX(SIOCGIWAP)]   = (iw_handler) cfg80211_wext_giwap,  
    [IW_IOCTL_IDX(SIOCSIWMLME)] = (iw_handler) cfg80211_wext_siwmlme,  
    [IW_IOCTL_IDX(SIOCSIWSCAN)] = (iw_handler) cfg80211_wext_siwscan,  
    [IW_IOCTL_IDX(SIOCGIWSCAN)] = (iw_handler) cfg80211_wext_giwscan,  
    [IW_IOCTL_IDX(SIOCSIWESSID)]    = (iw_handler) cfg80211_wext_siwessid,  
    [IW_IOCTL_IDX(SIOCGIWESSID)]    = (iw_handler) cfg80211_wext_giwessid,  
    [IW_IOCTL_IDX(SIOCSIWRATE)] = (iw_handler) cfg80211_wext_siwrate,  
    [IW_IOCTL_IDX(SIOCGIWRATE)] = (iw_handler) cfg80211_wext_giwrate,  
    [IW_IOCTL_IDX(SIOCSIWRTS)]  = (iw_handler) cfg80211_wext_siwrts,  
    [IW_IOCTL_IDX(SIOCGIWRTS)]  = (iw_handler) cfg80211_wext_giwrts,  
    [IW_IOCTL_IDX(SIOCSIWFRAG)] = (iw_handler) cfg80211_wext_siwfrag,  
    [IW_IOCTL_IDX(SIOCGIWFRAG)] = (iw_handler) cfg80211_wext_giwfrag,  
    [IW_IOCTL_IDX(SIOCSIWTXPOW)]    = (iw_handler) cfg80211_wext_siwtxpower,  
    [IW_IOCTL_IDX(SIOCGIWTXPOW)]    = (iw_handler) cfg80211_wext_giwtxpower,  
    [IW_IOCTL_IDX(SIOCSIWRETRY)]    = (iw_handler) cfg80211_wext_siwretry,  
    [IW_IOCTL_IDX(SIOCGIWRETRY)]    = (iw_handler) cfg80211_wext_giwretry,  
    [IW_IOCTL_IDX(SIOCSIWENCODE)]   = (iw_handler) cfg80211_wext_siwencode,  
    [IW_IOCTL_IDX(SIOCGIWENCODE)]   = (iw_handler) cfg80211_wext_giwencode,  
    [IW_IOCTL_IDX(SIOCSIWPOWER)]    = (iw_handler) cfg80211_wext_siwpower,  
    [IW_IOCTL_IDX(SIOCGIWPOWER)]    = (iw_handler) cfg80211_wext_giwpower,  
    [IW_IOCTL_IDX(SIOCSIWGENIE)]    = (iw_handler) cfg80211_wext_siwgenie,  
    [IW_IOCTL_IDX(SIOCSIWAUTH)] = (iw_handler) cfg80211_wext_siwauth,  
    [IW_IOCTL_IDX(SIOCGIWAUTH)] = (iw_handler) cfg80211_wext_giwauth,  
    [IW_IOCTL_IDX(SIOCSIWENCODEEXT)]= (iw_handler) cfg80211_wext_siwencodeext,  
    [IW_IOCTL_IDX(SIOCSIWPMKSA)]    = (iw_handler) cfg80211_wext_siwpmksa,  
  [IW_IOCTL_IDX(SIOCSIWPRIV)] = (iw_handler)cfg80211_wext_setpriv  
};  
  
const struct iw_handler_def cfg80211_wext_handler = {  
    .num_standard       = ARRAY_SIZE(cfg80211_handlers),  
    .standard       = cfg80211_handlers,  
    .get_wireless_stats = cfg80211_wireless_stats,  


4、创建并注册net_device

             当执行mac80211_config_ops-> ieee80211_add_iface时,它将创建net_device和对应的ieee80211_sub_if_data, 然后主要做了以下几件事:

1) 把net_device对应的名字增加到/sys/class/net/目录下   
2) 把新创建的net_device插入到init_net->dev_base_head中
3) 通知上层协议,有一个新的net_device出现了,大家可以使用它了
4) 把新创建的ieee80211_sub_if_data增加到ieee80211_local的interfaces列表中        

其流程如下图所示:


  

mac80211中定义的net_device_ops ieee80211_dataif_ops,以下这些方法,都有一个struct net_device参数。其具体定义如下:   

static const struct net_device_ops ieee80211_dataif_ops = {  
    .ndo_open       = ieee80211_open,              // net_device变换到 UP 时被调用  
    .ndo_stop       = ieee80211_stop,              // net_device变换到 Down 时被调用  
    .ndo_uninit     = ieee80211_teardown_sdata,    // 取消注册或注册失败时调用  
    .ndo_start_xmit     = ieee80211_subif_start_xmit,  // 需要发送包时被调用  
    .ndo_set_multicast_list = ieee80211_set_multicast_list,// 多播地址列表变化时被调用  
    .ndo_change_mtu     = ieee80211_change_mtu,        // 当用户想改变一个设备的MTU时被调用  
    .ndo_set_mac_address    = ieee80211_change_mac,        // mac地址需要改变时被调用  
    .ndo_select_queue   = ieee80211_netdev_select_queue, //当net_device支持多个发送队列时,用来决定使用哪个队列  
};  


mac80211中初始化net_device->netdev_ops:

static void ieee80211_if_setup(struct net_device *dev)  
{  
    ether_setup(dev);  
    dev->priv_flags &= ~IFF_TX_SKB_SHARING;  
    dev->netdev_ops = &ieee80211_dataif_ops;  
    dev->destructor = free_netdev;  
}  


5. 数据接收(Data RX)流程

   数据接收流程如下图所示:



IP层与TCP/UDP层接口定义如下:

static const struct net_protocol tcp_protocol = {  
    .handler =  tcp_v4_rcv,  
    .err_handler =  tcp_v4_err,  
    .gso_send_check = tcp_v4_gso_send_check,  
    .gso_segment =  tcp_tso_segment,  
    .gro_receive =  tcp4_gro_receive,  
    .gro_complete = tcp4_gro_complete,  
    .no_policy =    1,  
    .netns_ok = 1,  
};  
  
static const struct net_protocol udp_protocol = {  
    .handler =  udp_rcv,  
    .err_handler =  udp_err,  
    .gso_send_check = udp4_ufo_send_check,  
    .gso_segment = udp4_ufo_fragment,  
    .no_policy =    1,  
    .netns_ok = 1,  
};  
  
static const struct net_protocol icmp_protocol = {  
    .handler =  icmp_rcv,  
    .err_handler =  ping_err,  
    .no_policy =    1,  
    .netns_ok = 1,  
};  

IP层与net/core层接口定义如下
static struct packet_type ip_packet_type __read_mostly = {  
    .type = cpu_to_be16(ETH_P_IP),  
    .func = ip_rcv,  
    .gso_send_check = inet_gso_send_check,  
    .gso_segment = inet_gso_segment,  
    .gro_receive = inet_gro_receive,  
    .gro_complete = inet_gro_complete,  
};  




6、数据发送(Data TX)流珵

   数据发送流程如下图所示:



上半部分涉及到的相关代码如下所示(以上流程主要通过dump_stack获取):

     net/socket.c
     net/ipv4/af_net.c
     net/ipv4/tcp.c
     net/ipv4/tcp_output.c
     net/ipv4/ip_output.c
     net/core/neighbour.c
     net/core/dev.c


7、INET初始化

    INET为Linux OS实现了TCP/IP协议集,它使用BSD Socket接口作为与User通讯的方式。其初始化代码如下所示:

代码位于:net/ipv4/af_inet.c

static int __init inet_init(void)  
{  
    struct sk_buff *dummy_skb;  
    struct inet_protosw *q;  
    struct list_head *r;  
    int rc = -EINVAL;  
  
    BUILD_BUG_ON(sizeof(struct inet_skb_parm) > sizeof(dummy_skb->cb));  
  
    sysctl_local_reserved_ports = kzalloc(65536 / 8, GFP_KERNEL);  
    if (!sysctl_local_reserved_ports)  
        goto out;  
  
    rc = proto_register(&tcp_prot, 1);  
    if (rc)  
        goto out_free_reserved_ports;  
  
    rc = proto_register(&udp_prot, 1);  
    if (rc)  
        goto out_unregister_tcp_proto;  
  
    rc = proto_register(&raw_prot, 1);  
    if (rc)  
        goto out_unregister_udp_proto;  
  
    rc = proto_register(&ping_prot, 1);  
    if (rc)  
        goto out_unregister_raw_proto;  
  
    /* 
     *  Tell SOCKET that we are alive... 
     */  
  
    (void)sock_register(&inet_family_ops);  
  
#ifdef CONFIG_SYSCTL  
    ip_static_sysctl_init();  
#endif  
  
    /* 
     *  Add all the base protocols. 
     */  
  
    if (inet_add_protocol(&icmp_protocol, IPPROTO_ICMP) < 0)  
        printk(KERN_CRIT "inet_init: Cannot add ICMP protocol\n");  
    if (inet_add_protocol(&udp_protocol, IPPROTO_UDP) < 0)  
        printk(KERN_CRIT "inet_init: Cannot add UDP protocol\n");  
    if (inet_add_protocol(&tcp_protocol, IPPROTO_TCP) < 0)  
        printk(KERN_CRIT "inet_init: Cannot add TCP protocol\n");  
#ifdef CONFIG_IP_MULTICAST  
    if (inet_add_protocol(&igmp_protocol, IPPROTO_IGMP) < 0)  
        printk(KERN_CRIT "inet_init: Cannot add IGMP protocol\n");  
#endif  
  
    /* Register the socket-side information for inet_create. */  
    for (r = &inetsw[0]; r < &inetsw[SOCK_MAX]; ++r)  
        INIT_LIST_HEAD(r);  
  
    for (q = inetsw_array; q < &inetsw_array[INETSW_ARRAY_LEN]; ++q)  
        inet_register_protosw(q);  
  
    /* 
     *  Set the ARP module up 
     */  
  
    arp_init();  
  
    /* 
     *  Set the IP module up 
     */  
  
    ip_init();  
  
    tcp_v4_init();  
  
    /* Setup TCP slab cache for open requests. */  
    tcp_init();  
  
    /* Setup UDP memory threshold */  
    udp_init();  
  
    /* Add UDP-Lite (RFC 3828) */  
    udplite4_register();  
  
    ping_init();  
  
    /* 
     *  Set the ICMP layer up 
     */  
  
    if (icmp_init() < 0)  
        panic("Failed to create the ICMP control socket.\n");  
  
    /* 
     *  Initialise the multicast router 
     */  
#if defined(CONFIG_IP_MROUTE)  
    if (ip_mr_init())  
        printk(KERN_CRIT "inet_init: Cannot init ipv4 mroute\n");  
#endif  
    /* 
     *  Initialise per-cpu ipv4 mibs 
     */  
  
    if (init_ipv4_mibs())  
        printk(KERN_CRIT "inet_init: Cannot init ipv4 mibs\n");  
  
    ipv4_proc_init();  
  
    ipfrag_init();  
  
    dev_add_pack(&ip_packet_type);  
  
    rc = 0;  
out:  
    return rc;  
out_unregister_raw_proto:  
    proto_unregister(&raw_prot);  
out_unregister_udp_proto:  
    proto_unregister(&udp_prot);  
out_unregister_tcp_proto:  
    proto_unregister(&tcp_prot);  
out_free_reserved_ports:  
    kfree(sysctl_local_reserved_ports);  
    goto out;  
}  



  • 6
    点赞
  • 52
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值