wifi底层学习之路:二,无线配置管理服务cfg80211

本文详细介绍了Linux无线网络堆栈中cfg80211模块的功能与工作流程,解释了cfg80211如何通过netlink与iw交互,以及它与mac80211之间的交互机制。cfg80211负责无线设备的配置管理,而mac80211则处理MAC层功能。两者通过cfg80211_ops结构体进行通信,实现了从用户空间到无线设备的指令传递。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

1,什么是cfg80211?wiphy又是什么?

2,cfg80211工作流程是什么?

3,cfg80211如何通过netlink与iw进行交互?

4,cfg80211怎么与mac80211进行交互?

5,总结


1,什么是cfg80211?wiphy又是什么?

cfg80211:用于对无线设备进行配置管理。cfg80211&nl80211基于消息机制,使用netlink接口。

wiphy:无线网络设备驱动使用cfg80211需要硬件设备在cfg80211中实现注册。实现注册就要定义一系列的硬件功能描述的结构体。每个设备的基础性结构体是wiphy,设备连接到系统是,都要使用。每个wiphy有0个,1个或者许多个虚拟接口相关联。

2,cfg80211工作流程是什么?

static int __init cfg80211_init(void)
{
    //注册网络命名空间
    register_pernet_device(&cfg80211_pernet_ops);

    //注册ieee80211_class类
    wiphy_sysfs_init();
    //将class注册到内核中,同时会在/sys/class/下创建class对应的节点
    --->class_register(&ieee80211_class); 

    //注册网络通知,以接收网络事件,以通知链的方式
    register_netdevice_notifier(&cfg80211_netdev_notifier);

    //注册netlink“nl80211”,其操作为nl80211_ops
    nl80211_init();
    --->genl_register_family(&nl80211_fam);
    //在netlink_register链上注册一个回调函数,notifier机制是子系统之间通信手段,
    //netlink_register链上的子系统会检测用户态socket的连接状况
    //如果发生改变则通知运行回调函数
    --->netlink_register_notifier(&nl80211_netlink_notifier);

    //创建sys/class/ieee80211目录
    ieee80211_debugfs_dir = debugfs_create_dir("ieee80211", NULL);
    regulatory_init();
 
    //创建名为“cfg80211”的内核线程
    cfg80211_wq = alloc_ordered_workqueue("cfg80211", WQ_MEM_RECLAIM);
}

3,cfg80211如何通过netlink与iw进行交互?

nl80211_init()之后,通过nl80211_ops结构体实现与CMD关联,如iw发送消息NL80211_CMD_GET_POWER_SAVE,cfg80211就执行nl80211_get_power_save()来进行下一步操作。

//关键结构体
static __genl_const struct genl_ops nl80211_ops[] = {
	{
		.cmd = NL80211_CMD_GET_WIPHY,
		.doit = nl80211_get_wiphy,
		.dumpit = nl80211_dump_wiphy,
		.done = nl80211_dump_wiphy_done,
		.policy = nl80211_policy,
		/* can be retrieved by unprivileged users */
		.internal_flags = NL80211_FLAG_NEED_WIPHY |
				  NL80211_FLAG_NEED_RTNL,
	},
...
...
	{
		.cmd = NL80211_CMD_ABORT_SCAN,
		.doit = nl80211_abort_scan,
		.policy = nl80211_policy,
		.flags = GENL_UNS_ADMIN_PERM,
		.internal_flags = NL80211_FLAG_NEED_WDEV_UP |
				  NL80211_FLAG_NEED_RTNL,
	},
...
    {
		.cmd = NL80211_CMD_GET_POWER_SAVE,
		.doit = nl80211_get_power_save,
		.policy = nl80211_policy,
		/* can be retrieved by unprivileged users */
		.internal_flags = NL80211_FLAG_NEED_NETDEV |
				  NL80211_FLAG_NEED_RTNL,
	},
...
};

/*疑问:
1,nl80211_ops结构体是怎样与nl80211_init()关联的??
*

nl80211_get_power_save()函数实现如下,构造msg,填充msg,返回给iw。

//nl80211_get_power_save()函数实现
static int nl80211_get_power_save(struct sk_buff *skb, struct genl_info *info)
{
    struct wireless_dev *wdev;
    struct net_device *dev = info->user_ptr[1];
    struct sk_buff *msg;
    wdev = dev->ieee80211_ptr;
    //调用genlmsg_new()函数申请skb套接字缓存空间
    msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
    //构造返回msg
	hdr = nl80211hdr_put(msg, genl_info_snd_portid(info), info->snd_seq,
			     0, NL80211_CMD_GET_POWER_SAVE);
    //获取ps_state值
    if (wdev->ps)
		ps_state = NL80211_PS_ENABLED;
	else
		ps_state = NL80211_PS_DISABLED;
    //传ps_state值到msg
    nla_put_u32(msg, NL80211_ATTR_PS_STATE, ps_state)
    //调用genlmsg_end()更新消息头重的长度字段
    genlmsg_end(msg, hdr);
    //启动回发流程,为genlmsg_unicast()的一个封装
    return genlmsg_reply(msg, info);
}

/*疑问:
1,struct genl_info *info结构体的值,什么时候赋值的??
注:需要理解Generic Netlink,打算另写篇文件深入介绍。
*/

