【轉載】Android WiFi 架構總覽(模塊及接口)

原文地址:https://blog.csdn.net/xusiwei1236/article/details/48495485java

Android WiFi 架構總覽

本文介紹Android源碼項目(AOSP)中WiFi功能的軟件架構及各個模塊(可執行文件、動態連接庫)間的接口。linux

SDK API

Android SDK爲開發者提供了WiFi編程接口,使用起來很是方便。android

相關包: 
android.net.wifi(寫App時只需import該包,便可使用WiFi相關功能)編程

主要相關類: 
WifiManager WIFI編程入口,WIFI的多數功能都以該類的方法的形式提供 
WifiInfo 用於描述WIFI鏈接的狀態 
ScanResult 用於描述一個AP,如SSID,信號強度,安全方式等api

Overview

下圖基展現了Android系統WIFI模塊的架構(固然,這只是軟件的控制命令部分,數據部分直接經過kernel與網絡子系統、socket API交互)。 
Android WiFi 相關編譯模塊
(PS:一圖勝千言,雖然用ppt畫起來費勁) 
WifiManager是管理全部Wifi鏈接的基本API,能夠經過: 
android.content.Context.getSystemService(Context.WIFI_SERVICE) 
獲得它的實例。數組

具體 IPC(Inter-Process communication)

App & system_server(WifiManager & WifiService)

若是說Binder是鏈接 App 和 system_server 的橋樑,那麼WifiManager和WiFiService就是橋樑的兩頭。安全

framework代碼上和wifi相關的package位於: 
frameworks/base/wifi/java(WIFI相關的一些包) 
frameworks/base/services/java(各類Service,WIFI相關包爲:com.android.server.wifi)網絡

frameworks代碼中,和wifi相關的幾個類的關係以下:多線程

  • WifiService繼承自IWifiManager.Stub;
  • IWifiManager.Stub又繼承自Binder,同時實現了IWifiManager接口;
  • WifiManager.Stu.proxy也實現了IWifiManager接口;

如圖: 
WiFi相關的class架構

其中,IWifiManager, IWifiManager.Stub, IWifiManager.Stub.Proxy都由IWifiManger.aidl生成; 
aidl自動生成相關的java代碼,簡化了用Binder實現RPC的過程。 
IWifiManager.Stub.Proxy,WifiManager,BinberProxy用於客戶端(App進程); 
而IWifiManager.Stub,WifiService,Binder用於服務端(SystemServer進程)。

App 與 system_server 經過Binder通訊,但Binder自己只實現了IPC,即相似socket通訊的能力。而App端的WifiManager和system_server端的WifiService及Binder等類共同實現了RPC(remote procedure call)。

WifiManager只是系統爲app提供的接口。Context.getSystemService(Context.WIFI_SERVICE) 
返回的實際對象類型是IWifiManager.Stub.Proxy。 
IWifiManager.Stub.Proxy的實例是位於App端的一個代理,代理象IWifiManager.Stub.Proxy 
將WifiManager方法的參數序列化到Parcel,再經Binder發送給system_server進程。

system_server內的WifiService收App傳來的WifiManager調用,完成實際工做。 
這樣,實際和下層通訊的工做就由App轉移到了system_server進程(WifiService對象)。

WifiStateMachine

另外,能夠看到 WifiStateMachine 是wifi功能的樞紐,幾種不一樣模式下的控制流程都經它流下。 
當WIFI處在STA模式(或P2P模式)時,經過WifiNative與wpa_supplicant交互。 
WifiNative定義了幾個Native方法:

 1     public native static boolean setMaxTxPower(int txpower, boolean sapRunning);  2 
 3     public native static boolean loadDriver();  4 
 5     public native static boolean isDriverLoaded();  6 
 7     public native static boolean unloadDriver();  8 
 9     public native static boolean startSupplicant(boolean p2pSupported, int firstScanDelay); 10 
