FreeBSD无线网络BCM43602(通过wifibox)

备注

本文实践在 MacBook Pro 15" Late 2013 进行,最初该笔记本原装无线网卡芯片是 Broadcom BCM4360 。这个无线芯片可以在Linux上工作(其实也很难支持),但是FreeBSD目前无法支持。

我在最近一次部署 Gentoo Linux在MacBook Pro配置WifiMacBook Pro 15" Late 2013 无线网卡模块换成了 BCM943602CS蓝牙无线模块 来避免折腾NVIDIA私有驱动,所以现在我在 MacBook Pro 15" Late 2013 部署FreeBSD时候,将针对 BCM943602CS蓝牙无线模块 配置无线网络。理论上 BCM43602 无线模块对开源驱动较为友好,可能可以在FreeBSD中驱动。

检查硬件

  • 执行 pciconf (类似Linux平台的 lspci )命令检查硬件:

pciconf 检查硬件
pciconf -lv

显示:

pciconf 检查硬件显示 BCM43602
none1@pci0:3:0:0:       class=0x028000 rev=0x01 hdr=0x00 vendor=0x14e4 device=0x43ba subvendor=0x106b subdevice=0x0134
    vendor     = 'Broadcom Inc. and subsidiaries'
    device     = 'BCM43602 802.11ac Wireless LAN SoC'
    class      = network

博通(broadcom)网卡驱动

FreeBSD Broadcom Wi-Fi Improvements 提供了Broadcom无线网卡支持列表,但是没有 BCM43602

我在 reddit帖子: Support for BCM4360 (2014 Mac Mini) Trying to move from Linux/windows. 看到有提到虽然FreeBSD列表中没有支持,但是OpenBSD显示支持 BCM43602 但不支持BCM4360。看起来我的 BCM43602 还是有希望的...

FreeBSD Wifibox

非常幸运, Project FreeBSD Wifibox 项目在FreeBSD上通过使用Linux来驱动无线网卡(神奇啊!!!)

备注

FreeBSD不支持 BCM43602 的原因是License和技术原因(这块Broadcom无线网卡需要闭源驱动),所以FreeBSD官方是永远不会支持该网卡的。

Project FreeBSD Wifibox 通过在FreeBSD的 bhyve(BSD hypervisor) 运行 Alpine Linux 虚拟机,将物理主机的无线网卡从FreeBSD主机中直接透传给guest虚拟机,来实现在Linux VM中使用wifi驱动。

freebsd-wifibox 的最简单安装方法是通过 ports Collection : 也就是 FreeBSD Wifibox Port

check out ports 的HEAD分支
git clone --depth 1 https://git.FreeBSD.org/ports.git /usr/ports
git 更新 /usr/ports
git -C /usr/ports pull
安装 wifibox 前先安装必要的工具
pkg install gtar patchelf squashfs-tools-ng

为了能够启动操作系统时持久化启动 Linuxulator: Linux执行程序兼容 支持,应该配置 修改 /etc/rc.conf 添加:

配置 /etc/rc.conf 持久化激活 Linuxulator
linux_enable="YES"
  • 创建 /compat/linux 目录:

创建 /compat/linux 目录
mkdir -p /compat/linux

有时候 build 可能会出现 Abort trap 消息,从而导致 make 出现错误 134 。当尝试在FreeBSD上运行Linux二进制文件(例如用于安装组件的apk包管理起)时会发生这种情况。通常可能发生在没有使用过 Linuxulator: Linux执行程序兼容 的系统上,并且可能时没有创建 /compat/linux 目录

  • 安装 net/wifibox-core 依赖,其中 socat 软件包仅在 Unix Domain Socket pass-through 需要激活时要求:

安装 wifibox-core 运行依赖
pkg install grub2-bhyve socat

安装 wifibox-alpine

  • 安装 wifibox-alpine

安装 wifibox-alpine
make -C net/wifibox-alpine install clean

安装 wifibox-alpine 时会编译内核模块,我的 BCM943602CS蓝牙无线模块 内核驱动是 brcmfmac

默认配置选项中有 FW_BRCM (Broadcom 802.11n) ,参考 gentoo linux wiki: Apple MacBook Pro 15-inch (2016, Intel, Four Thunderbolt 3 Ports) Boradcom BCM43602 802.11ac 无线网卡驱动是 brcmfmac ,只支持 2.4GHz 网络

