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中的定义如下所示:

static 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,
};




接收下半部stack如下所示:

[  336.646628] [<c07d8b24>] (tcp_rcv_established+0x648/0x9b0) from [<c07e04cc>] (tcp_v4_do_rcv+0x74/0x2a8)
[  336.646661] [<c07e04cc>] (tcp_v4_do_rcv+0x74/0x2a8) from [<c07e0c40>] (tcp_v4_rcv+0x540/0x908)
[  336.646678] [<c07e0c40>] (tcp_v4_rcv+0x540/0x908) from [<c07c23d4>] (ip_local_deliver_finish+0x158/0x318)
[  336.646694] [<c07c23d4>] (ip_local_deliver_finish+0x158/0x318) from [<c07c1e44>] (ip_rcv_finish+0x420/0x440)
[  336.646715] [<c07c1e44>] (ip_rcv_finish+0x420/0x440) from [<c0772dcc>] (__netif_receive_skb+0x4d0/0x534)
[  336.646730] [<c0772dcc>] (__netif_receive_skb+0x4d0/0x534) from [<c0774434>] (netif_receive_skb+0x9c/0xb4)
[  336.646752] [<c0774434>] (netif_receive_skb+0x9c/0xb4) from [<c08b8e6c>] (ieee80211_deliver_skb+0x134/0x164)
[  336.646769] [<c08b8e6c>] (ieee80211_deliver_skb+0x134/0x164) from [<c08b9ed8>] (ieee80211_rx_handlers+0x103c/0x1978)
[  336.646785] [<c08b9ed8>] (ieee80211_rx_handlers+0x103c/0x1978) from [<c08baf10>] (ieee80211_prepare_and_rx_handle+0x6fc/0x788)
[  336.646802] [<c08baf10>] (ieee80211_prepare_and_rx_handle+0x6fc/0x788) from [<c08bb920>] (ieee80211_rx+0x908/0x988)
[  336.646819] [<c08bb920>] (ieee80211_rx+0x908/0x988) from [<c068a578>] (ath9k_rx_tasklet+0x4e4/0x54c)
[  336.646835] [<c068a578>] (ath9k_rx_tasklet+0x4e4/0x54c) from [<c0467d98>] (tasklet_action+0xa8/0x14c)
[  336.646850] [<c0467d98>] (tasklet_action+0xa8/0x14c) from [<c0468144>] (__do_softirq+0x88/0x158)
[  336.646863] [<c0468144>] (__do_softirq+0x88/0x158) from [<c0468414>] (irq_exit+0x48/0xac)
[  336.646882] [<c0468414>] (irq_exit+0x48/0xac) from [<c04313c0>] (do_local_timer+0x50/0x80)
[  336.646898] [<c04313c0>] (do_local_timer+0x50/0x80) from [<c0436708>] (__irq_svc+0x48/0xe0)


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;
}







阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页