Wi-Fi на BCM 4312/4313 в Mint/Ubuntu

Написано 5 Февраль, 2013 в категории Linux,Ubuntu/Debian/Mint

Всем счастливым обладателям карточек Broadcom посвящается.
Есть у меня 2 ноута и заставила меня жизнь настроить на них wifi соединение. На первом ноуте стоял Mint на втором Ubuntu. К слову сказать это не первая моя попытка настроить беспроводное соединение под Ubuntu.

Итак по шагам:
1. Идем на сайт компании Broadcom и качаем ихние дровишки себе. Дровишки естественно написаны на языке С и естественно требуют сборки. Скачать дровишки можно тут: http://www.broadcom.com/support/802.11.

2. Все делаем под рутом. Пытаемся собрать дрова и получаем ошибку в каком-то там сишном файле. Это лечится, таблетка тут http://www.mindwerks.net/2011/11/wireless-bcm4312-3-2-kernel/ Т.е. скачанные исходники драйвера от Broadcom перед использование придется пропатчить.

3. В Ридми предлагается выбор - для какого Wireless API собирать драйвер, итого:
make - предоставляем mak'у выбрать самому
make API=WEXT - поддержка старого WEXT модуля
make API=CFG80211 - поддержка нового Wireless API (его то я и выбрал)
драйвер собран, идем дальше.

4. Тут дорожки Mint и Ubuntu у меня разошлись. На этом этапе необходимо загрузить собранный драйвер в ядро.
Для Mint:
копируем собранный драйвер wl.ko например в /lib/modules/`uname -r`/kernel/lib/
для загрузки драйвера при старте системы в /etc/rc.local дописываем перед строкой exit 0

modprobe -r bcma
modprobe -r b43
modprobe -r ssb
modprobe wl

Для Ubuntu:
для загрузки драйвера при старте системы в /etc/rc.local дописываем перед строкой exit 0

modprobe -r bcma
modprobe -r b43
modprobe -r ssb
modprobe -r wl
modprobe lib80211
modprobe cfg80211
insmod /home/user/hybrid_wl/wl.ko

Система управления модулями ядра в Линухе довольно мутная. В Mint мне не удалось отключить ssb через blacklist.conf поэтому в Ubuntu я решил отключать их принудительно. Единственный минус такой конфигурации - можно случайно удалить wl.ko
После перезагрузки драйвер будет загружен.

5. В Ubuntu мне пришлось поставить wicd для настройки соединения (essid, key), но можно настроить и в ручную как написано тут: настройка wifi вручную
В Mint я настроил соединение в симпатичном Network менеджере, т.е. ручная настройка не понадобилась.

6. Это дополнение написано ровно через месяц после успешной настройки wi-fi на Убунте. Так сложилось, что за месяц я так и не пересел на Mint и честно говоря с момента настройки wi-fi её и не включал. А вот убунтой я пользуюсь ежедневно и одним прекрасным утром Убунта загрузилась, а wi-fi нет...

Худшие опасения, что карточка Broadcom накрылась медным тазом - не оправдались. Под windows на той же машине она прекрасно работала.
Симптомы:
ifconfig - сетевой беспроводной интерфейс отсутствует.
lsmod | grep wl - выдает пустой результат, т.е. модуль с драйвером не запущен.
Ну что ж попробуем запустить драйвер вручную:

sudo insmod <путь к модулю>/wl.ko

выдает загадочную ошибку: "insmod: error inserting '<путь к модулю>/wl.ko': -1 Invalid parameters"

Т.к. в настройках я ничего не менял и обновлений не устанавливал, то появилось предположение об автоматическом обновлении и опыт подсказывал что обновилось скорее всего ядро. И новое ядро не хочет работать со старым драйвером.

Проблема была решена повторной компиляцией модуля wl.ko под новой ядро. После компиляции модуль успешно подключился к новому ядру. А вот автоматические обновления были отключены...