编译 wifibox-alpine 时内核选项支持(仅选择 FM_BRCM )
                │ │new [X] IPV6               IPv6 support                                        │ │
                │ │new [X] UDS_PASSTHRU       Control socket pass-through (wpa_supplicant/hostapd)│ │
                │ │─────────────────────────────────── EXTRAS ────────────────────────────────────│ │
                │ │new [ ] XX_MDNS            mDNS Responder Daemon                               │ │
                │ │new [ ] XX_FORWARDING      User-space forwarding                               │ │
                │ │new [ ] XX_TCPDUMP         Packet analysis with tcpdump                        │ │
                │ │new [ ] XX_DRIVER_WL       Broadcom 802.11 STA driver (+ firmware, exclusive)  │ │
                │ │────────────────────────────────── FIRMWARE ───────────────────────────────────│ │
                │ │new [ ] FW_ATH10K          Qualcomm Atheros 802.11ac                           │ │
                │ │new [ ] FW_ATH11K          Qualcomm Atheros 802.11ax                           │ │
                │ │new [ ] FW_ATH12K          Qualcomm Atheros 802.11be                           │ │
                │ │new [ ] FW_ATMEL           Atmel at76c50x 802.11b                              │ │
                │ │new [ ] FW_B43             Broadcom B43xx 802.11a/b/g/n                        │ │
                │ │new [ ] FW_B43LEGACY       Broadcom B43xx 802.11b (legacy)                     │ │
                │ │new [X] FW_BRCM            Broadcom 802.11n                                    │ │
                │ │new [ ] FW_IPW2100         Intel(R) PRO/Wireless 2100 802.11a/b                │ │
                │ │new [ ] FW_IPW2200         Intel(R) PRO/Wireless 2200 802.11b/g/n              │ │
                │ │new [ ] FW_IWL3945         Intel(R) PRO/Wireless 3945ABG 802.11a/b/g           │ │
                │ │new [ ] FW_IWL4965         Intel(R) Wireless WiFi 4965AGN 802.11a/b/g/n        │ │
                │ │new [ ] FW_IWLWIFI         Intel(R) Wireless WiFi 802.11a/b/g/n                │ │
                │ │new [ ] FW_MEDIATEK        MediaTek MT76xxx 802.11n, MT79xx 802.11ax           │ │
                │ │new [ ] FW_MARVELL         Marvell 88W8xxx (TopDog) 802.11b/g/n                │ │
                │ │new [ ] FW_RT61            Ralink RT2xxx (RT61) 802.11a/b/g                    │ │
                │ │new [ ] FW_RTLWIFI         Realtek 802.11n                                     │ │
                │ │new [ ] FW_RTW88           Realtek 802.11ac                                    │ │
                │ │new [ ] FW_RTW89           Realtek 802.11ax                                    │ │
                │ │new [ ] FW_TI              Texas Instruments WL1xxx 802.11b/g/n                │ │
                │ │────────────────────── COMPRESSION [select at least one] ──────────────────────│ │
                │ │new ( ) COMP_GZIP          gzip                                                │ │
                │ │new ( ) COMP_LZ4           lz4                                                 │ │
                │ │new ( ) COMP_LZO           lzo                                                 │ │
                │ │new (*) COMP_XZ            xz                                                  │ │
                │ │new ( ) COMP_ZSTD          zstd                                                │ │
                │ │────────────────────── APPLICATION [select at least one] ──────────────────────│ │
                │ │new ( ) APP_HOSTAPD        Access Point (hostapd)                              │ │
                │ │new (*) APP_WPA_SUPPLICANT WPA Supplicant (wpa_supplicant)                     │ │
                │ │──────────────────────── KERNEL [select at least one] ─────────────────────────│ │
                │ │new (*) KERN_LTS           Linux LTS (6.6.x)                                   │ │
                │ │new ( ) KERN_EDGE          Linux edge (6.10.x)                                 │ │
  • 当选择了 FW_BRCM 选项之后,bcm43602的firmware(属于 linux-firmware 分发的一部分)将被加入镜像,Make.file中包含了 brcmfmac43602-pcie.FreeBSD-BHYVE.bin 软链接到 brcmfmac43602-pcie.bin

  • 虚拟机内部 /lib/firmware/brcm 目录下有一个 brcmfmac43602-pcie.txt 修改内容是设备mac地址

  • 编译配置方法参考 Can't get working with Broadcom BCM43602 (Macbook Pro 2015) #65 讨论中有人提供了编译选项

安装 wifibox-core

  • 安装 wifibox-core

安装 wifibox-core
make -C net/wifibox-core install clean

编译选项

编译 wifibox-core 时选项支持
                │ │    (*) RECOVER_RESTART_VMM  Restart the vmm(4) kernel module on resume     │ │

安装 wifibox

net/wifibox 只是一个metaport,仅仅时为了容易安装另外两个port

使用 wifibox

Project FreeBSD Wifibox 提供了一个 Wifibox EuroBSDcon 2024 演示PPT,介绍了工作原理和配置方法

  • 首先要把FreeBSD中的无线网卡passthrough给wifibox虚拟机内部,所以编辑 /usr/local/etc/wifibox/bhyve.conf :