11     /* Sends a kill signal to supplicant. To be used when we have lost connection 12  or when the supplicant is hung */
13     public native static boolean killSupplicant(boolean p2pSupported); 14 
15     private native boolean connectToSupplicantNative(); 16 
17     private native void closeSupplicantConnectionNative(); 18 
19     /** 20  * Wait for the supplicant to send an event, returning the event string. 21  * @return the event string sent by the supplicant. 22      */
23     private native String waitForEventNative(); 24 
25     private native boolean doBooleanCommandNative(String command); 26 
27     private native int doIntCommandNative(String command); 28 
29     private native String doStringCommandNative(String command);

 

當WIFI處在AP模式。經過NetworkManagementService與netd交互,具體是經過LocalSocket(Framework封裝的UNIX域socket)與netd進程通訊。 
好比,NetworkManagementService.startAccessPoint方法:

 1  @Override  2     public void startAccessPoint(  3  WifiConfiguration wifiConfig, String wlanIface) {  4  mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);  5         try {  6             wifiFirmwareReload(wlanIface, "AP");  7             if (wifiConfig == null) {  8                 mConnector.execute("softap", "set", wlanIface); // 向 netd 發送控制命令
 9             } else { 10                 mConnector.execute("softap", "set", wlanIface, wifiConfig.SSID, 11                                    wifiConfig.hiddenSSID ? "hidden" : "broadcast", 12                                    "1", getSecurityType(wifiConfig), 13                                    new SensitiveArg(wifiConfig.preSharedKey)); 14  } 15             mConnector.execute("softap", "startap"); 16         } catch (NativeDaemonConnectorException e) { 17             throw e.rethrowAsParcelableException(); 18  } 19     }

 

WifiNative

從功能上來講,WifiNative是system_server 和 wpa_supplicant 對話的窗口,實際上主要依靠wpa_supplicant項目編譯出來的動態庫libwpa_client.so。

WifiNative的幾個native方法的具體實如今: 
frameworks/base/core/jni/android_net_wifi_WifiNative.cpp

WifiNative的native方法的實現:

 1 static JNINativeMethod gWifiMethods[] = {  2     /* name, signature, funcPtr */
 3     { "loadDriver", "()Z",  (void *)android_net_wifi_loadDriver },  4     { "isDriverLoaded", "()Z",  (void *)android_net_wifi_isDriverLoaded },  5     { "unloadDriver", "()Z",  (void *)android_net_wifi_unloadDriver },  6     { "startSupplicant", "(ZI)Z",  (void *)android_net_wifi_startSupplicant },  7     { "killSupplicant", "(Z)Z",  (void *)android_net_wifi_killSupplicant },  8     { "connectToSupplicantNative", "()Z", (void *)android_net_wifi_connectToSupplicant },  9     { "closeSupplicantConnectionNative", "()V", (void *)android_net_wifi_closeSupplicantConnection }, 10     { "waitForEventNative", "()Ljava/lang/String;", (void*)android_net_wifi_waitForEvent }, 11     { "doBooleanCommandNative", "(Ljava/lang/String;)Z", (void*)android_net_wifi_doBooleanCommand }, 12     { "doIntCommandNative", "(Ljava/lang/String;)I", (void*)android_net_wifi_doIntCommand }, 13     { "doStringCommandNative", "(Ljava/lang/String;)Ljava/lang/String;", (void*) android_net_wifi_doStringCommand }, 14     { "setMaxTxPower", "(IZ)Z",  (void *)android_net_wifi_setMaxTxPower }, 15 };

 

android_net_wifi_WifiNative.cpp 並無作多少實際工做,大可能是直接調用 wifi.h wifi_maxtxpower.h 定義的函數: 
wifi.h 的具體實如今 hardware/libhardware_legacy/wifi/wifi.c (會被編譯爲 libhardware_legacy.so) 
wifi_maxtxpower.h 的具體實如今 hardware/qcom/wlan/libmaxtxpower/wifi_maxtxpower.c (會被編譯爲 libmaxtxpower.so) 
因此native代碼依賴libhardware_legacy.so模塊、libmaxtxpower.so模塊。