7. Как обычно бывает в таких случаях, happy end оказался временным. Полгода я выборочно ставил обновления, но ядро не обновлял. Честно говоря не было идей как это сделать (ну что поделать никогда не сталкивался с этим вопросом), да и времени тоже. Однако, я все таки нашел время для этого вопроса, т.к. очень хотелось обновиться, а перекомпилировать драйвер совсем не хотелось.
Все что будет написано ниже проверялось под Ubuntu 12.04.2 LTS, думаю на Mint все делается аналогично.

Итак, я обнаружил DKMS (Dynamic Kernel Module Support). Суть этой системы: при загрузке ubuntu c новым ядром, все сконфигурированные в этой системе драйвера автоматически перекомпилируются и устанавливаются в новое ядро. В общем, то что нужно.
Как обычно с наскока сделать не получилось - пришлось читать man и усиленно думать тыквой.

Как сделать сборку и установить драйвер из исходников в автоматическом режиме (при загрузке нового ядра):
0). Возможно dkms не установлен. Если так, то делаем:

sudo apt-get install dkms

1). Качаем драйвер (исходники). Что откуда взять я писал в самом начале статьи.

2). Помещаем папку с исходниками в /usr/src/

3). man dkms подсказывает, что имя папки с драйвером должно иметь формат <name>-<version>. Я свой драйвер назвал hybrid_wl-1.0 (произвольное имя и версия от балды). Т.о. у меня исходники драйвера теперь лежат в /usr/src/hybrid_wl-1.0.

4). Теперь необходимо подсказать системе как собрать исходники и куда положить собранный бинарник.
Для этого создаем файл /usr/src/hybrid_wl-1.0/dkms.conf с таким текстом:

MAKE[0]="make"
BUILT_MODULE_NAME[0]=wl
DEST_MODULE_LOCATION[0]="/kernel/lib/"
PACKAGE_NAME="hybrid_wl"
PACKAGE_VERSION="1.0"
CLEAN="make clean"
AUTOINSTALL="yes"

Индекс позволяет одновременно собрать несколько драйверов из одной папки. Начинается индекс с нуля.
MAKE - команда сборки проекта. Пробовал "make API='CFG80211'" - dkms отказался собирать драйвер, уже было расстроился, но узнал что и без параметра API все собирается правильно и решил не заморачиваться с исправлением ошибки.
BUILT_MODULE_NAME - имя вашего бинарника после сборки. К слову сказать сборка проводится не в /usr/src/hybrid_wl-1.0/. dkms делает линк на исходники в своей папке и сборку проводит там: /var/lib/dkms/<module>/<module-version>/build/ , т.е. в моем случае это было /var/lib/dkms/hybrid_wl/1.0/build/
DEST_MODULE_LOCATION - куда положим собранный бинарник драйвера.
PACKAGE_NAME и PACKAGE_VERSION - название и версия драйвера, используется для формирования пути в /var/lib/dkms/<module>/<module-version>/
CLEAN - очистка сборки, выполняется перед каждой сборкой драйвера
AUTOINSTALL - может принимать 2 значения "yes" и "no". Указывает должен ли собираться драйвер при установке ядра.

5). Сборка и установка драйвера :
Добавляем драйвер в dkms

sudo dkms add hybrid_wl/1.0

Собираем драйвер

sudo dkms build hybrid_wl/1.0

Устанавливаем драйвер в текущее ядро:

sudo dkms install hybrid_wl/1.0

При загрузке нового ядра, dkms попробует собрать и установить в него драйвер
Очень много полезной информации выдает man dkms, в том числе по формату и параметрам dkms.conf
Вот несколько полезных ссылок:
http://www.opennet.ru/tips/info/1826.shtml
http://deepwalker.blogspot.ru/2008/11/810-dkms-nvidia-btrfs.html

Теперь я могу снова включить автоматическое обновление ядра!