/usr/local/etc/wifibox/bhyve.conf
cpus=1
memory=128M
console=yes
priority=50
stop_wait_max=30
#以上配置是默认,没有修改

# The value of `passthru` has to match with the slot/bus/function of
# the wireless PCI device, which can be obtained from the output of
# the pciconf(8) tool.  THIS MUST BE SET otherwise the device will not
# be visible for the guest.  Expected format: "s/b/f", e.g."3/0/0" for
# the `pci0:3:0:0` device.
#
# Note that it is possible to include other PCI devices, for example
# the USB xHCI controller in case interaction with the Bluetooth
# device is needed.  Separate the slot/bus/function value with space,
# e.g. "3/0/0 0/20/0", where `pci0:0:20:0` is the xHCI controller.

# 我的BCM43602在 pciconf -lv 输出是:
# none1@pci0:3:0:0:	class=0x028000 rev=0x01 hdr=0x00 vendor=0x14e4 device=0x43ba subvendor=0x106b subdevice=0x0134
#     vendor     = 'Broadcom Inc. and subsidiaries'
#     device     = 'BCM43602 802.11ac Wireless LAN SoC'
#     class      = network
passthru=3/0/0
  • wifibox 的无线配置是从 /usr/local/etc/wifibox/wpa_supplicant/wpa_supplicant.conf 映射进虚拟机的,所以需要修订这个配置以便让虚拟机中的无线网络能够连接:

配置 /usr/local/etc/wifibox/wpa_supplicant/wpa_supplicant.conf 无线网络
ap_scan=1
country=CN
network={
    ssid="SSID"
    #psk="PASSWORD"
    psk=wpa_passphrase_PASSWORD
}

备注

其他按照默认配置就可以工作,不过后面还有一些配置解释

  • 启动wifibox

启动 wifibox
wifibox start

此时FreeBSD系统会增加一个 wifibox0 虚拟网卡,就是和 wifibox-alipine 虚拟机连接的网络接口,这个网络接口在虚拟机内部已经启动了一个 dhcpd 的IP分配服务,所以只要在物理服务器上启动一个 dhclient 连接这个虚拟网卡就能够让FreeBSD通过虚拟机的无线网络访问外部:

在物理FreeBSD主机上启动dhcp客户端
dhclient wifibox0

备注

如果一切正常,此时FreeBSD物理主机已经通过NAT方式从虚拟机的无线网络访问外部网络了

  • 配置FreeBSD系统启动时自动启动 wifibox 并恢复连接,修订FreeBSD物理主机 /etc/rc.conf :

物理主机FreeBSD配置自动运行 wifibox/etc/rc.conf
#wifibox
linux_enable="YES"
wifibox_enable="YES"
ifconfig_wifibox0="SYNCDHCP"
background_dhclient_wifibox0="YES"
defaultroute_delay="0"
  • 连接控制台(debug)

连接wifibox控制台
wifibox console

如果有如下错误提示,是因为默认 /usr/local/etc/wifibox/bhyve.conf 配置 console=no 需要改成 console=yes 然后重启wifibox

连接wifibox控制台错误
ERROR: No null-modem device is configured.

wifibox架构解析

../../_images/wifibox.png

wifibox 使用原生的 Alpine Linux 软件包来构建一个 SquashFS VM磁盘镜像:

  • 混合了定制和标准软件包

  • 在Alpine Linux中使用 aports 只读root文件系统,并使用 9P 挂载物理主机和 /tmp 目录来写入变量和可选的组件(mDNSResponder, tcpdump 等)

  • 包含了无线配置和诊断工具(iw, rfkill, iptables)

../../_images/wifibox-1.png
../../_images/wifibox-2.png
../../_images/wifibox-3.png
../../_images/wifibox-4.png

wifibox完善配置

备注

我主要修订:

  • 配置 wifibox0 使用固定IP地址(不使用dhcp可以加快配置生效)

  • 增加 wifibox 虚拟机内部 iptables 规则,将访问 22 端口定向到FreeBSD物理主机的虚拟 wifibox0 这样可以直接通过ssh访问FreeBSD(其他对外端口也可以通过这种方式)

  • 物理主机 /etc/rc.conf

配置 wifibox0 接口静态IP地址
#wifibox
linux_enable="YES"
wifibox_enable="YES"

#去除掉 3行dhcp分配 wifibox0接口IP 的配置
#ifconfig_wifibox0="SYNCDHCP"
#background_dhclient_wifibox0="YES"
#defaultroute_delay="0"