WIFI HAL

實現SystemServer與wpa_supplicant(hostapd)通訊的,即Wifi HAL。 
Wifi HAL封裝了UNIX域socket,SystemServer經過UNIX域socket與wpa_supplicant(hostapd) 
通訊;SystemServer發送的消息和wpa_supplicant響應的消息都是爲ASCII字符串。

Wifi HAL代碼主要分佈在: 
hardware/libhardware_legacy/wifi 
hardware/qcom/wlan/libmaxtxpower

分別被編譯爲: 
hardware/libhardware_legacy/wifi -> libhardware_legacy.so 
hardware/qcom/wlan/libmaxtxpower -> libmaxtxpower.so

wifi.h定義了WIFI HAL的接口,具體函數有:

 1 // 驅動相關:
 2 int wifi_load_driver();  3 int wifi_unload_driver();  4 int is_wifi_driver_loaded();  5 
 6 // supplicant相關:
 7 int wifi_start_supplicant(int p2pSupported, int first_scan_delay);  8 int wifi_stop_supplicant(int p2pSupported);  9 int wifi_connect_to_supplicant(); 10 void wifi_close_supplicant_connection(); 11 
12 // 等待WIFI事發生,該函數會阻塞當前調用,直到有wifi事件發生時,返回一個表示wifi事件的字符
13 int wifi_wait_for_event(char *buf, size_t len); 14 
15 // 向wifi驅動發一個命,(多數功能經該函數向下層發命令)
16 int wifi_command(const char *command, char *reply, size_t *reply_len); 17 
18 // 發起一dhcp請求
19 int do_dhcp_request(int *ipaddr, int *gateway, int *mask, 20                    int *dns1, int *dns2, int *server, int *lease); 21 
22 // 返回一個do_dhcp_request()的錯誤字符串
23 const char *get_dhcp_error_string(); 24 
25 #define WIFI_GET_FW_PATH_STA    0
26 #define WIFI_GET_FW_PATH_AP     1
27 #define WIFI_GET_FW_PATH_P2P    2
28 
29 // 返一個請的firmware路徑
30 const char *wifi_get_fw_path(int fw_type); 31 
32 // 爲wlan驅動改變firmware路徑
33 int wifi_change_fw_path(const char *fwpath); 34 
35 #define WIFI_ENTROPY_FILE   "/data/misc/wifi/entropy.bin"
36 
37 int ensure_entropy_file_exists();

 

wifi_maxtxpower.h 只定義了一個函數:

int set_max_tx_power(int power, int sap_running);
  • 1

android_net_wifi_WifiNative.cpp 調用了這些函數。 
wifi.c調用了wpa_ctrl.h定義的一些函數,而wpa_ctrl.h中的函數 
在external/wpa_supplicant_8 項目實現,並被編譯爲libwpa_client.so, 
詳見external/wpa_supplicant_8/Android.mk。

wpa_supplicant(hostapd)

代碼位於: 
external/wpa_supplicant_8 
該項目內包含兩個互相相關的開源項目wpa_supplicant和hostapd,它們將會生成兩個可執行文件: 
wpa_supplicant和hostapd,分別爲STA模式和AP模式時的守護進程。

除此以外,還會生成用於測試的wpa_cli,hostapd_cli, 
以及WIFI HAL依賴的wpa_client.so,具體能夠到Android.mk中找到。

wpa_supplicant源碼結構和hostapd相似,下面只介紹wpa_supplicant。

