mac80211无线网卡驱动设计

无线驱动设计思路

struct xxx_wifi_priv {
	struct ieee80211_hw *hw;
	struct wiphy *wiphy;
	...
	bool scanning;
	bool is_up;
	...
	struct ieee80211_channel channel;
	struct ieee80211_channel channels;
	struct work_struct scan_work;
	struct workqueue_struct *wq;
	struct address address;
};
 hw:保存硬件信息
 wiphy:保存phy信息
 scanning:记录扫描状态
 is_up:是否被启用
 scan_work:扫描时使用.
static struct ieee80211_os xxx_ops = {
	.tx = xxx_tx,
	.add_interface = xxx_add_interface,
	.remove_interface = xxx_remove_interface,
	.config = xxx_config,
	.bss_info_changed = xxx_bss_info_changed,
	.configure_filter = xxx_configure_filter,
	.start = xxx_start,
	.stop = xxx_stop,
	.hw_scan = xxx_hw_scan,
	.set_key = xxx_set_key,
	...
};
以上为必要的几个功能回调。
# 信道信息
static struct ieee80211_channel xxx_channels = {
	{ .center_freq = 2412, .hw_value = 1},
	{ .center_freq = 2417, .hw_value = 2},
	....
};
# 速率信息
static struct ieee80211_rate xxx_rates = {
	{ .bitrate = 10, .hw_value = 0},
	{ .bitrate = 20, .hw_value = 1},
	...
};

struct ieee80211_supported_band xxx_supported_band = {
	.channels = xxx_channels,
	.n_channels = ARRAY_SIZE(xxx_channels),
	.bitrates = xxx_rates,
	.n_bitrates = ARRAY_SIZE(xxx_rates),
	.ht_caps = {
		.ht_supported = true,
		.cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
				IEEE80211_HT_CAP_SGI_20 |
				IEEE80211_HT_CAP_DSSSCCK40,
		.ampdu_factor = 0x3,
		.ampdu_density = 0x6,
		.mcs = {
			.rx_mask = {0xff, 0xff},
			.tx_params = IEEE80211_HT_MCS_TX_DEFINED,
		},
	},
};

probe处理流程

struct xxx_wifi_priv *priv;
struct ieee80211_hw *hw;
struct wiphy *wiphy;

hw = ieee80211_alloc_hw(sizeof(*priv), &xxx_ops);

#这里需要检查返回值。
if (!hw)
	return -ENOMEM;

priv = hw->priv;
priv->hw = hw;
priv->wiphy = hw->wiphy; 

#wiphy在alloc时会自动分配置并配置默认的回调函数

wiphy->max_scan_ssids = 1;
wiphy->max_scan_ie_len = 0;
wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
wiphy->bands[NL80211_BAND_2GHZ] &xxx_supported_band;

ieee80211_hw_set(hw, RX_INCLUDES_FCS);
ieee80211_hw_set(hw, SIGNAL_DBM)

# interface_modes表示支持哪些模式,可以一同设置多个。

hw->max_signal = -30;

# 当设置了SIGNAL_DBM之后,max_signal为负数.

SET_IEEE80211_DEV(hw, priv->dev); # 设置hw的父设备

# 设置默认MAC地址

eth_random_addr(priv->address.addr);
wiphy->addresses = &priv->address;
wiphy->n_addresses = 1;
wiphy->hw_version = 1;

# 进行一些基础的配置,比如初始化timer, 队列等。

#注册hw, 注册成功后,使用ifconfig就能看到wlanx设备。
ret = ieee80211_register_hw(hw);

# 扫描的实现与设计思路

#在用户态使用iw scan时,通过一些检查之后,如果ops实现了hw_scan将会调用
hw_scan.
#如果没有实现,可以return 1,表示使用sw_scan。
此时就必须实现sw_scan_start和sw_scan_stop.

在调用iw scan后,会一直等待内核返回结果,可以返回,也可以返回扫描结果。
可以在hw_scan的回调函数设置priv->scanning = true。
然后调度一个延迟任务。
在延迟任务中检查网卡的扫描状态。
如果网卡还处于扫描中,等继续等待和,如果等待时间过长。可以在调用
ieee80211_scan_completed中第二个参数中将aborted设置成true。
如果是正常扫描结束结设置为fase

struct ieee80211_scan_info info = {
	.aborted = false,
};

ieee80211_scan_completed(priv->hw, &info);

需要注意的是,ieee80211_scan_completed必须延迟一段时间后调用。
否则会导致用户态接收不到消息。

关于扫描结果返回

在常规的无线网卡中,扫描行为是offload的,无需用户去干预。
网卡会将扫描结果放在网卡的正常数据流中。
所以在接收数据的时候,接收到数据之后调用mac80211实现的ieee80211_rx_napi。
这样,当接收到扫描数据时会通过netlink返回给用户态。
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值