# 直接看配置 wifibox0接口 10.0.0.2
ifconfig_wifibox0="inet 10.0.0.2/24"
defaultrouter="10.0.0.1"
  • 物理主机 /usr/local/etc/wifibox/bhyve.conf (配置无线网卡直通进虚拟机):

/usr/local/etc/wifibox/bhyve.conf
cpus=1
memory=128M
console=yes
priority=50
stop_wait_max=30
#以上配置是默认,没有修改

# The value of `passthru` has to match with the slot/bus/function of
# the wireless PCI device, which can be obtained from the output of
# the pciconf(8) tool.  THIS MUST BE SET otherwise the device will not
# be visible for the guest.  Expected format: "s/b/f", e.g."3/0/0" for
# the `pci0:3:0:0` device.
#
# Note that it is possible to include other PCI devices, for example
# the USB xHCI controller in case interaction with the Bluetooth
# device is needed.  Separate the slot/bus/function value with space,
# e.g. "3/0/0 0/20/0", where `pci0:0:20:0` is the xHCI controller.

# 我的BCM43602在 pciconf -lv 输出是:
# none1@pci0:3:0:0:	class=0x028000 rev=0x01 hdr=0x00 vendor=0x14e4 device=0x43ba subvendor=0x106b subdevice=0x0134
#     vendor     = 'Broadcom Inc. and subsidiaries'
#     device     = 'BCM43602 802.11ac Wireless LAN SoC'
#     class      = network
passthru=3/0/0
  • (无需修改) /etc/local/etc/wifibox/core.conf 配置日志级别:

/etc/local/etc/wifibox/core.conf 配置日志级别
loglevel=warn
  • (无需修改) /etc/local/etc/wifibox/applicance/hostname 配置虚拟机主机名:

/etc/local/etc/wifibox/applicance/hostname 配置虚拟机主机名
wifibox
  • (无需修改) /etc/local/etc/wifibox/applicance/interfaces.conf 配置虚拟机内部IP地址:

/etc/local/etc/wifibox/applicance/interfaces.conf 配置虚拟机内部IP
iface eth0 inet static
  address 10.0.0.1
  netmask 255.255.255.0

iface eth0 inet6 static
  address fd00::ffff/64

iface wlan0 dhcp
  • (可修改) /etc/local/etc/wifibox/applicance/udhcpd.conf 配置虚拟机内部提供的DHCP所使用IP范围:

/etc/local/etc/wifibox/applicance/udhcpd.conf 配置虚拟机内部提供的DHCP所使用IP范围
start		10.0.0.3
end		10.0.0.254
max_leases	64
interface	eth0
opt	subnet	255.255.255.0
opt	router	10.0.0.1
opt	dns	%%DNS%% 8.8.8.8 8.8.4.4
opt	lease	864000
  • 无线配置 /usr/local/etc/wifibox/wpa_supplicant/wpa_supplicant.conf 按照实际WiFi配置修订

配置 /usr/local/etc/wifibox/wpa_supplicant/wpa_supplicant.conf 无线网络
ap_scan=1
country=CN
network={
    ssid="SSID"
    #psk="PASSWORD"
    psk=wpa_passphrase_PASSWORD
}
  • 物理主机 /usr/local/etc/wifibox/appliance/iptables 添加映射到Host主机22端口

虚拟机iptables增加22端口映射
# This file contains exported IP Tables data that can be read by the
# iptables-restore(8) utility.  It is not meant to be edited by hand
# but regenerated by the iptables-save(8) utility after the necessary
# changes were made via the respective iptables(8) commands.
#
# The IP Tables stored here implement a simplistic IP forwarding and
# NAT between the `eth0` (virtual Ethernet, facing towards the host)
# and `wlan0` (wireless networking) interfaces.

*filter
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
COMMIT
*nat
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:PREROUTING ACCEPT [0:0]
[0:0] -A PREROUTING -p tcp -m tcp -i wlan0 --dport 22 -j DNAT --to-destination 10.0.0.2:22
:POSTROUTING ACCEPT [0:0]
[0:0] -A POSTROUTING -p tcp -m tcp -d 10.0.0.2 --dport 22 -j SNAT --to-source 10.0.0.1
[0:0] -A POSTROUTING -o wlan0 -j MASQUERADE
COMMIT

备注

今后所有需要访问FreeBSD物理主机服务端口的外网进入流量,都需要在这个 iptables 中添加规则。方法和 iptables端口转发(port forwarding) 相同。

  • 附加: 如果要支持 AMD-Vi/IOMMU ,则因为 AMD-Vi passthrough 默认是 disabled 的,还需要在 /boot/loader.conf 中添加:

如果要支持 AMD-Vi/IOMMU 配置 /boot/loader.conf
hw.vmm.amdvi.enable=1

参考