wpa_ctrl.h 定義了與wpa_supplicant(或hostapd)進程通訊的接口:

 1 struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path);  2 
 3 // Close a control interface to wpa_supplicant/hostapd
 4 void wpa_ctrl_close(struct wpa_ctrl *ctrl);  5 
 6 // Send a command to wpa_supplicant/hostapd
 7 int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,  8              char *reply, size_t *reply_len,  9              void (*msg_cb)(char *msg, size_t len)); 10 
11 // Register as an event monitor for the control interface
12 int wpa_ctrl_attach(struct wpa_ctrl *ctrl); 13 
14 // Unregister event monitor from the control interface
15 int wpa_ctrl_detach(struct wpa_ctrl *ctrl); 16 
17 // Receive a pending control interface message
18 int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len); 19 
20 // Check whether there are pending event messages
21 int wpa_ctrl_pending(struct wpa_ctrl *ctrl); 22 
23 // Get file descriptor used by the control interface
24 int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl); 25 
26 char * wpa_ctrl_get_remote_ifname(struct wpa_ctrl *ctrl);

 

wpa_ctrl_open 建立一個UNIX域socket 與 wpa_supplicant(或hostapd)進程相連, 
wpa_ctrl_close 用於關閉wpa_ctrl_open建立的鏈接, 
wpa_ctrl_request 用於向wpa_supplicant/hostapd發送控制命令,並阻塞, 
直到wpa_supplicant/hostapd返回命令響應。控制命令和相應都是ASCII字符串。

wpa_ctrl.h除了聲明瞭這些函數外,還定義了wpa_supplicant/hostapd的一些消息,這裏沒有詳細列出。

源碼中wpa_supplicant_global_ctrl_iface_receive 
負責分派上層發來的控制命令,進而調用具體處理函數:

 1  "ATTACH" -> wpa_supplicant_ctrl_iface_attach  2  "DETACH" -> wpa_supplicant_ctrl_iface_detach  3   else -> wpa_supplicant_global_ctrl_iface_process:  4     "IFNAME="(prefix) // 多數控制命令以IFNAME=開頭
 5         -> wpas_global_ctrl_iface_ifname  6             -> wpa_supplicant_ctrl_iface_process # "IFNAME="開頭的命令的處理  7  wpas_global_ctrl_iface_redir  8         -> wpas_global_ctrl_iface_redir_p2p  9             -> wpa_supplicant_ctrl_iface_process # "IFNAME="開頭的命令的處理 10         -> wpas_global_ctrl_iface_redir_wfd 11             -> wpa_supplicant_ctrl_iface_process # "IFNAME="開頭的命令的處理 12     "PING" -> "PONG"
13     "INTERFACE_ADD" -> wpa_supplicant_global_iface_add 14     "INTERFACE_REMOVE" -> wpa_supplicant_global_iface_remove 15     "INTERFACE_LIST" -> wpa_supplicant_global_iface_list 16     "INTERFACES" -> wpa_supplicant_global_iface_interfaces 17     "TERMINATE" -> wpa_supplicant_terminate_proc 18     "SUSPEND" -> wpas_notify_suspend 19     "RESUME" -> wpas_notify_resume 20     "SET" -> wpas_global_ctrl_iface_set 21     "SAVE_CONFIG" -> wpas_global_ctrl_iface_save_config 22     "STATUS" -> wpas_global_ctrl_iface_status

 

該函數在wpa_supplicant目錄下的 
ctrl_iface_unix.cctrl_iface_udp.c內都有實現,可由該目錄下的android.config切換 
(android.config被Android.mk包含,具體參見Android.mk)

wpa_supplicant與內核通訊

wpa_supplicant的運行模型是單進程單線程的 Reactor(IO multiplexing)。wpa_supplicant經過NETLINK socket與內核通訊。

wpa_supplicant項目支持多種驅動編程接口,在Android上使用的是nl80211;

nl80211是新的802.11netlink接口公共頭,與cfg80211一同組成了Wireless-Extensions的替代方案。 
cfg80211是Linux 802.11配置API, nl80211用於配置cfg80211設備,同時用於內核到用戶空間的通訊。

