歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> Linux技術 >> Linux Wireless架構總結

Linux Wireless架構總結

日期:2017/3/3 11:47:14   编辑:Linux技術


1、無線網絡驅動(ath9k_htc)

ath9k_htc是一個基於USB接口的SoftMAC無線網絡適配器。為了其驅動能正常工作,首先必須調用usb_register來注冊驅動定義的usb_driver,以借助USB Core的力量來處理與USB協議相關的事件。其代碼如下:
[cpp] view
plain copy





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的調用。
[cpp] view
plain copy





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中,其定義如下所示:
[cpp] view
plain copy





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中的定義如下所示:
[cpp] view
plain copy





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參數。其具體定義如下:
[cpp] view
plain copy





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:
[cpp] view
plain copy





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層接口定義如下:
[cpp] view
plain copy





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層接口定義如下
[cpp] view
plain copy





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
[cpp] view
plain copy





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;
}
Copyright © Linux教程網 All Rights Reserved