wpa_supplicant經過socket通訊機制實現下行接口,與內核進行通訊,獲取信息或下發命令。linux
如下摘自http://blog.csdn.net/fxfzz/article/details/6176414 ,該文章應該主要是分析wpa_supplicant_6的,和wpa_supplicant_8確實存在一些差異!!!如下仍是根據6來分析。android
wpa_supplicant提供的下行接口主要用於和kernel(driver)進行通訊,下發命令和獲取信息。sass
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。其中,less
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等多種驅動。socket
其中一個最主要的數據結構爲wpa_driver_ops, 其定義了driver相關的各類操做接口。函數
(2) driver_wext.h/driver_wext.c實現了wext形式的wpa_driver_ops,並建立了PF_INET socket接口和PF_NETLINK socket接口(wpa_supplicant_8中沒有建立PF_NETLINK socket接口),而後經過這兩個接口完成與kernel的信息交互。oop
wext提供的一個主要數據結構爲:spa
struct wpa_driver_wext_data { void *ctx; int event_sock; //PF_NETLINK socket接口 int ioctl_sock; //PF_INET socket接口 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接口。.net
driver_wext.c實現了大量底層處理函數用於實現wpa_driver_ops操做參數,其中比較重要的有:
/* 初始化wpa_driver_wext_data 數據結構,並建立PF_NETLINK socket和 PF_INET socket 接口 */ 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_supplicant_6上,wpa_supplicant_8中沒有.... 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協議棧。
其中主要的功能函數爲:
/* 建立並初始化PF_PACKET socket接口,其中rx_callback 爲從L2接收到的packet 處理callback函數 */ 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);
ps:l2_packet_init方法中有代碼:
eloop_register_read_sock(l2->fd, l2_packet_receive, l2, NULL);
即註冊了與socket關聯的回調方法爲l2_packet_receive。
/* 銷燬 PF_PACKET socket接口 */ void l2_packet_deinit(struct l2_packet_data *l2); /* L2層packet發送函數,wpa_supplicant用此發送L2層 802.1X packet */ int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto, const u8 *buf, size_t len); /* L2層packet接收函數,接收來自L2層數據後,將其發送到上層 */ static void l2_packet_receive(int sock, void *eloop_ctx, void *sock_ctx);
最後,附圖說明wpa_supplicant與驅動交互的過程。從該圖看,由於應用層部分還有WifiLayer類,說明android源碼應該是2.1的,比較老了。不過度析了下wpa_supplicant,感受變更不大,仍是能夠參考一下底層這一部分的。