我新裝的centos7主機無法使用裡面自帶的網卡,查詢後發現網卡型號為BCM4312。我在看資料安裝的過程中遇到了些問題,糾結了好久,現在分享下要註意的點,為後來的遇到同樣問題的人提供點幫助。現在開始說正事: 若要安裝以 Broadcom BCM4311、BCM4312、BCM4313、BCM432 ...
我新裝的centos7主機無法使用裡面自帶的網卡,查詢後發現網卡型號為BCM4312。我在看資料安裝的過程中遇到了些問題,糾結了好久,現在分享下要註意的點,為後來的遇到同樣問題的人提供點幫助。現在開始說正事:
若要安裝以 Broadcom BCM4311、BCM4312、BCM4313、BCM4321、BCM4322、BCM43224、BCM43225、BCM43227 或 BCM43228 為基礎的無線網路卡,請遵照以下的步驟:
第 1 步:辨認無線網路晶元及安裝時依賴的組件
首先,請確定你是位「擁有 Broadcom BCM43xx 無線網路卡的幸運兒」:
[user@host ~]$ /sbin/lspci | grep Broadcom 0b:00.0 Network controller: Broadcom Corporation BCM4312 802.11a/b/g (rev 01)
辨認完無線網路晶元型號之後,請確定你不會欠缺編譯及安裝時所需的組件:
[root@host]# yum install kernel-headers kernel-devel gcc
當然,假若你要為 Xen 內核(kernel-xen)編譯驅動程式,你必須安裝 kernel-xen-devel 而不是 kernel-devel。需不需安裝,推薦看下:http://blog.sina.com.cn/s/blog_946b3ae20100yxdm.html
第 2 步:下載並解壓 Broadcom 驅動程式的壓縮檔
請從Broadcom的官方網站(https://www.broadcom.com/)下載 Broadcom BCM43xx 的 linux 驅動程式壓縮檔到你的機器並將它解壓到 /usr/local/src/hybrid-wl,請隨你所需將這個目錄的擁有者改為無特權的用戶:(我下載的是hybrid-v35_64-nodebug-pcoem-6_30_223_271.tar.gz,把這個包放/usr/local/src/hybrid-wl這個目錄下,我以這個包寫的例子,你根據自己下的包來改動下麵的語句。我選的無特權用戶為nobody。)
[root@host ~]# mkdir -p /usr/local/src/hybrid-wl [root@host hybrid-wl]# cd /usr/local/src/hybrid-wl [root@host hybrid-wl]# tar xvfz /usr/local/src/hybrid-wl/hybrid-v35_64-nodebug-pcoem-6_30_223_271.tar.gz [root@host hybrid-wl]# chown -R nobody.nobody /usr/local/src/hybrid-wl
註:為什麼不隨便將它解壓到一個位置並保留預設的擁有者?
原因是上面的做法會把驅動模塊的源代碼保留在系統上 —— 在你放置它們的位置 —— 好讓你可以隨時按需要創建驅動程式(譬如:你將內核升了級 —— 因為驅動模塊永遠根據某個內核來編譯),還有,就是你可以用無特權的用戶來編譯!
第 3 步上:編譯 Broadcom 驅動模塊 (在 EL6 和 EL7 上)
驅動模塊可以這樣編譯:
[user@host hybrid-wl]$ make -C /lib/modules/`uname -r`/build M=`pwd`
請留意引號(即反引號),centos官方的文檔寫的是[user@host hybrid-wl]$ make -C /lib/modules/`uname -r`/build/ M=`pwd`,我照做了,就是通不過,後來發現M前面的/是不需要的,加個空格就行。
編譯現有的驅動程式(6.30.223.271 版)時,你差不多肯定會獲得一個錯誤信息,而不是一個編譯好的驅動模塊
make: Entering directory `/usr/src/kernels/2.6.32-573.7.1.el6.x86_64'
CFG80211 API is prefered for this kernel version
Using CFG80211 API
LD /usr/local/src/hybrid-wl/built-in.o
CC [M] /usr/local/src/hybrid-wl/src/shared/linux_osl.o
CC [M] /usr/local/src/hybrid-wl/src/wl/sys/wl_linux.o
CC [M] /usr/local/src/hybrid-wl/src/wl/sys/wl_iw.o
CC [M] /usr/local/src/hybrid-wl/src/wl/sys/wl_cfg80211_hybrid.o
/usr/local/src/hybrid-wl/src/wl/sys/wl_cfg80211_hybrid.c:83: warning: ‘enum tx_power_setting’ declared inside parameter list
/usr/local/src/hybrid-wl/src/wl/sys/wl_cfg80211_hybrid.c:83: warning: its scope is only this definition or declaration, <snip>
/usr/local/src/hybrid-wl/src/wl/sys/wl_cfg80211_hybrid.c: In function ‘wl_cfg80211_join_ibss’:
/usr/local/src/hybrid-wl/src/wl/sys/wl_cfg80211_hybrid.c:730: error: ‘struct cfg80211_ibss_params’ has no member named ‘channel’
/usr/local/src/hybrid-wl/src/wl/sys/wl_cfg80211_hybrid.c: At top level:
/usr/local/src/hybrid-wl/src/wl/sys/wl_cfg80211_hybrid.c:1096: warning: ‘enum tx_power_setting’ declared inside parameter list
/usr/local/src/hybrid-wl/src/wl/sys/wl_cfg80211_hybrid.c:1096: error: parameter 2 (‘type’) has incomplete type
/usr/local/src/hybrid-wl/src/wl/sys/wl_cfg80211_hybrid.c: In function ‘wl_cfg80211_set_tx_power’:
/usr/local/src/hybrid-wl/src/wl/sys/wl_cfg80211_hybrid.c:1107: error: ‘TX_POWER_AUTOMATIC’ undeclared (first use in this <snip>
/usr/local/src/hybrid-wl/src/wl/sys/wl_cfg80211_hybrid.c:1107: error: (Each undeclared identifier is reported only once
/usr/local/src/hybrid-wl/src/wl/sys/wl_cfg80211_hybrid.c:1107: error: for each function it appears in.)
/usr/local/src/hybrid-wl/src/wl/sys/wl_cfg80211_hybrid.c:1109: error: ‘TX_POWER_LIMITED’ undeclared (first use in this function)
/usr/local/src/hybrid-wl/src/wl/sys/wl_cfg80211_hybrid.c:1115: error: ‘TX_POWER_FIXED’ undeclared (first use in this function)
/usr/local/src/hybrid-wl/src/wl/sys/wl_cfg80211_hybrid.c: At top level:
/usr/local/src/hybrid-wl/src/wl/sys/wl_cfg80211_hybrid.c:1774: warning: initialization from incompatible pointer type
/usr/local/src/hybrid-wl/src/wl/sys/wl_cfg80211_hybrid.c:1779: warning: initialization from incompatible pointer type
/usr/local/src/hybrid-wl/src/wl/sys/wl_cfg80211_hybrid.c:1780: warning: initialization from incompatible pointer type
/usr/local/src/hybrid-wl/src/wl/sys/wl_cfg80211_hybrid.c:1781: warning: initialization from incompatible pointer type
/usr/local/src/hybrid-wl/src/wl/sys/wl_cfg80211_hybrid.c:1782: warning: initialization from incompatible pointer type
/usr/local/src/hybrid-wl/src/wl/sys/wl_cfg80211_hybrid.c:1783: warning: initialization from incompatible pointer type
/usr/local/src/hybrid-wl/src/wl/sys/wl_cfg80211_hybrid.c:1784: warning: initialization from incompatible pointer type
/usr/local/src/hybrid-wl/src/wl/sys/wl_cfg80211_hybrid.c:1789: warning: initialization from incompatible pointer type
/usr/local/src/hybrid-wl/src/wl/sys/wl_cfg80211_hybrid.c: In function ‘wl_inform_single_bss’:
/usr/local/src/hybrid-wl/src/wl/sys/wl_cfg80211_hybrid.c:1984: error: too few arguments to function <snip>
/usr/local/src/hybrid-wl/src/wl/sys/wl_cfg80211_hybrid.c:2023: warning: passing argument 1 of ‘cfg80211_put_bss’ from <snip>
include/net/cfg80211.h:3380: note: expected ‘struct wiphy *’ but argument is of type ‘struct cfg80211_bss *’
/usr/local/src/hybrid-wl/src/wl/sys/wl_cfg80211_hybrid.c:2023: error: too few arguments to function ‘cfg80211_put_bss’
/usr/local/src/hybrid-wl/src/wl/sys/wl_cfg80211_hybrid.c: In function ‘wl_update_bss_info’:
/usr/local/src/hybrid-wl/src/wl/sys/wl_cfg80211_hybrid.c:2276: error: ‘struct cfg80211_bss’ has no member named <snip>
/usr/local/src/hybrid-wl/src/wl/sys/wl_cfg80211_hybrid.c:2277: error: ‘struct cfg80211_bss’ has no member named <snip>
/usr/local/src/hybrid-wl/src/wl/sys/wl_cfg80211_hybrid.c:2283: warning: passing argument 1 of ‘cfg80211_put_bss’ from <snip>
include/net/cfg80211.h:3380: note: expected ‘struct wiphy *’ but argument is of type ‘struct cfg80211_bss *’
/usr/local/src/hybrid-wl/src/wl/sys/wl_cfg80211_hybrid.c:2283: error: too few arguments to function ‘cfg80211_put_bss’
/usr/local/src/hybrid-wl/src/wl/sys/wl_cfg80211_hybrid.c: In function ‘wl_bss_roaming_done’:
/usr/local/src/hybrid-wl/src/wl/sys/wl_cfg80211_hybrid.c:2322: warning: passing argument 2 of ‘cfg80211_roamed’ from <snip>
include/net/cfg80211.h:3726: note: expected ‘struct ieee80211_channel *’ but argument is of type ‘u8 *’
/usr/local/src/hybrid-wl/src/wl/sys/wl_cfg80211_hybrid.c:2322: warning: passing argument 4 of ‘cfg80211_roamed’ makes <snip>
include/net/cfg80211.h:3726: note: expected ‘const u8 *’ but argument is of type ‘s32’
/usr/local/src/hybrid-wl/src/wl/sys/wl_cfg80211_hybrid.c:2322: warning: passing argument 5 of ‘cfg80211_roamed’ makes <snip>
include/net/cfg80211.h:3726: note: expected ‘size_t’ but argument is of type ‘u8 *’
/usr/local/src/hybrid-wl/src/wl/sys/wl_cfg80211_hybrid.c:2322: warning: passing argument 6 of ‘cfg80211_roamed’ makes <snip>
include/net/cfg80211.h:3726: note: expected ‘const u8 *’ but argument is of type ‘s32’
/usr/local/src/hybrid-wl/src/wl/sys/wl_cfg80211_hybrid.c:2322: error: too few arguments to function ‘cfg80211_roamed’
/usr/local/src/hybrid-wl/src/wl/sys/wl_cfg80211_hybrid.c: In function ‘wl_update_wowl’:
/usr/local/src/hybrid-wl/src/wl/sys/wl_cfg80211_hybrid.c:2791: warning: unused variable ‘wdev’
make[1]: *** [/usr/local/src/hybrid-wl/src/wl/sys/wl_cfg80211_hybrid.o] Error 1
make: *** [_module_/usr/local/src/hybrid-wl] Error 2
make: Leaving directory `/usr/src/kernels/2.6.32-573.7.1.el6.x86_64'
註意: 在 EL6 和 EL7 的步驟由此起有分別。如果是 EL6,你應該遵從第 3 步上;而 EL7 只須應用第 3 步上的修正及第 3 步下的 sed 指命,並按照此步驟(3 上)內的指示編譯它。即是說, EL7 要略過第3步上的 sed 指令。
在 EL6 上,驅動程式由於 wl_cfg80211_hybrid.c 檔內檢查內核版本的 if-then-else 句式而不能編譯。我們須要執行下列的 sed 替換指令來進行修正:
。這則信息的內容隨著內核和操作系統版本而變化,但是在 CentOS 6 上它大致上是:
[user@host hybrid-wl]$ sed -i 's/[ >][>=] KERNEL_VERSION(2, 6, 3.)/>= KERNEL_VERSION(2, 6, 32)/' src/wl/sys/wl_cfg80211_hybrid.c [user@host hybrid-wl]$ sed -i 's/[ >][>=] KERNEL_VERSION(3, ., .)/>= KERNEL_VERSION(2, 6, 32)/' src/wl/sys/wl_cfg80211_hybrid.c [user@host hybrid-wl]$ sed -i 's/[ >][>=] KERNEL_VERSION(3, 11, .)/>= KERNEL_VERSION(2, 6, 32)/' src/wl/sys/wl_cfg80211_hybrid.c [user@host hybrid-wl]$ sed -i 's/< KERNEL_VERSION(3, 18, .)/< KERNEL_VERSION(2, 6, 30)/' src/wl/sys/wl_cfg80211_hybrid.c [user@host hybrid-wl]$ sed -i 's/[ >][>=] KERNEL_VERSION(3, 15, .)/>= KERNEL_VERSION(2, 6, 32)/' src/wl/sys/wl_cfg80211_hybrid.c [user@host hybrid-wl]$ sed -i 's/[ >][>=] KERNEL_VERSION(4, 0, 0)/>= KERNEL_VERSION(2, 6, 32)/' src/wl/sys/wl_cfg80211_hybrid.c [user@host hybrid-wl]$ sed -i 's/< KERNEL_VERSION(4,2,0)/< KERNEL_VERSION(2, 6, 30)/' src/wl/sys/wl_cfg80211_hybrid.c
不過,這些 'sed' 替換命令仍未能確保驅動程式可以正常編譯。我們還須要在編譯驅動程式前應用 wl-kmod-fix-ioctl-handling.patch 這個修正。請將它下載至 /usr/local/src 然後執行下列指令來修正驅動程式的源代碼:
[user@host hybrid-wl]$ patch -p1 < ../wl-kmod-fix-ioctl-handling.patch patching file src/wl/sys/wl_cfg80211_hybrid.c Hunk #1 succeeded at 1467 (offset 17 lines). patching file src/wl/sys/wl_linux.c Hunk #1 succeeded at 1659 (offset 8 lines).
現在,請嘗試再次編譯驅動模塊:
[user@host hybrid-wl]$ make -C /lib/modules/`uname -r`/build M=`pwd`
編譯器的輸出大致上是這樣:
make: Entering directory `/usr/src/kernels/2.6.32-573.7.1.el6.x86_64' CFG80211 API is prefered for this kernel version Using CFG80211 API LD /usr/local/src/hybrid-wl/built-in.o CC [M] /usr/local/src/hybrid-wl/src/shared/linux_osl.o CC [M] /usr/local/src/hybrid-wl/src/wl/sys/wl_linux.o CC [M] /usr/local/src/hybrid-wl/src/wl/sys/wl_iw.o CC [M] /usr/local/src/hybrid-wl/src/wl/sys/wl_cfg80211_hybrid.o /usr/local/src/hybrid-wl/src/wl/sys/wl_cfg80211_hybrid.c:1802: warning: initialization from incompatible pointer type LD [M] /usr/local/src/hybrid-wl/wl.o Building modules, stage 2. CFG80211 API is prefered for this kernel version Using CFG80211 API MODPOST 1 modules CC /usr/local/src/hybrid-wl/wl.mod.o LD [M] /usr/local/src/hybrid-wl/wl.ko.unsigned NO SIGN [M] /usr/local/src/hybrid-wl/wl.ko make: Leaving directory `/usr/src/kernels/2.6.32-573.7.1.el6.x86_64'
一旦這個模塊被建成,你便可以刪除不必要的符號:
[user@host hybrid-wl]$ strip --strip-debug wl.ko
你會發現驅動模塊的文件尺寸會縮小(由 8.2MB 降至 7.2MB)。而且,你的驅動模塊仍能正常運作。
第 3 步下:編譯 Broadcom 驅動模塊 (EL7需要的部分細節,也是我要重點說的部分)
許多中文資料都是這麼說的:
寫完這上面4個sed,再make,
[user@host hybrid-wl]$ make -C /lib/modules/`uname -r`/build M=`pwd`
就是通不過,後來找到centos WIKI 的英文原版資料才發現,中文翻譯的資料落後了,沒有及時跟新,中文資料只說到EL7.2的事,那EL7.3 即 kernel-3.10.0-514.X該怎麼寫呢?看英文怎麼說吧:
EL7.3 即 kernel-3.10.0-514.X 需要6個sed:
[user@host hybrid-wl]$ sed -i 's/ >= KERNEL_VERSION(3, 11, 0)/ >= KERNEL_VERSION(3, 10, 0)/' src/wl/sys/wl_cfg80211_hybrid.c [user@host hybrid-wl]$ sed -i 's/ >= KERNEL_VERSION(3, 15, 0)/ >= KERNEL_VERSION(3, 10, 0)/' src/wl/sys/wl_cfg80211_hybrid.c [user@host hybrid-wl]$ sed -i 's/ < KERNEL_VERSION(3, 18, 0)/ < KERNEL_VERSION(3, 9, 0)/' src/wl/sys/wl_cfg80211_hybrid.c [user@host hybrid-wl]$ sed -i 's/ >= KERNEL_VERSION(4, 0, 0)/ >= KERNEL_VERSION(3, 10, 0)/' src/wl/sys/wl_cfg80211_hybrid.c [user@host hybrid-wl]$ sed -i 's/ < KERNEL_VERSION(4,2,0)/ < KERNEL_VERSION(3, 9, 0)/' src/wl/sys/wl_cfg80211_hybrid.c [user@host hybrid-wl]$ sed -i 's/ >= KERNEL_VERSION(4, 7, 0)/ >= KERNEL_VERSION(3, 10, 0)/' src/wl/sys/wl_cfg80211_hybrid.c
別急,EL7.3先得裝個補丁,再跑上面的6個sed,補丁 wl-kmod-kernel_4.7_IEEE80211_BAND_to_NL80211_BAND.patch ,把它下好放到/usr/local/src 目錄下,運行補丁:
[user@host hybrid-wl]$ patch -p1 < /usr/local/src/wl-kmod-kernel_4.7_IEEE80211_BAND_to_NL80211_BAND.patch patching file src/wl/sys/wl_cfg80211_hybrid.c Hunk #6 succeeded at 1911 (offset 3 lines). Hunk #7 succeeded at 2040 (offset 3 lines). Hunk #8 succeeded at 2160 (offset 3 lines). Hunk #9 succeeded at 2298 (offset 3 lines). Hunk #10 succeeded at 2941 (offset 3 lines).
註意-p1中是數字1。打完了補丁,再輸6個sed,然後再make,
[user@host hybrid-wl]$ make -C /lib/modules/`uname -r`/build M=`pwd`
以為就這樣成功了,並沒有,看:
找了半天,終於發現上圖小紅框中與centos wiki的教程不同,就多了兩個空格,仔細看,小紅框上面和下麵的括弧裡面都有空格,唯獨這個括弧裡面就沒有空格,找到問題了,我再試試,終於跑通了。如下圖:
同時特別註意第3個和第5個sed中沒有等號,而且箭頭指向與其他sed也不同。
第 4 步上:將驅動模塊裝入內核中
當你成功地編譯了驅動模塊後,你便可以將它裝入內核中,並最終設置開機時自動裝入此驅動程式(要這樣做,你必須利用 root 的許可權)。當然,做這一切之先,你必須從內核刪除現在的無線驅動模塊(假如有的話):
[root@host ~]# modprobe -r bcm43xx [root@host ~]# modprobe -r b43 [root@host ~]# modprobe -r b43legacy [root@host ~]# modprobe -r ssb [root@host ~]# modprobe -r bcma [root@host ~]# modprobe -r brcmsmac [root@host ~]# modprobe -r ndiswrapper
請將驅動模塊的文件複製到一個可以讓內核找到它的地方:
[root@host hybrid-wl]# cp -vi /usr/local/src/hybrid-wl/wl.ko /lib/modules/`uname -r`/extra/
這樣做是為了與其它已經/將會從 kmod 組件安裝的外置模塊(例如:fuse、ntfs-3g、等)保持一貫性。按著,請執行:
[root@host ~]# depmod $(uname -r)
以便能創建一個模塊的互賴性清單。現在我們裝入驅動模塊:
[root@host hybrid-wl]# insmod wl.ko
假如這一步失敗了(有不少這樣的報告,但是作者本身還沒有遇到過這類問題),並伴有如下提示信息:
insmod: error inserting 'wl.ko': -1 Unknown symbol in module
首先嘗試創建模塊依賴:
[root@host ~]# depmod `uname -r`
然後裝入驅動模塊:
[root@host hybrid-wl]# modprobe wl
要是沒有錯誤信息,驅動程式已被裝入及隨時可用。假如你只有無線驅動程式應用 ndiswrapper 內核模塊,你可將它刪除 —— 但這並非必須的。
第 4 步下:在開機時將驅動模塊裝入內核中
你仍須額外數個步驟才能在開機時自動裝入模塊。首先,編輯 /etc/modprobe.d/blacklist.conf 這個文件並加入以下內容:
blacklist bcm43xx blacklist b43 blacklist b43legacy blacklist bcma blacklist brcmsmac blacklist ssb blacklist ndiswrapper
什麼?沒有找到/etc/modprobe.d/blacklist.conf,那我們就自己寫一個(我用gedit寫的)取名叫作blacklist.conf,再放到那個目錄下就行了。
通過這樣做,你可以防止這些模塊在開機時被裝入內核中,與 wl 模塊產生衝突。
另外,若要在開機時裝入 wl 模塊,請創建或者編輯/etc/sysconfig/modules/kmod-wl.modules並把以下內容剪貼到其中:
#!/bin/bash for M in lib80211 cfg80211 wl; do modprobe $M &>/dev/null done
現在你的驅動應該在每次開機時都會被裝入(當然除了在你安裝了新內核之後,到時你必須依照以上步驟將它重新編譯)。
操作完這些,我終於看到我的屏幕上出現了wifi的圖標:
好,那我再連個網試試,非常開心,主機可以使用無線網卡上網了。
最後嘮叨一句,原版英文資料是最靠譜的。
參考資料1:https://wiki.centos.org/HowTos/Laptops/Wireless/Broadcom?action=show