wpa_supplicant下行接口淺析(轉)

wpa_supplicant通過socket通信機制實現下行接口,與內核進行通信,獲取信息或下發命令。

 

以下摘自http://blog.csdn.net/fxfzz/article/details/6176414 ,該文章應該主要是分析wpa_supplicant_6的,和wpa_supplicant_8確實存在一些差別!!!以下還是根據6來分析。

 

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, Broadcomipw, 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接口(wpa_supplicant_8中沒有創建PF_NETLINK socket接口),然後通過這兩個接口完成與kernel的信息交互。

 

wext提供的一個主要數據結構爲:

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接口。

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,感覺變動不大,還是可以參考一下底層這一部分的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章