hostapd源代碼分析(一):網絡接口和BSS的初始化


【轉】hostapd源代碼分析(一):網絡接口和BSS的初始化

原文鏈接:http://blog.csdn.net/qq_21949217/article/details/46004349

   最近在做一個基於OpenFlow 協議的無線AP 的項目,於是就分析了hostapd 的源代碼,並在原有的基礎上添加上我們的代碼。經過近半個月的調試和分析,算是基本上搞清楚了hostapd 的運作機制。鑒於網上對於hostapd 的具體資料甚是稀少,所以筆者在此整理學習筆記並在網上與各位讀者分享,希望能對讀者們有幫助。如果有分析不恰當或者錯誤的地方,也歡迎各位指正。另外,本文是在讀者已經具有IEEE 802.11 和良好C 語言的基礎的假設上寫的,因此,本文將直奔主題,對於IEEE 802.11 和C 代碼細節將不再贅述。  

       還有,筆者在分析hostapd 源代碼的時候,hostapd/supplicant 開發文檔也提供了大量的有用信息,各位讀者也可以參考。(http://w1.fi/wpa_supplicant/devel/

一、幾個重要的數據結構

        此次分析hostapd 源代碼,發現了其中出現頻率最高的兩個數據結構——struct hostapd_iface 和struct hostapd_data。其實很簡單,hostapd_iface 結構體描述了一個物理接口(比如wlan0),hostapd_data 則描述一個BSS。這兩個數據結構幾乎貫穿所有的源代碼,所以一定要搞清楚這兩個數據結構。

  • struct hostapd_iface (src/ap/hostapd.h)。在這個數據結構中,主要有以下字段:
    •  struct hostapd_config: 保存對網絡接口的配置(從配置文件hostapd.conf中加載)
    •  sizt_t num_bss: 此接口下轄的BSS 個數
    • struct hostapd_data **bss:BSS 列表,描述各BSS 的配置
  • struct hostapd_data (src/ap/hostapd.h)。在這個數據結構中,主要有以下字段:
    • struct hostapd_bss_config *conf:保存BSS 的配置信息(從配置文件hostapd.conf 中加載)
    •  u8 own_addr[ETH_ALEN]:表示此BSS 的BSSID (ETH_ALEN 為6,u8 其實是unsigned char)
    • struct wpa_driver_ops *driver:指向一組驅動程序接口,用來和內核交互。(這里是用的nl80211)  

  說到這里,也許有人會問,實際源文件中有數十個字段,難道只知道這些就足夠了嗎?我的答案是肯定的——是的,只需要知道這么多。

二、hostapd 初始化

   首先,我們打開hostapd/main.c,並找到主程序入口main()。直接跳轉到大概659 行。看到如下代碼:

for (i = 0; i < interfaces.count; i++) {  
    interfaces.iface[i] = hostapd_interface_init(&interfaces,argv[optind + i],debug);  
    if (!interfaces.iface[i]) {  
        wpa_printf(MSG_ERROR, "Failed to initialize interface");  
        goto out;  
    }  
}  

  很明顯, 這是對每個網絡接口( 或者干脆叫物理網卡也行) 的初始化。然后找到hostapd_interface_init 的定義(大概從main.c 的第234 行開始),我們看到了如下的一句話:

iface = hostapd_init(interfaces, config_fname);  

  嗯,看來,真正的初始化工作是在hostapd_init 函數中進行,並返回一個描述網絡接口的結構體(struct hostapd_iface)。然后我們再深一層的挖掘,找到hostapd_init 的定義(從src/ap/hostapd.c 的第1416 行起)。我們先看那句

conf = interfaces->config_read_cb(hapd_iface->config_file);</span>  

  這個其實就是讀取hostapd 的配置文件hostapd.conf 中的配置信息,並保存到hostapd_conf的結構體中去。之后緊接着就是為每個BSS 分配內存空間:

 1 hapd_iface->num_bss = conf->num_bss; //從配置信息中獲取BSS 的個數  
 2 hapd_iface->bss = os_calloc(conf->num_bss, sizeof(struct hostapd_data *)); //分配BSS 列表空間  
 3 if (hapd_iface->bss == NULL) //內存空間分配失敗  
 4     goto fail;  
 5 for (i = 0; i < conf->num_bss; i++) {  
 6     hapd = hapd_iface->bss[i] = hostapd_alloc_bss_data(hapd_iface, conf, conf->bss[i]); //初始化每個BSS 數據結構  
 7     if (hapd == NULL) //內存空間分配失敗  
 8         goto fail;  
 9     hapd->msg_ctx = hapd; //這句不知道啥意思,不過也無妨  
10 } 

OK,到這里,網絡接口和每個BSS 的基本初始化(即為它們分配內存)的工作結束了。回到main,跳轉到第715 行,我們看到了這句話:

1 if (hostapd_driver_init(interfaces.iface[i])||hostapd_setup_interface(interfaces.iface[i]))  
2     goto out;  

從字面上理解,那就是“初始化每個網絡接口的驅動程序”和“設置每個網絡接口”。好吧,我們先看hostapd_driver_init 函數是如何定義的。最關鍵的是在第185 行到第204 行。代碼如下:

params.bssid = b; //BSSID  
params.ifname = hapd->conf->iface; //網絡接口名稱(比如wlan0)  
params.ssid = hapd->conf->ssid.ssid; //SSID  
params.ssid_len = hapd->conf->ssid.ssid_len; //SSID 長度  
…………(這部分不重要。好吧,我承認我也不清楚是干嘛的……)  
params.own_addr = hapd->own_addr; //網絡接口的MAC 地址  
hapd->drv_priv = hapd->driver->hapd_init(hapd, &params); //將以上參數傳遞給驅動程序  

那么,問題來了,hapd_init 是怎么定義的呢?由於筆者分析的hostapd 是基於nl80211 的,所以hapd_init 指向nl80211 的初始化函數i802_init(定義在src/drivers/nl80211_driver.c 中,本文只分析hostapd 在用戶空間的工作原理,至於內核空間是如何工作的,不在本文討論之列。有興趣的讀者可以查找有關Netlink 和mac80211 的資料。筆者以后也會推出關於mac80211 的學習筆記)。好了,驅動程序初始化完了,下面我們看如何設置每個網絡接口。hostapd_setup_interface 函數定義在src/ap/hostapd.c,打開這個文件,跳到大概1315 行,里面就一句setup_interface……好吧,找到大概第1040 行,就是這個函數的定義。里面有一段話是這么說的:

1 /* 
2  * Make sure that all BSSes get configured with a pointer to the same 
3  * driver interface. 
4  */  
5 for (i = 1; i < iface->num_bss; i++) {  
6     iface->bss[i]->driver = hapd->driver;  
7     iface->bss[i]->drv_priv = hapd->drv_priv;  
8 }  

還好有注釋,就是確保每個BSS 都使用和物理網卡(我喜歡稱呼BSS 為虛擬網卡)同一套驅動程序接口。然后直接看return 吧,哎?怎么又有個setup_interface2?好吧,去看看setup_interface2 是怎么回事……找到大概第1113 行,就是它的定義了。這里面主要是設置網卡的硬件模式( a,g,n 等等), 再看return , 我去, 咋還有個hostapd_setup_interface_complete 呢?( 程序作者真磨嘰) 好吧,既然說了complete,那應該就是最后一步了吧?那我就硬着頭皮繼續看看——跳到大概1162 行,就找到了它的定義。這個過程里面主要是設置網卡的信道,速率(根據硬件模式),RTS 參數等等。最后通過hostapd_setup_bss 函數配置每個BSS 。那我們就再看看hostapd_setup_bss 是怎么個回事吧( 無語) — — 再跳到大概687 行, 就找到了hostapd_setup_bss 的定義。這個函數需要兩個參數,第一個是hostapd_data 結構體,描述一個BSS 的配置信息,第二個參數first 則用來表示這個BSS 是否為第一個BSS(通常,第一個BSS 就是wlan0)。先看第一部分代碼:

 1 if (!first || first == -1) { //此BSS 不是第一個BSS 的情況  
 2     if (hostapd_mac_comp_empty(conf->bssid) == 0) { //配置文件沒有為此BSS 指定BSSID  
 3         /* Allocate the next available BSSID. */  
 4         do {  
 5             //將上一個BSS 的BSSID 增加1 做為這個BSS 的BSSID,並且反復這一步驟直到不與其他BSSID 重復為止  
 6             inc_byte_array(hapd->own_addr, ETH_ALEN);  
 7         } while (mac_in_conf(hapd->iconf, hapd->own_addr));  
 8     } else { //配置文件已經為此BSS 指定BSSID 的情況  
 9         /* Allocate the configured BSSID. */  
10         os_memcpy(hapd->own_addr, conf->bssid, ETH_ALEN);  
11         if (hostapd_mac_comp(hapd->own_addr, hapd->iface->bss[0]->own_addr) ==0) {  
12             wpa_printf(MSG_ERROR, "BSS '%s' may not have "  
13                 "BSSID set to the MAC address of "  
14                 "the radio", conf->iface);  
15             return -1;  
16         }  
17     }   
18     hapd->interface_added = 1; //不知道干嘛的  
19     //在內核中為此BSS 創建一個interface(比如wlan0_0)  
20     if (hostapd_if_add(hapd->iface->bss[0], WPA_IF_AP_BSS,  
21             conf->iface, hapd->own_addr, hapd, &hapd->drv_priv, force_ifname, if_addr,  
22             conf->bridge[0] ? conf->bridge : NULL, first == -1)) {  
23         wpa_printf(MSG_ERROR, "Failed to add BSS (BSSID="  
24             MACSTR ")", MAC2STR(hapd->own_addr));  
25         hapd->interface_added = 0;  
26         return -1;  
27     }  
28 }  

再看第二部分:

1 …… //此部分是對這個BSS 的加密方式,SSID 等參數的設置  
2 //將這個BSS 的interface 激活。(假設這個BSS 的interface 為wlan0_0 的話,那么這句話的意思就相當於在終端下執行“ifconfig wlan0_0 up”命令)  
3 if (hapd->driver && hapd->driver->set_operstate)  
4     hapd->driver->set_operstate(hapd->drv_priv, 1);  
5 return 0;  

啊,終於是return 0 了。好了,重新回到main。至此,網絡接口和每個BSS 的初始化工作完成了。

未完待續……下一篇將詳細講解hostapd的工作機制。

 

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM