struct socket 數據結構 interface network callback html
啓動命令數組
Wpa_supplicant提供的接口socket
wpa supplicant 在啓動時,啓動命令能夠帶有不少參數,目前咱們的啓動命令以下:
wpa_supplicant /system/bin/wpa_supplicant -Dwext -ieth0 -c/data/wifi/wpa_supplicant.conf -f/data/wifi/wpa_log.txt
wpa_supplicant對於啓動命令帶的參數,用了兩個數據結構來保存,
一個是 wpa_params, 另外一個是wpa_interface.
這主要是考慮到wpa_supplicant是能夠同時支持多個網絡接口的。
wpa_params數據結構主要記錄與網絡接口無關的一些參數設置。
而每個網絡接口就用一個wpa_interface數據結構來記錄。
在啓動命令行中,能夠用-N來指定將要描述一個新的網絡接口,對於一個新的網絡接口,能夠用下面六個參數描述:
-i<ifname> : 網絡接口名稱
-c<conf>: 配置文件名稱
-C<ctrl_intf>: 控制接口名稱
-D<driver>: 驅動類型
-p<driver_param>: 驅動參數
-b<br_ifname>: 橋接口名稱
在這個函數中,主要作了四件事。
a. 解析命令行傳進的參數。
b. 調用wpa_supplicant_init()函數,作wpa_supplicant的初始化工做。
c. 調用wpa_supplicant_add_iface()函數,增長網絡接口。
d. 調用wpa_supplicant_run()函數,讓wpa_supplicant真正的run起來。
a. 打開debug 文件。
b. 註冊EAP peer方法。
c. 申請wpa_global內存,該數據結構做爲統領其餘數據結構的一個核心, 主要包括四個部分:
wpa_supplicant *ifaces /*每一個網絡接口都有一個對應的wpa_supplicant數據結構,該指針指向最近加入的一個,在wpa_supplicant數據結構中有指針指向next*/
wpa_params params /*啓動命令行中帶的通用的參數*/
ctrl_iface_global_priv *ctrl_iface /*global 的控制接口*/
ctrl_iface_dbus_priv *dbus_ctrl_iface /*dbus 的控制接口*/
d. 設置wpa_global中的wpa_params中的參數。
e. 調用eloop_init函數將全局變量eloop中的user_data指針指向wpa_global。
f. 調用wpa_supplicant_global_ctrl_iface_init函數初始化global 控制接口。
g. 調用wpa_supplicant_dbus_ctrl_iface_init函數初始化dbus 控制接口。
h. 將該daemon的pid寫入pid_file中。
該函數根據啓動命令行中帶有的參數增長網絡接口, 有幾個就增長几個。
a. 由於wpa_supplicant是與網絡接口對應的重要的數據結構,因此,首先分配一個wpa_supplicant數據結構的內存。
b. 調用wpa_supplicant_init_iface() 函數來作網絡接口的初始工做,主要包括:
設置驅動類型,默認是wext;
讀取配置文件,並將其中的信息設置到wpa_supplicant數據結構中的conf 指針指向的數據結構,它是一個wpa_config類型;
命令行設置的控制接口ctrl_interface和驅動參數driver_param覆蓋配置文件裏設置,命令行中的優先;
拷貝網絡接口名稱和橋接口名稱到wpa_config數據結構;
對於網絡配置塊有兩個鏈表描述它,一個是 config->ssid,它按照配置文件中的順序依次掛載在這個鏈表上,還有一個是pssid,它是一個二級指針,指向一個指針數組,該指針數組按照優先級從高到底的順序依次保存wpa_ssid指針,相同優先級的在同一鏈表中掛載。
c. 調用wpa_supplicant_init_iface2() 函數,主要包括:
調用wpa_supplicant_init_eapol()函數來初始化eapol;
調用相應類型的driver的init()函數;
設置driver的param參數;
調用wpa_drv_get_ifname()函數得到網絡接口的名稱,對於wext類型的driver,沒有這個接口函數;
調用wpa_supplicant_init_wpa()函數來初始化wpa,並作相應的初始化工做;
調用wpa_supplicant_driver_init()函數,來初始化driver接口參數;在該函數的最後,會
wpa_s->prev_scan_ssid = BROADCAST_SSID_SCAN;
wpa_supplicant_req_scan(wpa_s, interface_count, 100000);
來主動發起scan,
調用wpa_supplicant_ctrl_iface_init()函數,來初始化控制接口;對於UNIX SOCKET這種方式,其本地socket文件是由配置文件裏的ctrl_interface參數指定的路徑加上網絡接口名稱;
初始化完成以後,讓wpa_supplicant的main event loop run起來。
在wpa_supplicant中,有許多與外界通訊的socket,它們都是須要註冊到eloop event模塊中的,具體地說,就是在eloop_sock_table中增長一項記錄,其中包括了sock_fd, handle, eloop_data, user_data。
eloop event模塊就是將這些socket組織起來,統一管理,而後在eloop_run中利用select機制來管理socket的通訊。
從通訊層次上劃分,wpa_supplicant提供向上的控制接口 control interface,用於與其餘模塊(如UI)進行通訊,其餘模塊能夠經過control interface 來獲取信息或下發命令。Wpa_supplicant經過socket通訊機制實現下行接口,與內核進行通訊,獲取信息或下發命令。
Wpa_supplicant提供兩種方式的上行接口。一種基於傳統dbus機制實現與其餘進程間的IPC通訊;另外一種經過Unix domain socket機制實現進程間的IPC通訊。
該接口主要在文件「ctrl_iface_dbus.h」,「ctrl_iface_dbus.c」,「ctrl_iface_dbus_handler.h」和「ctrl_iface_dbus_handler.c」中實現,提供一些基本的控制方法。
DBusMessage * wpas_dbus_new_invalid_iface_error(DBusMessage *message);
DBusMessage * wpas_dbus_global_add_interface(DBusMessage *message,
struct wpa_global *global);
DBusMessage * wpas_dbus_global_remove_interface(DBusMessage *message,
struct wpa_global *global);
DBusMessage * wpas_dbus_global_get_interface(DBusMessage *message,
struct wpa_global *global);
DBusMessage * wpas_dbus_global_set_debugparams(DBusMessage *message,
struct wpa_global *global);
DBusMessage * wpas_dbus_iface_scan(DBusMessage *message,
struct wpa_supplicant *wpa_s);
DBusMessage * wpas_dbus_iface_scan_results(DBusMessage *message,
struct wpa_supplicant *wpa_s);
DBusMessage * wpas_dbus_bssid_properties(DBusMessage *message,
struct wpa_supplicant *wpa_s,
struct wpa_scan_res *res);
DBusMessage * wpas_dbus_iface_capabilities(DBusMessage *message,
struct wpa_supplicant *wpa_s);
DBusMessage * wpas_dbus_iface_add_network(DBusMessage *message,
struct wpa_supplicant *wpa_s);
DBusMessage * wpas_dbus_iface_remove_network(DBusMessage *message,
struct wpa_supplicant *wpa_s);
DBusMessage * wpas_dbus_iface_set_network(DBusMessage *message,
struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid);
DBusMessage * wpas_dbus_iface_enable_network(DBusMessage *message,
struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid);
DBusMessage * wpas_dbus_iface_disable_network(DBusMessage *message,
struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid);
DBusMessage * wpas_dbus_iface_select_network(DBusMessage *message,
struct wpa_supplicant *wpa_s);
DBusMessage * wpas_dbus_iface_disconnect(DBusMessage *message,
struct wpa_supplicant *wpa_s);
DBusMessage * wpas_dbus_iface_set_ap_scan(DBusMessage *message,
struct wpa_supplicant *wpa_s);
DBusMessage * wpas_dbus_iface_set_smartcard_modules(
DBusMessage *message, struct wpa_supplicant *wpa_s);
DBusMessage * wpas_dbus_iface_get_state(DBusMessage *message,
struct wpa_supplicant *wpa_s);
DBusMessage * wpas_dbus_iface_get_scanning(DBusMessage *message,
struct wpa_supplicant *wpa_s);
DBusMessage * wpas_dbus_iface_set_blobs(DBusMessage *message,
struct wpa_supplicant *wpa_s);
DBusMessage * wpas_dbus_iface_remove_blobs(DBusMessage *message,
struct wpa_supplicant *wpa_s);
該接口主要在文件「wpa_ctrl.h」,「wpa_ctrl.c」,「ctrl_iface_unix.c」,「ctrl_iface.h」和「ctrl_iface.c」實現。
(1)「wpa_ctrl.h」,「wpa_ctrl.c」完成對control interface的封裝,對外提供統一的接口。其主要的工做是經過Unix domain socket創建一個control interface 的client結點,與做爲server的wpa_supplicant結點通訊。
主要功能函數:
struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path);
/* 創建並初始化一個Unix domain socket的client結點,並與做爲server的wpa_supplicant結點綁定 */
void wpa_ctrl_close(struct wpa_ctrl *ctrl);
/* 撤銷並銷燬已創建的Unix domain socket的client結點 */
int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
char *reply, size_t *reply_len,
void (*msg_cb)(char *msg, size_t len));
/* 用戶模塊直接調用該函數對wpa_supplicant發送命令並獲取所需信息
* 能夠發送的命令如附件1所示 */
Note:
Wpa_supplicant 提供兩種由外部模塊獲取信息的方式:一種是外部模塊經過發送request 命令而後獲取response的問答模式,另外一種是wpa_supplicant主動向外部發送event事件,由外部模塊監聽接收。
通常的經常使用作法是外部模塊經過調用wpa_ctrl_open()兩次,創建兩個control interface接口,一個爲ctrl interface,用於發送命令,獲取信息,另外一個爲monitor interface,用於監聽接收來自於wpa_supplicant的event時間。此舉能夠下降通訊的耦合性,避免response和event的相互干擾。
int wpa_ctrl_attach(struct wpa_ctrl *ctrl);
/* 註冊 某個 control interface 做爲 monitor interface */
int wpa_ctrl_detach(struct wpa_ctrl *ctrl);
/* 撤銷某個 monitor interface 爲 普通的 control interface */
int wpa_ctrl_pending(struct wpa_ctrl *ctrl);
/* 判斷是否有掛起的event 事件 */
int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len);
/* 獲取掛起的event 事件 */
(2)「ctrl_iface_unix.c」實現wpa_supplicant的Unix domain socket通訊機制中server結點,完成對client結點的響應。
其中最主要的兩個函數爲:
static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
void *sock_ctx)
/* 接收並解析client發送request命令,而後根據不一樣的命令調用底層不一樣的處理函數;
* 而後將得到response結果回饋到 client 結點。
*/
static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv,
int level, const char *buf,
size_t len)
/* 向註冊的monitor interfaces 主動發送event事件 */
(3)「ctrl_iface.h」和「ctrl_iface.c」主要實現了各類request命令的底層處理函數。
Wpa_supplicant提供的下行接口主要用於和kernel(driver)進行通訊,下發命令和獲取信息。
Wpa_supplicant下行接口主要包括三種重要的接口:
1. PF_INET socket接口,主要用於向kernel 發送ioctl命令,控制並獲取相應信息。
2. PF_NETLINK socket接口,主要用於接收kernel發送上來的event 事件。
3. PF_PACKET socket接口,主要用於向driver傳遞802.1X報文。
主要涉及到的文件包括:「driver.h」,「drivers.c」,「driver_wext.h」,「driver_wext.c」,「l2_packet.h」和「l2_packet_linux.c」。其中「driver.h」,「drivers.c」,「driver_wext.h」和「driver_wext.c」實現PF_INET socket接口和PF_NETLINK socket接口;「l2_packet.h」和「l2_packet_linux.c」實現PF_PACKET socket接口。
(1)「driver.h」,「drivers.c」主要用於封裝底層差別對外顯示一個相同的wpa_driver_ops接口。Wpa_supplicant可支持atmel, Broadcom, ipw, madwifi, ndis, nl80211, wext等多種驅動。
其中一個最主要的數據結構爲wpa_driver_ops, 其定義了driver相關的各類操做接口。
(2)「driver_wext.h」,「driver_wext.c」實現了wext形式的wpa_driver_ops,並建立了PF_INET socket接口和PF_NETLINK socket接口,而後經過這兩個接口完成與kernel的信息交互。
Wext提供的一個主要數據結構爲:
struct wpa_driver_wext_data {
void *ctx;
int event_sock;
int ioctl_sock;
int mlme_sock;
char ifname[IFNAMSIZ + 1];
int ifindex;
int ifindex2;
int if_removed;
u8 *assoc_req_ies;
size_t assoc_req_ies_len;
u8 *assoc_resp_ies;
size_t assoc_resp_ies_len;
struct wpa_driver_capa capa;
int has_capability;
int we_version_compiled;
/* for set_auth_alg fallback */
int use_crypt;
int auth_alg_fallback;
int operstate;
char mlmedev[IFNAMSIZ + 1];
int scan_complete_events;
};
其中event_sock 爲PF_NETLINK socket接口,ioctl_sock爲PF_INET socket藉口。
Driver_wext.c實現了大量底層處理函數用於實現wpa_driver_ops操做參數,其中比較重要的有:
void * wpa_driver_wext_init(void *ctx, const char *ifname);
/* 初始化wpa_driver_wext_data 數據結構,並建立PF_NETLINK socket和 PF_INET socket 接口 */
void wpa_driver_wext_deinit(void *priv);
/* 銷燬wpa_driver_wext_data 數據結構,PF_NETLINK socket和 PF_INET socket 接口 */
static void wpa_driver_wext_event_receive(int sock, void *eloop_ctx,
void *sock_ctx);
/* 處理kernel主動發送的event事件的 callback 函數 */
最後,將實現的操做函數映射到一個全局的wpa_driver_ops類型數據結構 wpa_driver_wext_ops中。
const struct wpa_driver_ops wpa_driver_wext_ops = {
.name = "wext",
.desc = "Linux wireless extensions (generic)",
.get_bssid = wpa_driver_wext_get_bssid,
.get_ssid = wpa_driver_wext_get_ssid,
.set_wpa = wpa_driver_wext_set_wpa,
.set_key = wpa_driver_wext_set_key,
.set_countermeasures = wpa_driver_wext_set_countermeasures,
.set_drop_unencrypted = wpa_driver_wext_set_drop_unencrypted,
.scan = wpa_driver_wext_scan,
.get_scan_results2 = wpa_driver_wext_get_scan_results,
.deauthenticate = wpa_driver_wext_deauthenticate,
.disassociate = wpa_driver_wext_disassociate,
.set_mode = wpa_driver_wext_set_mode,
.associate = wpa_driver_wext_associate,
.set_auth_alg = wpa_driver_wext_set_auth_alg,
.init = wpa_driver_wext_init,
.deinit = wpa_driver_wext_deinit,
.add_pmkid = wpa_driver_wext_add_pmkid,
.remove_pmkid = wpa_driver_wext_remove_pmkid,
.flush_pmkid = wpa_driver_wext_flush_pmkid,
.get_capa = wpa_driver_wext_get_capa,
.set_operstate = wpa_driver_wext_set_operstate,
};
(3)「l2_packet.h」和「l2_packet_linux.c」主要用於實現PF_PACKET socket接口,經過該接口,wpa_supplicant能夠直接將802.1X packet發送到L2層,而不通過TCP/IP協議棧。
其中主要的功能函數爲:
struct l2_packet_data * l2_packet_init(
const char *ifname, const u8 *own_addr, unsigned short protocol,
void (*rx_callback)(void *ctx, const u8 *src_addr,
const u8 *buf, size_t len),
void *rx_callback_ctx, int l2_hdr);
/* 建立並初始化PF_PACKET socket接口,其中rx_callback 爲從L2接收到的packet 處理callback函數 */
void l2_packet_deinit(struct l2_packet_data *l2);
/* 銷燬 PF_PACKET socket接口 */
int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto,
const u8 *buf, size_t len);
/* L2層packet發送函數,wpa_supplicant用此發送L2層 802.1X packet */
static void l2_packet_receive(int sock, void *eloop_ctx, void *sock_ctx);
/* L2層packet接收函數,接收來自L2層數據後,將其發送到上層 */
PING
MIB
STATUS
STATUS-VERBOSE
PMKSA
SET <variable> <valus>
LOGON
LOGOFF
REASSOCIATE
RECONNECT
PREAUTH <BSSID>
ATTACH
DETACH
LEVEL <debug level>
RECONFIGURE
TERMINATE
BSSID <network id> <BSSID>
LIST_NETWORKS
DISCONNECT
SCAN
SCAN_RESULTS
BSS
SELECT_NETWORK <network id>
ENABLE_NETWORK <network id>
DISABLE_NETWORK <network id>
ADD_NETWORK
REMOVE_NETWORK <network id>
SET_NETWORK <network id> <variable> <value>
GET_NETWORK <network id> <variable>
SAVE_CONFIG