實際使用nl80211時,只須要在程序中包含頭文件

wireless module(in kernel)

代碼位於: 
kernel/net/wireless

nl80211.c 中的 nl80211_init 使用genl_register_family_with_ops 註冊了響應應用程序的 
struct genl_ops nl80211_ops[], 該數組定義了響應NETLINK消息的函數。

而 nl80211_init 在 cfg80211_init 內被調用,cfg80211_init是被subsys_initcall註冊的 
子系統初始化程序,被編譯爲cfg80211.ko。

nl80211_ops[] 節選:

 1 static struct genl_ops nl80211_ops[] = {  2     // ...
 3  {  4         .cmd = NL80211_CMD_TRIGGER_SCAN,  5         .doit = nl80211_trigger_scan,  6         .policy = nl80211_policy,  7         .flags = GENL_ADMIN_PERM,  8         .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
 9  NL80211_FLAG_NEED_RTNL, 10  }, 11  { 12         .cmd = NL80211_CMD_GET_SCAN, 13         .policy = nl80211_policy, 14         .dumpit = nl80211_dump_scan, 15  }, 16  { 17         .cmd = NL80211_CMD_START_SCHED_SCAN, 18         .doit = nl80211_start_sched_scan, 19         .policy = nl80211_policy, 20         .flags = GENL_ADMIN_PERM, 21         .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
22  NL80211_FLAG_NEED_RTNL, 23  }, 24  { 25         .cmd = NL80211_CMD_STOP_SCHED_SCAN, 26         .doit = nl80211_stop_sched_scan, 27         .policy = nl80211_policy, 28         .flags = GENL_ADMIN_PERM, 29         .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
30  NL80211_FLAG_NEED_RTNL, 31  }, 32 
33     // ...
34 };

 

wlan driver

代碼位於: 
vendor/qcom/opensource/wlan/prima

模塊初始化(module_init),模塊退出(module_exit): 
CORE/HDD/src/wlan_hdd_main.c

模型: 
多線程 + 隊列

建立內核線程: 
CORE/VOSS/src/vos_sched.c 的 vos_sched_open()

線程任務(vos_sched.c): 
* VosMcThread() - The VOSS Main Controller thread 
* VosWdThread() - The VOSS Watchdog thread 
* VosTXThread() - The VOSS Main Tx thread 
* VosRXThread() - The VOSS Main Rx thread

線程環境(context) (vos_sched.h):

 1 typedef struct _VosSchedContext  2 {  3   /* Place holder to the VOSS Context */ 
 4  v_PVOID_t pVContext;  5 
 6   /* WDA Message queue on the Main thread*/
 7  VosMqType wdaMcMq;  8 
 9    /* PE Message queue on the Main thread*/
10  VosMqType peMcMq; 11 
12    /* SME Message queue on the Main thread*/
13  VosMqType smeMcMq; 14 
15    /* TL Message queue on the Main thread */
16  VosMqType tlMcMq; 17 
18    /* SYS Message queue on the Main thread */
19  VosMqType sysMcMq; 20 
21   /* WDI Message queue on the Main thread*/
22  VosMqType wdiMcMq; 23 
24    /* WDI Message queue on the Tx Thread*/
25  VosMqType wdiTxMq; 26 
27    /* WDI Message queue on the Rx Thread*/
28  VosMqType wdiRxMq; 29 
30    /* TL Message queue on the Tx thread */
31  VosMqType tlTxMq; 32 
33    /* TL Message queue on the Rx thread */
34  VosMqType tlRxMq; 35 
36    /* SYS Message queue on the Tx thread */
37  VosMqType sysTxMq; 38 
39  VosMqType sysRxMq; 40 
41     // ...
42 
43    struct task_struct* McThread; 44 
45    /* TX Thread handle */
46 
47    struct task_struct* TxThread; 48 
49    /* RX Thread handle */
50    struct task_struct* RxThread; 51 
52     // ...
53 } VosSchedContext, *pVosSchedContext;

 

