文章目錄
- 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版本)
創建網絡設備過程: