用Raspberry Pi學Embedded Linux (4) — 利用C語言設定Wi-Fi

sepfy
7 min readFeb 14, 2021

--

目前Wi-Fi已是嵌入式設備常見的連網界面,不管是網通設備、消費性電子或者工控設備都有可能擁有Wi-Fi連網的功能,在打造嵌入式產品時勢必要能控制與設定Wi-Fi,而最有名Open source當然就是wpa-supplicant了,這是一個能幫助我們讓Linux系統連上Wi-Fi的工具,就連Android的wireless也是靠它來管理的,在樹莓派上使用它的教學應該已經有很豐富的資源了,透過修改wpa_supplicant.conf設定檔就可以連上我們指定的熱點(當然最簡便的方式是透過rasp-config來設定,不過背後的作法是相同的),但如果今天我們是開發一個完整的嵌入式產品,應該不太可能讓使用者去修改設定檔,我們可能要透過網頁或者GUI來設定,這時候就要更靈活的去控制與修改,所以這篇我們就使用C語言透過wpa-supplicant提供的客戶端函式庫來設定Wi-Fi

wpa_cli指令熱身

如果在網路上搜尋wpa-supplicant相關的設定指令,會找到一個wpa_cli的工具(其實我們就是要來自製一個簡易的wpa_cli),它可以用來設定連線或者掃描附近的熱點,可以在樹莓派Official OS image中測試它,以下指令可以掃描附近的熱點資訊,包含SSID與信號強度等等

$ wpa_cli -iwlan0 scan_results

也可以登入互動的界面去監控目前Wi-Fi連線的訊息

$ wpa_cli -iwlan0

當然功能不止這些,可以用help來查看完整指令

$ wpa_cli --help

接著我們會用C語言來實現上述的兩個功能

準備wpa-supplicant函式庫

因為我們需要wpa client端的函式庫, 在樹莓派官方的OS image中找不到這個函式庫, 所以我們需要自行編譯wpa client端函式庫(libwpa_client.so)

$ sudo apt-get update
$ sudo apt-get install libdbus-1-dev libssl-dev libnl-genl-3-dev
$ wget https://w1.fi/releases/wpa_supplicant-2.9.tar.gz
$ tar zxvf wpa_supplicant-2.9.tar.gz
$ cd wpa_supplicant-2.9/wpa_supplicant
$ cp defconfig .config

修改.config,加入CONFIG_BUILD_WPA_CLIENT_SO=y 後編譯

$ make -j4

編譯完成後,可以在該目錄下找到libwpa_client.so,我們把library與header檔都放到系統的目錄下就可以來開發囉

$ sudo cp wpa_supplicant-2.9/wpa_supplicant/libwpa_client.so /usr/lib/
$ sudo cp wpa_supplicant-2.9/src/common/wpa_ctrl.h /usr/include/

發送wpa-supplicant命令

這個範例將SCAN_RESULTS的指令發送給wpa-supplicant來獲取附近熱點的訊息,首先我們調用wpa_ctrl_open來連接wpa-supplicant service,參數為interface的unix socket界面,可以在wpa_supplicant.conf中找到對應的位置

如果沒有的話可以自行加入ctrl_interface並重新啟動wpa-supplicant,接著調用wpa_ctrl_request來發送命令,相關的參數可以參考官方的文件,基本上就是命令與回覆的內容

可以直接在樹莓派上編譯這個範例然後執行看看,應該可以成功掃描到附件的熱點資訊

$ gcc control.c -lwpa_client -o control
$ ./control

監控wpa-supplicant事件

有時候我們需要監控Wi-Fi的狀態,例如當斷線時我們要顯示一個警告等等,所以監控wpa-supplicant事件也是常常使用到的,與發送指令一樣,一開始呼叫wpa_ctrl_open來建立連接,接著調用wpa_ctrl_attach來監控這個interface,如果翻閱官方文件的話,再調用wpa_ctrl_recv來獲取事件內容以前必須先呼叫wpa_ctrl_attach才行,因為是監控事件,所以我們是透過一個while迴圈去polling事件消息,為了讓程式更有效率,範例使用了select來確認file descriptor是否有新的消息(timeout的時間為5秒),file descriptor與select等等的使用算是Linux程式開發上常使用的API,有興趣的話可以研究一下,不過這邊主要還是介紹如何做wpa client端的程式開發,wpa_ctrl_recv會將新的事件內容放到buf的陣列當中,接著我們就可以判斷buf裡的訊息來執行我們要的功能,編譯並執行範例程式,可以看到wpa-supplicant掃描的相關訊息

$ gcc monitor.c -lwpa_client -o monitor
$ ./monitor

更多的指令可以參考wpa-supplicant的開發文件

https://w1.fi/wpa_supplicant/devel/ctrl_iface_page.html

這樣我們就可以客製一個wpa_cli的程式來符合自己的產品應用,除了wpa_supplicant,另外一個Wi-Fi常用的Softap工具hostapd也是使用相同的架構,對應的客戶端程式為hostapd_cli,有興趣的話也可以透過ctrl interface來操作哦

參考資料

[1] https://w1.fi/wpa_supplicant/devel/index.html

[2] https://www.kancloud.cn/alex_wsc/android-wifi-nfc-gps/414067

[3] https://blog.csdn.net/sinat_20059415/article/details/82050586

[4] http://lishiwen4.github.io/wifi/WPAS-connect-with-client

--

--