高通資料: 
80-Y0513-1_G_QCA_WCN36x0_Software_Architecture.pdf 
chapter: Android WLAN Host Software Architecture

SCAN過程跟蹤

App

 1 WifiManager wifiManager = (WifiManager)Context.getService(Contex.WIFI_SERVICE);  2 wifiManager.startScan();  3 
 4 //wifiManager --> IWifiManager.Stub.Proxy
 5 
 6 IWifiManager.Stub.Proxy implements android.net.wifi.IWifiManager  7 
 8 wifiManager.startScan()  9 -> IWifiManager.Stub.Proxy.startScan(WorkSource=null); 10 -> BinderProxy.transact(Stub.TRANSACTION_startScan, _data, _reply, 0);

 

systerm_server

wifi –> WifiService

 1 WifiService extends IWifiManager.Stub  2 
 3 IWifiManager.Stub extends android.os.Binder  4  implements android.net.wifi.IWifiManager  5 
 6 -> IWifiManager.Stub.onTransact(int code, Parcel data, Parcel reply, int flags);  7     case TRANSACTION_startScan:  8 -> WifiService.startScan(WorkSource workSource);  9 -> WifiStateMachine.startScan(int callingUid, WorkSource workSource); 10 -> StateMachine.sendMessage(CMD_START_SCAN, callingUid, 0, workSource); 11     case CMD_START_SCAN: 12 -> handleScanRequest(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message); 13 -> startScanNative(type, freqs) 14 -> WifiNative.scan(type, freqs) 15 ->  doBooleanCommand("SCAN ..."); // AF_UNIX socket, send to wpa_supplicant

 

wpa_supplicant