8. А история все не кончается и не кончается. Однажды после обновления ядра я забыл вставить в ноутбук сетевой адаптер - батарея разрядилась и ноут отключился. Отключился без нормального завершения работы Ubuntu (хотя dkms успел пересобрать драйвер).
И вот тут начинается нечто непонятное. После включения машины, вайфай не поднялся, т.к. оказалось что dkms собрал драйвер для нового ядра, но при сборке использовал старое. В результате драйвер не мог загрузиться. Как обычно помогла перекомпиляция и замена драйвера в новом ядре.

9. Прошло практически 15 месяцев, я по-прежнему на Ubuntu 12.04 LTS. Все это время в целом без проблем обновлялись ядра серии 3.2.x Пока в один прекрасный день мне не пришла идея попробовать docker :) Как говорится, сказано сделано, но docker для своей работы требует ядро linux 3.8 т.к. именно в нем была добавлена поддержка технологии lxc. И вот легким движением руки я обновил ядро до 3.8 и... интернет погас, вернее перестал работать wifi. Симптомы все теже
ifconfig - сетевой беспроводной интерфейс отсутствует.
lsmod | grep wl - выдает пустой результат, т.е. модуль с драйвером не запущен.
Однако на этот раз, пересборка драйвера не помогла, поэтому был скачана новая версия драйвера, установлена аналогично старому. А в dkms.conf старого драйвера был изменен один параметр

AUTOINSTALL="no"

По идее это не даст старому драйверу мешать работе нового драйвера.
Перезагружаем ноутбук и вуаля, интернет появился!
10. Пришли длинные новогодние праздники 2015 года. И я решил рискнуть и обновиться до последней LTS версии ubuntu 14.04.1 И угадайте что!?!? Правильно, wifi не поднялся... Кажется что у этой истории не будет конца... :) При этом симптомы несколько иные, команда

lsmod | grep wl

показала, что модуль драйвера загружен. А значит проблема на этот раз не в драйвере. Скорее всего при upgrad'e что-то сломалось в настройках соединения.
Смотрим какие интерфейсы нам выдает

[moon:~] % sudo iwconfig
eth0      no wireless extensions.
 
lo        no wireless extensions.
 
wlan0     IEEE 802.11abg  ESSID:off/any  
          Mode:Managed  Access Point: Not-Associated   Tx-Power=200 dBm   
          Retry  long limit:7   RTS thr:off   Fragment thr:off
          Encryption key:off
          Power Management:off

Т.е. у нас присутствует беспроводной сетевой интерфейс с именем wlan0. Смотрим настроен ли он в /etc/network/interfaces :

[moon:~] % sudo cat /etc/network/interfaces
...
iface eth1 inet dhcp
...
auto eth1

Т.е. мы видим что почему-то сменилось имя беспроводного интерфейса на wlan0, а в настройках по-прежнему указан eth1. Меняем eth1 на wlan0 в /etc/network/interfaces

[moon:~] % sudo cat /etc/network/interfaces
...
iface wlan0 inet dhcp
...
auto wlan0

и пробуем поискать доступные wifi сети:

[moon:~] % sudo iwlist wlan0 scan

Появился список доступных для подключения сетей! WiFi под Ubuntu в очередной раз побежден! Ура, товарищи!

11. Несмотря на то, что я в прошлый раз справился с wifi, осталась одна проблемка. Каждый раз, после установки нового ядра, не собирался драйвер wifi, и приходилось это делать вручную.
Начал разбираться по принципу - чиним все что некорректно работает.
Обнаружилось что sudo dkms status выдает вместо списка установленных модулей строку: "Error! Could not locate dkms.conf file."
Как я устранял эту проблему? Нашел все dkms.conf Некоторые оказались "невалидными" символическими ссылками - удалил такие ссылки. Все заработало.
После очередного обновления ядра - модули успешно скомпилировались! Ура! Ура!