4,cfg80211怎么与mac80211进行交互?

4.1,以NL80211_CMD_TRIGGER_SCAN指令为例,cfg80211接收iw的NL80211_CMD_TRIGGER_SCAN消息后,运行nl80211_trigger_scan()函数,nl80211_trigger_scan()的分析如下



//nl80211_trigger_scan()关键分析
static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
{
    struct cfg80211_registered_device *rdev = info->user_ptr[0];
    struct wireless_dev *wdev = info->user_ptr[1];
    struct wiphy *wiphy;
    wiphy = &rdev->wiphy;

    //调用mac80211注册的cfg80211_ops对应的函数.scan
    rdev->scan_req = request;
	err = rdev_scan(rdev, request);
    ---->ret = rdev->ops->scan(&rdev->wiphy, request);

    //构造netlink消息,回复给iw
    nl80211_send_scan_start(rdev, wdev);
    ---->msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
    ---->nl80211_prep_scan_msg(msg, rdev, wdev, 0, 0, 0,NL80211_CMD_TRIGGER_SCAN) < 0) 
    -------->nl80211hdr_put(msg, portid, seq, flags, cmd);
    -------->nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx)
    -------->nl80211_add_scan_req(msg, rdev);
    -------->genlmsg_end(msg, hdr);
    ---->genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
				NL80211_MCGRP_SCAN, GFP_KERNEL);
    return err;
}

/*疑问:
1,cfg80211是如何关联到mac80211的cfg80211_ops,使其可以调用ops对应函数?
*/

4.2,mac80211向cfg80211注册的cfg80211_ops 如下

const struct cfg80211_ops mac80211_config_ops = {
	.add_virtual_intf = ieee80211_add_iface,
	.del_virtual_intf = ieee80211_del_iface,
	.change_virtual_intf = ieee80211_change_iface,
	.start_p2p_device = ieee80211_start_p2p_device,
	.stop_p2p_device = ieee80211_stop_p2p_device,
	.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,
	.start_ap = ieee80211_start_ap,
	.change_beacon = ieee80211_change_beacon,
	.stop_ap = ieee80211_stop_ap,
	.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 CPTCFG_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,
	.get_mpp = ieee80211_get_mpp,
	.dump_mpp = ieee80211_dump_mpp,
	.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
	.join_ocb = ieee80211_join_ocb,
	.leave_ocb = ieee80211_leave_ocb,
	.change_bss = ieee80211_change_bss,
	.set_txq_params = ieee80211_set_txq_params,
	.set_monitor_channel = ieee80211_set_monitor_channel,
	.suspend = ieee80211_suspend,
	.resume = ieee80211_resume,
	.scan = ieee80211_scan,
	.abort_scan = ieee80211_abort_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_mcast_rate = ieee80211_set_mcast_rate,
	.set_wiphy_params = ieee80211_set_wiphy_params,
	.set_tx_power = ieee80211_set_tx_power,
	.get_tx_power = ieee80211_get_tx_power,
	.set_antenna_gain = ieee80211_set_antenna_gain,
	.set_wds_peer = ieee80211_set_wds_peer,
	.rfkill_poll = ieee80211_rfkill_poll,
	CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd)
	CFG80211_TESTMODE_DUMP(ieee80211_testmode_dump)
	.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,
	.set_cqm_rssi_range_config = ieee80211_set_cqm_rssi_range_config,
	.mgmt_frame_register = ieee80211_mgmt_frame_register,
	.set_antenna = ieee80211_set_antenna,
	.get_antenna = ieee80211_get_antenna,
	.set_rekey_data = ieee80211_set_rekey_data,
	.tdls_oper = ieee80211_tdls_oper,
	.tdls_mgmt = ieee80211_tdls_mgmt,
	.tdls_channel_switch = ieee80211_tdls_channel_switch,
	.tdls_cancel_channel_switch = ieee80211_tdls_cancel_channel_switch,
	.probe_client = ieee80211_probe_client,
	.set_noack_map = ieee80211_set_noack_map,
#ifdef CONFIG_PM
	.set_wakeup = ieee80211_set_wakeup,
#endif
	.get_channel = ieee80211_cfg_get_channel,
	.start_radar_detection = ieee80211_start_radar_detection,
	.channel_switch = ieee80211_channel_switch,
	.set_qos_map = ieee80211_set_qos_map,
	.set_ap_chanwidth = ieee80211_set_ap_chanwidth,
	.add_tx_ts = ieee80211_add_tx_ts,
	.del_tx_ts = ieee80211_del_tx_ts,
	.start_nan = ieee80211_start_nan,
	.stop_nan = ieee80211_stop_nan,
	.nan_change_conf = ieee80211_nan_change_conf,
	.add_nan_func = ieee80211_add_nan_func,
	.del_nan_func = ieee80211_del_nan_func,
	.set_multicast_to_unicast = ieee80211_set_multicast_to_unicast,
};

5,总结

指令流程:iw<--netlink-->cfg80211<--cfg80211_ops-->mac80211

文章的细节与疑问,后面会继续更新!
欢迎订阅公众号【从零开始学无线】,一起学习交流! 

                                                                

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值