1 external/wpa_supplicant_8/wpa_supplicant$ grep -nr "\"SCAN " . 2 ./ChangeLog:197:      - "SCAN freq=<freq list>" can be used to specify which channels are 3 ./ChangeLog:199:      - "SCAN passive=1" can be used to request a passive scan (no Probe 4 ./ChangeLog:201:      - "SCAN use_id" can be used to request a scan id to be returned and 5 ./ChangeLog:203:      - "SCAN only_new=1" can be used to request the driver/cfg80211 to 6 ./ctrl_iface.c:6986:    } else if (os_strncmp(buf, "SCAN ", 5) == 0) { 7 ./src/drivers/driver_test.c:1289:   ret = os_snprintf(pos, end - pos, "SCAN " MACSTR, 8 ./src/drivers/driver_test.c:1994:   } else if (os_strncmp(buf, "SCAN ", 5) == 0) { 9 ./ctrl_iface.c:6986:    } else if (os_strncmp(buf, "SCAN ", 5) == 0) {

 

refer to ./ctrl_iface.c:6986

1     } else if (os_strcmp(buf, "SCAN") == 0) { 2         wpas_ctrl_scan(wpa_s, NULL, reply, reply_size, &reply_len); 3     } else if (os_strncmp(buf, "SCAN ", 5) == 0) { 4         wpas_ctrl_scan(wpa_s, buf + 5, reply, reply_size, &reply_len);

 

wpas_ctrl_scan -> wpa_supplicant_req_scan

1     int res = eloop_deplete_timeout(sec, usec, wpa_supplicant_scan, wpa_s, 2  NULL); 3     if (res == 1) { 4         wpa_dbg(wpa_s, MSG_DEBUG, "Rescheduling scan request: %d.%06d sec", 5  sec, usec); 6     }

 

wpa_supplicant_scan -> wpa_supplicant_trigger_scan

1 -> radio_add_work(wpa_s, 0, "scan", 0, wpas_trigger_scan_cb, ctx)

 

wpas_trigger_scan_cb -> wpa_drv_scan

1 static inline int wpa_drv_scan(struct wpa_supplicant *wpa_s, 2                    struct wpa_driver_scan_params *params) 3 { 4     if (wpa_s->driver->scan2) // callback
5         return wpa_s->driver->scan2(wpa_s->drv_priv, params); 6     return -1; 7 }

 

grep scan2 callback

1 external/wpa_supplicant_8/wpa_supplicant$ grep -nr "scan2\s*=" . 2 ./src/drivers/driver_wext.c:2401:   .scan2 = wpa_driver_wext_scan, 3 ./src/drivers/driver_privsep.c:726: .scan2 = wpa_driver_privsep_scan, 4 ./src/drivers/driver_test.c:2677:   .scan2 = wpa_driver_test_scan, 5 ./src/drivers/driver_bsd.c:1618:    .scan2          = wpa_driver_bsd_scan, 6 ./src/drivers/driver_nl80211.c:12612:   .scan2 = driver_nl80211_scan2, 7 ./src/drivers/driver_ndis.c:3217:   wpa_driver_ndis_ops.scan2 = wpa_driver_ndis_scan;

 

refer to ./src/drivers/driver_nl80211.c:12612

driver_nl80211_scan2 -> wpa_driver_nl80211_scan

1     msg = nl80211_scan_common(drv, NL80211_CMD_TRIGGER_SCAN, params, 2                   bss->wdev_id_set ? &bss->wdev_id : NULL); 3     if (!msg) 4         return -1;

 

use NL80211_CMD_TRIGGER_SCAN talk with kernel(cfg80211.ko)

kernel

grep NL80211_CMD_TRIGGER_SCAN in kernel source:

1 kernel$ cgrep NL80211_CMD_TRIGGER_SCAN 2 ./net/wireless/nl80211.c:9053:      .cmd = NL80211_CMD_TRIGGER_SCAN, 3 ./net/wireless/nl80211.c:9605:                NL80211_CMD_TRIGGER_SCAN) < 0) { 4 ./include/uapi/linux/nl80211.h:255: *   option to specify additional IEs in NL80211_CMD_TRIGGER_SCAN, 5 ./include/uapi/linux/nl80211.h:260: * @NL80211_CMD_TRIGGER_SCAN: trigger a new scan with the given parameters 6 ./include/uapi/linux/nl80211.h:759: NL80211_CMD_TRIGGER_SCAN, 7 ./include/uapi/linux/nl80211.h:1362: *  This attribute is used with %NL80211_CMD_TRIGGER_SCAN and 8 ./include/uapi/linux/nl80211.h:3863: * of NL80211_CMD_TRIGGER_SCAN and NL80211_CMD_START_SCHED_SCAN

 

refer to net/wireless/nl80211.c:9053

 1 static struct genl_ops nl80211_ops[] = {  2 
 3 // ... ...
 4 
 5  {  6         .cmd = NL80211_CMD_TRIGGER_SCAN,  7         .doit = nl80211_trigger_scan,  8         .policy = nl80211_policy,  9         .flags = GENL_ADMIN_PERM, 10         .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
11  NL80211_FLAG_NEED_RTNL, 12  }, 13 
14 // ... ...
15 };

 

nl80211_trigger_scan -> rdev_scan(rdev, request);

1 static inline int rdev_scan(struct cfg80211_registered_device *rdev, 2                 struct cfg80211_scan_request *request) 3 { 4     int ret; 5     trace_rdev_scan(&rdev->wiphy, request); 6     ret = rdev->ops->scan(&rdev->wiphy, request); // callback
7     trace_rdev_return_int(&rdev->wiphy, ret); 8     return ret; 9 }

轉載註明請出處(https://blog.csdn.net/xusiwei1236),勿作商用! 
歡迎評論或email(xusiwei1236@163.com)交流觀點

driver

參考高通文檔

相關文章
相關標籤/搜索