文章目录
- 1、资料快车
- 2、目录介绍
- 2、术语
- 3、Linux无线子系统概述
- 4、内核无线子系统框架
- 1)认识内核无线子系统中的三个软件框架
- 2、无线网络子系统框架
- 3、Android WIFI Management框架
- 1)fullMAC和softMAC是什么?
- 2)fullmac对比softmac
- 3)如何区分fullmac还是softmac架构?
- 4)fullmac和softmac的整体架构回顾
- 4、WEXT与nl80211
- 5、WIFI网络数据向上传递过程
- 6、WIFI网络数据向下传递过程
- 7、三种软件架构和产品形态
- 5、内核netlink机制
- 1)netlink介绍
- 2)源码目录
- 3)netlink架构图
- 4)用户空间和内核空间使用netlink
- 5)源码分析
- 6、内核模块nl80211
- 7、内核模块cfg80211+非mac80211方式实现的驱动分析(fullMAC)
- 8、内核模块mac80211(softmac)
- 1)mac80211所在的层级
- 2)802.11 MAC帧
- 3)代码分析
- 9、内核模块cfg80211 + mac80211方式实现的驱动分析(softmac)
1、资料快车
1、WIFI驱动框架概述
https://zhuanlan.zhihu.com/p/696776194
2、WIFI底层学习之路(源码分析)
https://blog.csdn.net/qq_26602023/category_10005218.html
3、WIFI驱动示例
how-to-write-simple-linux-wireless-driver
https://www.apriorit.com/dev-blog/645-lin-linux-wi-fi-driver-tutorial-how-to-write-simple-linux-wireless-driver-prototype
2、目录介绍
1、Network configuration - 网络协议栈实现
android\kernel\fusion\4.19\net
android\kernel\fusion\4.19\net\wireless (nl80211 / cfg80211实现)//IP层实现
android\kernel\fusion\4.19\net\ipv4
android\kernel\fusion\4.19\net\ipv6//无线栈mac层实现
android\kernel\fusion\4.19\net\mac802112、Network device configuration - 网络设备驱动程序实现
android\kernel\fusion\4.19\drivers\net
android\kernel\fusion\4.19\drivers\net\wireless
2、术语
1、octet : 它是能为网络设备和协议所能理解的最小单位;
2、MLME : MAC subLayer Management Entity (MAC层协议实现)1、网络设备程序不会生成/dev 设备节点 -> 而是 iface (由网络设备子系统负责生成维护) : wlan0/eth0/loopback ->调用net_device_register() 即可完成调用2、sys下的net device节点
console:/sys/class/net # ls
dummy0 eth0 gretap0 ifb1 ip6gre0 ip_vti0 sit0 wlan0
erspan0 gre0 ifb0 ip6_vti0 ip6tnl0 lo tunl03、socket节点
console:/dev/socket # ls
audioserver logdr property_service traced_consumer
dnsproxyd logdw statsdw traced_producer
fwmarkd mdns tombstoned_crash usap_pool_primary
lmkd mdnsd tombstoned_intercept wpa_wlan0
logd prng_seeder tombstoned_java_trace zygote重要的数据结构:
android\kernel\fusion\4.19\include\linux\netdevice.h
net_device : 表示网络设备
android\kernel\fusion\4.19\include\linux\skbuff.h
skbuff : socket buffer 套接字缓冲区
分配方法:netdev_alloc_skb()驱动框架
struct rwnx_vif *vif = netdev_priv(net);1、传统的net device
int snull_init_module(void) {snull_devs[0] = alloc_netdev(sizeof(struct snull_priv), "sn%d", snull_init);if ((result = register_netdev(snull_devs[i])))
}
2、wifi 驱动与 以太网实现不同!
3、Linux无线子系统概述
1、WIFI驱动子系统 也是基于网络设备(net_driver),属于扩展子系统;
2、如何学习无线子系统?
1)基于传统linux网络子系统进行差异化学习;
linux网络子系统本身也很庞大复杂,先消化这块,否则再叠加无线部分,难度会非常大
2)无线子系统 较于有线子系统 有哪些新的模块? 主要是新增了80211部分(从上至下的实现 nl80211/cfg80211/mac80211),接下来重点看下80211部分框架。
3、WIFI软件架构为什么有多个版本?
1)由于WIFI在不断迭代,产品形态也不同,导致软件架构相对繁杂,但总体上没有太大变化;
2)软件架构的差异归根结底与其硬件架构以及历史积累有关;
3)WIFI技术栈相对较深,市面上专门做WIFI的厂商也相对较多,竞争激烈,不断推陈出新;
4、内核无线子系统框架
1)认识内核无线子系统中的三个软件框架
three types of wireless driver configurations in Linux:1、Cfg80211 — The configuration API for 802.11 devices in Linux. It works together with FullMAC drivers, which also should implement the MAC Sublayer Management Entity (MLME).2、Mac80211 — A subsystem of the Linux kernel that works with soft-MAC/half-MAC wireless devices. MLME is mostly implemented by the kernel, at least for station mode (STA).3、WEXT — Stands for Wireless-Extensions, which is a driver API that was replaced by cfg80211. New drivers should no longer implement WEXT.4、nl80211 (与WEXT一样,代替WEXT)
1、WEXT已被抛弃,nl80211(对应上层应用工具是iw) 代替了WEXT (对应上层应用工具是iwpriv) 方式,最新的资料也都使用nl80211进行展示;
2、接下来看下三个软件框架(cfg80211/mac80211/nl80211)位于哪个层级,以及如何作用,后续再单独讨论细节;
2、无线网络子系统框架
无线网络子系统框架中有两大“通讯路径”:Management路径和网络数据传输路径,以博通的Fullmac架构为例
1)左边路径为Linux的网络子系统,即有线网走的路径,无线网络则分为两个路径,数据路径走原来的网络子系统,达到设备层然后对接WIFI driver处理;管理功能走的是nl80211和cfg80211软件框架。
2)无线网络数据传输还是走TCP/IP网络协议栈那一套;
3)对比以太网的体系结构
可以看出数据包的发送和接收部分,无线网络从网络协议栈开始,往下层级都区别于以太网,重新实现自己的一套软件框架 MAC80211;
4)为什么Management单独分开?
AP热点、P2P投屏、STA 正式进行网络数据传输之前,要进行许多配置(搜索、认证、连接等过程),这些功能归类为Management,lLinux内核针对WIFI的通信特性 开发出cfg80211(configuration 80211) 软件框架来支持这些功能;
实际项目中,基本都在Management侧进行配置工作,很少动到数据通路侧;
5)WIFI CPU firmware属于专业领域,这里不深入,重点看linux端的内核框架和驱动实现;
3、Android WIFI Management框架
1)以博通WIFI为例,存在三种驱动形式
2)可以看出差异在于是FullMAC方式实现、SoftMAC方式实现 或混合实现(历史原因导致),但无论哪种实现,从上往下的软件功能始终未变;
3)WIFI CPU firmware架构说明
bcmdhd ( FullMAC / Android)
brcmfmac (FullMAC / Linux)
brcmsmac (SoftMAC / Linux)
b43 (reversed from proprietary wl / old SoftMAC / Linux)
1)fullMAC和softMAC是什么?
1、先来回忆一下Linux系统的五层网络模型
2、80211对WIFI的MAC层和PHY层的规定如下:
1)如上图 80211规定了网络模型中MAC层和PHY层,而MAC层是软件实现,fullMAC和softMA均是MAC层的软件实现,区别在于fullMAC由WIFI芯片的固件实现,softMAC由linux驱动实现;
2)出现这种差异是因为Linux一开始没有提供稳定统一的API,厂商不得已在wifi soc上实现大部分的管理工作,后面推出80211无线协议栈(2007) - mac80211;
3)从接触到的项目来看,当下fullMAC的居多,厂商肯定是能不变则尽量不变更原则,大多数产品还是老架构;
2)fullmac对比softmac
1)fullmac的方式,MLME(MAC subLayer Management Entity)是在wifi中的处理器运行,通常以固件的形式提供,Linux driver运行时将这些固件通过USB/SDIO/PCI烧写到WIFI芯片侧;
2)这种方式有很快的速度和较低的功耗(因为这个处理器往往是一个低功耗的DSP);
3)但是对于用户侧的特殊的报文的支持能力有限;
3)如何区分fullmac还是softmac架构?
可以通过驱动实现的接口来区分
-Fullmac方式的Linux驱动不使用mac80211, 因此其需要与网络设备子系统 直接连接,接口是struct net_device_ops;
-softmac方式的Linx驱动则是与mac80211连接,对接的接口是struct ieee80211_ops(注意mac80211负责对接网络子系统 )
4)fullmac和softmac的整体架构回顾
4、WEXT与nl80211
1)iw + nl80211 代替旧的架构 iwconifg/iwlist + wext;
2)实际项目上仍有不少厂家产品还在使用wext;
5、WIFI网络数据向上传递过程
1)这里细分三个路径(管理路径、数据路径、监听路径);
2)面对复杂庞大的WIFI架构,监听路径对于debug显得十分重要;
6、WIFI网络数据向下传递过程
7、三种软件架构和产品形态
以CEVA为例,CEVA的产品体系覆盖常用的三种软件架构对比图如下:
从ceva release的文档来看,其主要存在三种软件架构:
1、fully hosted。主要在低端设备比如IOT wifi中。只有一个cpu,运行顶层的操作系统,又运行wifi驱动程序,还有wifi的mac软件。
2、Fullmac架构。MLME在wifi CPU上实现。
3、Softmac架构。MLME在host OS的协议栈实现,主要数据通路在wifi CPU firmware实现。
WIFI CPU firmware属于专业领域,这里不深入,重点看linux端的内核框架和驱动实现;
通俗来说(三中软件架构对应三种产品形态)
1)产品1,一般为MCU产品,比如智能锁、IOT设备等,直接跑WIFI芯片即可满足需求的场景;
2)产品2 和 产品3,一般为跑linux系统的产品,full mac还是soft mac取决于wifi芯片,CPU端均可支持;
5、内核netlink机制
1)netlink介绍
1、netlink是linux平台下的基于socket的IPC通信机制(既可以 应用->kernel,也可以是应用->应用),即在原有的socket框架下新增netlink部分逻辑代码;
2、内核利用netlink机制重构了wext,产生nl80211 ,这里先介绍netlink;
2)源码目录
1.netlink源码
android\kernel\fusion\4.19\net\netlink2.libnl
android\external\libnl 对netlink进一步封装//旧的netlink api
android\kernel\fusion\4.19\net\netlink\af_netlink.c
//新的通用netlink api - generic netlink,内部部分复用netlink.c,正常情况下都使用这个
android\kernel\fusion\4.19\net\netlink\genetlink.c
//读取Netlink套接字的信息,debug用途
android\kernel\fusion\4.19\net\netlink\diag.c
3)netlink架构图
1)最下方的Kernel Module实现真正的接口,比如nl80211,Application通过netlink访问到80211
4)用户空间和内核空间使用netlink
general Netlink消息头格式
5)源码分析
1)应用层
6、Application通过netlink访问nl80211过程分析,比如wpa_supplication
android\external\wpa_supplicant_8\src\drivers\driver_nl80211.c
send_and_recv_msgs
--send_and_recv
----setsockopt
----nl_send_auto_complete/android/external/libnl/lib/nl.c
nl_send_auto_complete
--nl_send_auto(struct nl_sock *sk, struct nl_msg *msg)
----nl_send(sk, msg)
------nl_send_iovec(sk, msg, &iov, 1)
--------nl_sendmsg(sk, msg, &hdr)
----------sendmsg(sk->s_fd, hdr, 0)
nl_recvmsgs(nl_handle, cb);
最终进入内核netlink模块处理
2)内核层netlink
1、netlink本质上是在socket的接口上新增netlink接口,使用套接字段AF_NETLINK区别(分发数据用到)2、重要的结构体
1)android\kernel\fusion\4.19\include\uapi\linux\netlink.h
struct nlmsghdr { //信息头__u32 nlmsg_len; /* Length of message including header */__u16 nlmsg_type; /* Message content */__u16 nlmsg_flags; /* Additional flags */__u32 nlmsg_seq; /* Sequence number */__u32 nlmsg_pid; /* Sending process port ID */
};2)android\kernel\fusion\4.19\include\net\genetlink.h
struct genl_ops {const struct nla_policy *policy;int (*doit)(struct sk_buff *skb,struct genl_info *info); //标准命令回调函数int (*start)(struct netlink_callback *cb);int (*dumpit)(struct sk_buff *skb,struct netlink_callback *cb); //转储回调函数(传输数据量大的情况使用)int (*done)(struct netlink_callback *cb); //转储结束后执行的回调函数u8 cmd;u8 internal_flags;u8 flags;
};注意doit / dumpit 两个都是执行对应的函数,构造genl_ops时只能挂在一个3)android\kernel\fusion\4.19\include\net\genetlink.h
struct genl_family {int (*pre_doit)();void (*post_doit);struct nlattr ** attrbuf;const struct genl_ops * ops;
}3、generic netlink初始化,内核启动时调用执行
static int __net_init genl_pernet_init(struct net *net)
{struct netlink_kernel_cfg cfg = {.input = genl_rcv, //通过通用Netlink套接字从用户空间发送的数据将有此回调函数进行处理(sokcet() 或 libnl-genl API).flags = NL_CFG_F_NONROOT_RECV,.bind = genl_bind,.unbind = genl_unbind,};net->genl_sock = netlink_kernel_create(net, NETLINK_GENERIC, &cfg);
}static struct pernet_operations genl_pernet_ops = {.init = genl_pernet_init,.exit = genl_pernet_exit,
};static int __init genl_init(void)
{genl_register_family(&genl_ctrl);register_pernet_subsys(&genl_pernet_ops);
}subsys_initcall(genl_init);4、处理用户下发的netlink消息
/android/kernel/fusion/4.19/net/netlink/genetlink.c
genl_rcv() {netlink_rcv_skb(skb, &genl_rcv_msg);
}genl_rcv_msg()
--family = genl_family_find_byid(nlh->nlmsg_type); //找到family簇
--genl_family_rcv_msg()
----ops = genl_get_cmd(hdr->cmd, family); //根据上层下发的cmd,匹配对应的genl_ops结构体
----if (family->pre_doit) { family->pre_doit(ops, skb, &info)}
----ops->doit(skb, &info);
----family->post_doit(ops, skb, &info);ops->doit是什么?对于nl80211,就是nl80211_ops->doit5、内核层构造genl_ops,以nl80211为例
android\kernel\fusion\4.19\net\wireless\nl80211.c
static const struct genl_ops nl80211_ops[] = {{.cmd = NL80211_CMD_AUTHENTICATE,.doit = nl80211_authenticate,.policy = nl80211_policy,.flags = GENL_UNS_ADMIN_PERM,.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |NL80211_FLAG_NEED_RTNL |NL80211_FLAG_CLEAR_SKB,},
}static struct genl_family nl80211_fam __ro_after_init = {.name = NL80211_GENL_NAME, /* have users key off the name instead */.hdrsize = 0, /* no private header */.version = 1, /* no particular meaning now */.maxattr = NL80211_ATTR_MAX,.netnsok = true,.pre_doit = nl80211_pre_doit,.post_doit = nl80211_post_doit,.module = THIS_MODULE,.ops = nl80211_ops, //genl_ops挂接到genl_family簇中.n_ops = ARRAY_SIZE(nl80211_ops),.mcgrps = nl80211_mcgrps,.n_mcgrps = ARRAY_SIZE(nl80211_mcgrps),
};nl80211_fam挂接哪里?
static DEFINE_IDR(genl_fam_idr); //最终是挂接在静态结构体genl_fam_idr上
6、内核模块nl80211
1)应用层如何访问网卡设备? 需要遵循802.11规范,因此提供nl80211框架库给Applications调用
2)nl80211本质上是利用netlink机制(对应的库是libnl),将802.11规范中相关的命令和参数发送给驱动去执行
3)访问路径
4)wpa_supplicant访问nl80211 api
1、android\external\wpa_supplicant_8\src\drivers\driver_nl80211.c
int wpa_driver_nl80211_scan(struct i802_bss *bss, struct wpa_driver_scan_params *params)
{struct nl_msg *msg = NULL;msg = nl80211_scan_common(bss, NL80211_CMD_TRIGGER_SCAN, params); //构造nl_msgsend_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL); //经过层层调用(libnl->netlink->socket)到达nl80211实现的接口
}2、更多命令和参数信息可查询(庞大的命令集)
android\external\kernel-headers\original\uapi\linux\nl80211.h
enum nl80211_commands {NL80211_CMD_GET_INTERFACE,NL80211_CMD_GET_BEACON,NL80211_CMD_GET_STATION,NL80211_CMD_SET_BSS,NL80211_CMD_TRIGGER_SCAN,...
}3、无线模式
android\kernel\fusion\4.19\include\uapi\linux\nl80211.h
enum nl80211_iftype {NL80211_IFTYPE_UNSPECIFIED,NL80211_IFTYPE_ADHOC, //IBSS 对等模式NL80211_IFTYPE_STATION,NL80211_IFTYPE_AP,NL80211_IFTYPE_AP_VLAN,NL80211_IFTYPE_WDS, //Wireless Distribution System 无线分布式系统NL80211_IFTYPE_MONITOR,NL80211_IFTYPE_MESH_POINT,NL80211_IFTYPE_P2P_CLIENT,NL80211_IFTYPE_P2P_GO,NL80211_IFTYPE_P2P_DEVICE,NL80211_IFTYPE_OCB,NL80211_IFTYPE_NAN,/* keep last */NUM_NL80211_IFTYPES,NL80211_IFTYPE_MAX = NUM_NL80211_IFTYPES - 1
};enum nl80211_attrs {NL80211_ATTR_WIPHY,NL80211_ATTR_MAC,...
}4、用户态通过socket发送的命令如何传递到内核,内核的入口在哪里?
结合netlink来看一个具体的例子,比如CMD : NL80211_CMD_AUTHENTICATE
应用层 socket(NL80211_CMD_AUTHENTICATE) -> 最后触发内核函数 nl80211_authenticate()1、首先到达内核的第一层nl802112、应用层和内核层都需要引用头文件中定义的CMD
/android/external/kernel-headers/original/uapi/linux/nl80211.h
NL80211_CMD_AUTHENTICATE3、
/android/kernel/fusion/4.19/net/netlink/af_netlink.c //af的含义 Address Family 套接字通信域的标识符
static int netlink_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) //内核发给用户层API4、根据netlink,内核的处理入口为
genl_rcv_msg()
--family = genl_family_find_byid(nlh->nlmsg_type); //找到family簇
--genl_family_rcv_msg()
----ops = genl_get_cmd(hdr->cmd, family); //根据上层下发的cmd,匹配对应的genl_ops结构体
----if (family->pre_doit) { family->pre_doit(ops, skb, &info)}
----ops->doit(skb, &info);
----family->post_doit(ops, skb, &info);5、NL80211_CMD_AUTHENTICATE对应的doit为nl80211_authenticate
static const struct genl_ops nl80211_ops[] = {{.cmd = NL80211_CMD_AUTHENTICATE,.doit = nl80211_authenticate,...}
}6、
android\kernel\fusion\4.19\net\wireless\nl80211.c
nl80211_authenticate()
--cfg80211_mlme_auth()
----rdev_auth(rdev, dev, &req); //struct cfg80211_registered_device *rdev
------rdev->ops->auth(&rdev->wiphy, dev, req); //cfg80211_ops在无线网络设备驱动里面挂载7、比如atbm6032x的实现
wifi_driver/hal_apollo/mac80211/cfg.c
struct cfg80211_ops mac80211_config_ops = {.auth = ieee80211_auth,
}
7、内核模块cfg80211+非mac80211方式实现的驱动分析(fullMAC)
1)cfg80211实现+ 非mac80211实现方式称为HardMAC (fullMAC) - MT7663与AIC都是fullMAC,因为都没有使用ieee80211接口
2)内核例子-博通
drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c (linux-6.5)3)内核模块cfg80211源码实现包含在 android\kernel\fusion\4.19\net\wireless\* 目录下4)这里结合驱动源码,看看驱动如何利用cfg80211提供的服务以及接口实现;5)重要的结构体
1、cfg80211_ops结构体
/android/kernel/fusion/4.19/net/wireless/core.h
struct cfg80211_registered_device {const struct cfg80211_ops *ops;int wiphy_idx;struct wiphy wiphy __aligned(NETDEV_ALIGN);
}2、net_device-代表网络设备(囊括有线设备、无线设备等)
android\kernel\fusion\4.19\include\linux\netdevice.h
struct net_device {char name[IFNAMSIZ];struct net_device_stats stats;const struct net_device_ops *netdev_ops;const struct ethtool_ops *ethtool_ops;struct wireless_dev *ieee80211_ptr;struct wpan_dev *ieee802154_ptr;
}3、wireless_dev -代表无线设备
android\kernel\fusion\4.19\include\net\cfg80211.h
struct wireless_dev {struct wiphy *wiphy;enum nl80211_iftype iftype;struct net_device *netdev;u8 ssid[IEEE80211_MAX_SSID_LEN];void (*reg_notifier)(struct wiphy *wiphy,struct regulatory_request *request);struct device dev;
}4、wiphy
wiphy是什么?代表无线网络硬件设备 wireless hardware description
/android/kernel/fusion/4.19/include/net/cfg80211.h
struct wiphy {struct mac_address *addresses;const struct ieee80211_txrx_stypes *mgmt_stypes;u16 interface_modes;enum cfg80211_signal_type signal_type;
}5、net_device_ops 与 cfg80211_ops 的关系?
>>cfg80211_ops定义了无线配置的操作,在add_iface接口中,它将创建并注册net_device6、驱动定义的私有结构体-usb_dev
aic\aic8800dl\20231219\wifi_driver\aic8800_fdrv\aicwf_usb.h
struct aic_usb_dev {struct rwnx_hw *rwnx_hw;struct aicwf_bus *bus_if;struct usb_device *udev;struct device *dev;struct aicwf_rx_priv* rx_priv;
}7、驱动定义的私有结构体-rwnx_hw
wifi_driver\aic8800_fdrv\rwnx_defs.h
struct rwnx_hw {struct rwnx_mod_params *mod_params;struct device *dev;struct aic_usb_dev *usbdev;struct wiphy *wiphy;struct tasklet_struct task;
}3、驱动的probe
wifi_driver\aic8800_fdrv\aicwf_usb.c
aicwf_usb_probe() //当usb设备接入系统时,进行probe
--aicwf_rwnx_usb_platform_init()
----rwnx_platform_init()
------rwnx_cfg80211_init() //cfg80211的初始化
--------/android/kernel/fusion/4.19/include/net/cfg80211.h 这里进入cfg80211处理
--------wiphy_new(&rwnx_cfg80211_ops, sizeof(struct rwnx_hw))//create a new wiphy for use with cfg80211, 挂接关系rwnx_hw->wiphy = wiphy; wiphy->ops = rwnx_cfg80211_ops
----------wiphy_new_nm(const struct cfg80211_ops *ops)
--------tasklet_init(&rwnx_hw->task, rwnx_task, (unsigned long)rwnx_hw);
--------wiphy_register(wiphy) //register wiphy device 最终在/sys/class/ieee80211 生成设备节点
----------device_add(&rdev->wiphy.dev);
----------wiphy_regulatory_register(wiphy);
----------nl80211_notify_wiphy(rdev, NL80211_CMD_NEW_WIPHY);
--------rwnx_interface_add(rwnx_hw, "wlan%d", NET_NAME_UNKNOWN,NL80211_IFTYPE_STATION, NULL);android\kernel\fusion\4.19\net\wireless\core.c
wiphy_new(wiphy)
--wiphy_priv_nm()static struct cfg80211_ops rwnx_cfg80211_ops = {.add_virtual_intf = rwnx_cfg80211_add_iface, //使用给定的名字创建一个"虚拟接口",在wiphy的命名空间中创建net_device.del_virtual_intf = rwnx_cfg80211_del_iface,.change_virtual_intf = rwnx_cfg80211_change_iface,.start_p2p_device = rwnx_cfgp2p_start_p2p_device,.stop_p2p_device = rwnx_cfgp2p_stop_p2p_device,.scan = rwnx_cfg80211_scan,#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0).channel_switch = rwnx_cfg80211_channel_switch,
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)//.tdls_channel_switch = rwnx_cfg80211_tdls_channel_switch,//.tdls_cancel_channel_switch = rwnx_cfg80211_tdls_cancel_channel_switch,
#endif//.tdls_mgmt = rwnx_cfg80211_tdls_mgmt,//.tdls_oper = rwnx_cfg80211_tdls_oper,.change_bss = rwnx_cfg80211_change_bss,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 17, 0) || defined(CONFIG_WPA3_FOR_OLD_KERNEL).external_auth = rwnx_cfg80211_external_auth,
#endif
}从这里来看,5.15内核 与 4.19内核没有接口上的差异4、net_device_ops结构体
wifi_driver\aic8800_fdrv\rwnx_main.c
static const struct net_device_ops rwnx_netdev_ops = {.ndo_open = rwnx_open,.ndo_stop = rwnx_close,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0).ndo_siocdevprivate = rwnx_do_ioctl,
#else.ndo_do_ioctl = rwnx_do_ioctl,
#endif
}在哪里使用以及挂接?rwnx_cfg80211_init
rwnx_cfg80211_add_iface()
--rwnx_interface_add(rwnx_hw, "wlan%d", NET_NAME_UNKNOWN);
----alloc_netdev_mqs(sizeof(*vif), "wlan", rwnx_netdev_setup); //构造net_device,分配网络设备,里面会调用rwnx_netdev_setup,分配好,必然有注册的地方,接着走
------rwnx_netdev_setup()
--------dev->netdev_ops = &rwnx_netdev_ops; //挂载网络设备ops
----register_netdevice() //注册网络设备
------call_netdevice_notifiers(NETDEV_POST_INIT, dev);//通知协议,一个新的net_device出现了
------netdev_register_kobject()
--------dev_set_name(dev, "%s", ndev->name);
--------device_add(dev); //在目录/sys/class/net/wlan%d 网络设备节点1)如前面框架所提到的,fullmac方式需要实现传统网络子系统中的netdev_ops;
2)从这里来看,5.15内核与4.19内核也没有接口上的差异3、AIC中的aic_vendor.c 与 genl_ops 的关联?
1)genl_ops 是generic operation,是nl80211定义的通用接口,vendor是厂商自定义接口(作为扩展用途)
2)所有的genl_ops都在nl80211.c中定义, 厂商如需要新增接口 走vendor command
3)4.19\net\wireless\nl80211.c
struct const struct genl_ops nl80211_ops[] = {{.cmd = NL80211_CMD_TRIGGER_SCAN,.doit = nl80211_trigger_scan,.policy = nl80211_policy,.flags = GENL_UNS_ADMIN_PERM,.internal_flags = NL80211_FLAG_NEED_WDEV_UP |NL80211_FLAG_NEED_RTNL,},必须使用合法注册的厂商OUI(避免冲突)
}4)vendor_command 厂商自定义命令
wiphy_vendor_command 是Linux 无线子系统 (cfg80211) 中用于实现厂商特定命令的核心结构体。它允许 Wi-Fi 芯片厂商在不修改内核主线代码的情况下,扩展自定义功能和控制接口。wifi_driver\aic8800_fdrv\aic_vendor.c
android\kernel\fusion\4.19\include\net\cfg80211.h
struct nl80211_vendor_cmd_info {__u32 vendor_id;__u32 subcmd;
};vendor_id 必须使用合法注册的厂商OUI(避免冲突)
#define GOOGLE_OUI 0x001A11
#define BRCM_OUI 0x001018struct wiphy_vendor_command {struct nl80211_vendor_cmd_info info;u32 flags;int (*doit)(struct wiphy *wiphy, struct wireless_dev *wdev,const void *data, int data_len);int (*dumpit)(struct wiphy *wiphy, struct wireless_dev *wdev,struct sk_buff *skb, const void *data, int data_len,unsigned long *storage);
};const struct wiphy_vendor_command aicwf_vendor_cmd[] = {{{.vendor_id = GOOGLE_OUI,.subcmd = WIFI_OFFLOAD_SUBCMD_START_MKEEP_ALIVE},.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,.doit = aicwf_vendor_start_mkeep_alive,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0).dumpit = aicwf_dump_interface, //空函数
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0).policy = aicwf_cfg80211_mkeep_alive_policy,.maxattr = MKEEP_ALIVE_ATTRIBUTE_MAX
#endif},
}5.3.0以上有这个接口
aicwf_cfg80211_mkeep_alive_policy()在哪里初始化?
rwnx_cfg80211_init
--aicwf_vendor_init(wiphy)
8、内核模块mac80211(softmac)
1)mac80211所在的层级
回顾一下
1、mac80211以上的层级 - fullmac和softmac都是一样的;
2、可以看出mac80211提供API给驱动程序使用,作为中间层(实现非常复杂,充斥着大量的细节),与其他子系统合作实现;实现驱动程序,将方法挂接到mac80211层级对应结构体即可;
2)802.11 MAC帧
1、在mac80211层会对网络包进行封装,把MAC控制信息 打包到数据包中;
2、空中包是MAC帧?可以称为MAC帧,因为网络包 最底层的打包环节是MAC层;
3、MAC帧头
对应的结构体
struct ieee80211_hdr {__le16 frame_control;__le16 duration_id;u8 addr1[ETH_ALEN];u8 addr2[ETH_ALEN];u8 addr3[ETH_ALEN];__le16 seq_ctrl;u8 addr4[ETH_ALEN];
} __packed __aligned(2);802.11中有3种数据包:
IEEE80211_FTYPE_MGMT - 执行管理操作-关联、身份验证、扫描
IEEE80211_FTYPE_CTL - 流量控制
IEEE80211_FTYPE_DATA
4、wireshark中的MAC帧
3)代码分析
1、术语:
minstrel : 歌手艺人,先进的控制无线传输速率控制算法
minstrel_ht:支持HT/VHT速率(802.11n/ac)HT : hight throughput
tim : Traffic Indication Map 流量指示映射
DTIM : Delivery team2、管理架构
MAC层管理实体(MAC Layer Management Entity, MLME)- 扫描、身份验证、关联
物理层管理实体 (Physical Layer Management Entity, PLME)
系统管理实体(System Management Entity, SME)Entity可以理解为该层级对应的具体软件实现3、mac80211层初始化
android\kernel\fusion\4.19\net\mac80211\main.c
static int __init ieee80211_init(void)
{ret = rc80211_minstrel_init();ret = rc80211_minstrel_ht_init();ret = ieee80211_iface_init();
}static void __exit ieee80211_exit(void)
{rc80211_minstrel_ht_exit();rc80211_minstrel_exit();ieee80211s_stop();ieee80211_iface_exit();rcu_barrier();
}subsys_initcall(ieee80211_init);
module_exit(ieee80211_exit);4、重要头文件
1)android\kernel\fusion\4.19\net\mac80211\ieee80211_i.h
2)android\kernel\fusion\4.19\include\net\mac80211.h
struct ieee80211_hw { //表示硬件信息struct ieee80211_conf conf;struct wiphy *wiphy;void *priv;
}
int ieee80211_register_hw(struct ieee80211_hw *hw)
struct ieee80211_hw *ieee80211_alloc_hw_nm(const struct ieee80211_ops *ops)
struct ieee80211_ops {void (*tx)(struct ieee80211_hw *hw,struct ieee80211_tx_control *control,struct sk_buff *skb);int (*start)(struct ieee80211_hw *hw);void (*stop)(struct ieee80211_hw *hw);int (*add_interface)(struct ieee80211_hw *hw,struct ieee80211_vif *vif);int (*config)(struct ieee80211_hw *hw, u32 changed);
}3)sta_info(STA客户端信息)
android\kernel\fusion\4.19\net\mac80211\sta_info.hstruct sta_info {struct list_head list, free_list;struct rcu_head rcu_head;struct rhlist_head hash_node;struct ieee80211_sta sta;
}int sta_info_insert(struct sta_info *sta);
int sta_info_init(struct ieee80211_local *local);5、MAC层管理接口
1)scan
android\kernel\fusion\4.19\net\mac80211\util.c
android\kernel\fusion\4.19\net\mac80211\scan.c
ieee80211_send_probe_req()
ieee80211_request_scan()
ieee80211_hw_config(IEEE80211_CONF_CHANGE_CHANNEL) //信道切换2)auth
android\kernel\fusion\4.19\net\mac80211\util.c
ieee80211_send_auth()3)associate
android\kernel\fusion\4.19\net\mac80211\mlme.c
ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)4、rx.c - 接收数据包
android\kernel\fusion\4.19\net\mac80211\rx.c
void ieee80211_rx_napi(struct ieee80211_hw *hw, struct ieee80211_sta *pubsta,struct sk_buff *skb, struct napi_struct *napi) {ieee80211_rx_monitor();__ieee80211_rx_handle_packet();
}void ieee80211_rx_irqsafe(struct ieee80211_hw *hw, struct sk_buff *skb)5、tx.c - 发送数据包
android\kernel\fusion\4.19\net\mac80211\tx.c
struct bool ieee80211_tx(struct ieee80211_sub_if_data *sdata, struct sta_info *sta, struct sk_buff *skb,
bool txpending, u32 txdata_flags) {ieee80211_tx_prepare();__ieee80211_tx();
}其它
1)数据包聚合 - 将多个应用程序的数据包合并成一个传输帧技术,提高吞吐量
AMSDU : 聚合的MAC服务数据单元
AMPDU : 聚合的MAC协议数据单元
/android/kernel/fusion/4.19/net/mac80211/agg-tx.c
ieee80211_send_addba_request() - 驱动中调用2)
HWMP (Hybrid Wireless Mesh Protocol) 默认路由选择协议
hwmp_preq_frame_process()
9、内核模块cfg80211 + mac80211方式实现的驱动分析(softmac)
1)如前面框架所提到的,softmac方式不再实现传统网络子系统中的netdev_ops,而是struct ieee80211_ops,其它方面是一样的;2)比如atbm6032x的实现
wifi_driver/hal_apollo/mac80211/cfg.c
struct cfg80211_ops mac80211_config_ops = {.auth = ieee80211_auth,
}android\kernel\fusion\4.19\net\mac80211\mlme.c
ieee80211_auth()
--ieee80211_send_auth()
----ieee80211_tx_skb()
------ieee80211_tx_skb_tid()
--------__ieee80211_tx_skb_tid_band()
----------ieee80211_xmit()
------------ieee80211_tx() //最终到达WIFI芯片
USB无线适配器枚举过程(mac80211版本)
创建网络设备过程: