大家好,我是杂烩君。
这篇文章我们来分享从内核驱动编译到 SSH 远程登录的完整操作操作流程,从零为 i.MX6ULL 搭建无线远程登录环境:WiFi 驱动移植 + wpa_supplicant + SSH 全流程实战。(文末提供脚本)
实验环境
| 项目 | 版本/型号 |
|---|---|
| 开发板 | i.MX6ULL(100ASK) |
| 内核版本 | Linux-4.9.88 |
| WiFi 模块 | RTL8723BU(USB 接口) |
| 交叉编译器 | gcc-linaro-6.2.1 arm-linux-gnueabihf |
| 主机系统 | Ubuntu |
整体流程
┌──────────────────┐ ┌───────────────────────┐ ┌──────────────────┐
│ Step 1 │ │ Step 2 │ │ Step 3 │
│ RTL8723BU 驱动 │ ──▶ │ wpa_supplicant 移植 │ ──▶ │ openssh 移植 │
│ 编译进内核 │ │ WiFi 配网 & 联网验证 │ │ SSH 远程登录 │
└──────────────────┘ └───────────────────────┘ └──────────────────┘
WiFi网卡(RTL8723)驱动移植
1、把WiFi驱动文件夹放到内核文件夹中
RTL8723BU驱动文件夹放入内核wireless目录
把RTL8723驱动文件夹放到Linux-4.9.88/drivers/net/wireless中。WiFi驱动可以在网上找得到。
2、修改Kconfig及Makefile文件
修改Linux-4.9.88/drivers/net/wireless文件夹下的Kconfig及Makefile文件。
在Kconfig文件中添加如下内容:
source "drivers/net/wireless/rtl8723BU/Kconfig"
Kconfig文件中添加rtl8723BU源码路径
在Makefile文件中添加如下内容:
obj-$(CONFIG_RTL8723BU) += rtl8723BU/
Makefile文件中添加rtl8723BU编译条目
3、make menuconfig配置内核
我们需要加载rtl8723BU驱动、配置内核,如配置内核支持USB设备、WiFi设备等。
在内核路径输入命令make menuconfig进入内核配置界面。
(1)选中rtl8723BU模块
menuconfig中选中rtl8723BU模块
(2)支持USB设备
USB设备支持配置-1
USB设备支持配置-2
USB设备支持配置-3
USB设备支持配置-4
(3)支持wifi设备
menuconfig中WiFi设备支持配置
(4)支持无线网络IEEE 802.11
IEEE 802.11无线网络支持配置
配置好之后,可以把rtl8723BU驱动编译进内核,也可以编译成内核模块,然后再动态加载。这里我们直接把rtl8723BU驱动编译进内核。
wpa_supplicant移植
有了上一步的基础之后,我们就需要对无线网络进行配置,需要借助一些配置工具,wpa_supplicant就是用来配置无线网络的工具。下面我们来把wpa_supplicant移植到板子上。
交叉编译wpa_supplicant需要依赖于libnl及openssl库,所以我们需要先交叉编译好这两个库。这些库都有很多个版本,可能会遇到版本不匹配的问题,这里我使用的版本如下:
- openssl-1.0.2libnl-3.2.23wpa_supplicant-2.9
(1)交叉编译openssl-1.0.2
./config no-asm -shared
--prefix=/home/LinuxZn/git_clone/openssl-1.0.2/openssl_build_arm
os/compiler:/home/LinuxZn/100ask_imx6ull-sdk/ToolChain/gcc-linaro-6.2.1-2016.11-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-gcc
make
make install
需要执行config脚本生成Makefile文件,这里加了一些配置参数,配置编译安装的位置为openssl_build_arm文件夹,配置交叉编译器为arm-linux-gnueabihf-gcc。
make编译不通过的话,注意Makefile里交叉编译器配置有没有配置正确,正确的配置如:
CROSS_COMPILE= arm-linux-gnueabihf-
CC= /home/LinuxZn/100ask_imx6ull-sdk/ToolChain/gcc-linaro-6.2.1-2016.11-x86_64_arm-linux-gnueabihf/bin/$(CROSS_COMPILE)gcc
编译得到:
openssl交叉编译产物目录
我们有必要检查一下生成的可执行程序、库是不是arm版本的,否则后面交叉编译wpa_supplicant就会有问题。如:
file命令验证编译产物为ARM架构
(2)交叉编译libnl-3.2.23
./configure --prefix=/home/LinuxZn/git_clone/libnl-3.2.23/libnl_build_arm --host=arm-linux-gnueabihf
make
make install
交叉编译得到:
libnl交叉编译产物目录
(3)交叉编译wpa_supplicant-2.9
将wpa_supplicant源码拷贝到linux主机并解压,然后进入wpa_supplicant目录下。 将wpa_supplicant目录下的defconfig拷贝一份并重命名为.config,然后打开.config文件:
cp defconfig .config
vim .config
在.config文件中增加如下内容,其中openssl和libnl库的路径就是刚刚openssl和libnl安装的位置:
#交叉编译器
CC=arm-linux-gnueabihf-gcc
#openssl 库和头文件路径
CFLAGS += -I/home/LinuxZn/git_clone/openssl-1.0.2/openssl_build_arm/include
LIBS += -L/home/LinuxZn/git_clone/openssl-1.0.2/openssl_build_arm/lib
#libnl 库和头文件路径
CFLAGS += -I/home/LinuxZn/git_clone/libnl-3.2.23/libnl_build_arm/include/libnl3
LIBS += -L/home/LinuxZn/git_clone/libnl-3.2.23/libnl_build_arm/lib
接着还需要指定 libnl 库的 pkgconfig 路径,环境变量 PKG_CONFIG_PATH 保存着 pkgconfig 包路径:
export PKG_CONFIG_PATH=/home/LinuxZn/git_clone/libnl-3.2.23/libnl_build_arm/lib/pkgconfig:$PKG_CONFIG_PATH
编译:
make
编译可能会报如下错误。这时候把.config里的下面两句屏蔽掉即可:
#CONFIG_CTRL_IFACE_DBUS_NEW=y
#CONFIG_CTRL_IFACE_DBUS_INTRO=y
编译结束后会在当前目录下生成wpa_supplicant和wpa_cli两个工具。 将这两个文件拷贝到开发板/usr/bin目录下。
首先,在开发板/etc目录下新建一个wpa_supplicant.conf文件,文件内容如下:
ctrl_interface=/var/run/wpa_supplicant
update_config=1
ctrl_interface_group=root
ap_scan=1
network={
ssid="你的WiFi名称"
psk="你的WiFi密码"
key_mgmt=WPA-PSK
}
接着需要新建/var/run/wpa_supplicant目录:
mkdir -p /var/run/wpa_supplicant
最后使用下面的命令连接wifi:
wpa_supplicant -Dwext -c /etc/wpa_supplicant.conf -i wlan1&
输出如下信息(wlan1: CTRL-EVENT-CONNECTED)则表明已经连接成功
[root@imx6ull:/etc]# [ 968.615223] ------------[ cut here ]------------
[ 968.622210] WARNING: CPU: 0 PID: 127 at net/wireless/sme.c:733 __cfg80211_connect_result+0x2e4/0x404
[ 968.635489] ---[ end trace c94b130fc23cc767 ]---
wlan1: Associated with 28:bf:89:7b:a1:23
wlan1: WPA: Key negotiation compl[ 968.655338] IPv6: ADDRCONF(NETDEV_CHANGE): wlan1: link becomes ready
eted with 28:bf:89:7b:a1:23 [PTK=CCMP GTK=CCMP]
wlan1: CTRL-EVENT-CONNECTED - Connection to 28:bf:89:7b:a1:23 completed [id=0 id_str=]
这样就是连接成功,再动态获取下ip即可
udhcpc -i wlan1 //-i指定网卡
接着执行ifconfig就可以看到已经分配ip地址的无线网卡了。这里若wlan1还是没有ip地址,可能是获取的ip地址还没有被写入网卡设备。
我们开发板分到的ip如:
ifconfig查看wlan1已分配IP地址
这时候如果我们的路由器可以上网的话,就可以ping得通外网,如果路由器没网的话,可以ping我们的Ubuntu主机进行测试。这里我们ping百度测试如下则表明我们的开发板已经搭建好网络环境了:
ping百度验证网络连通性
这时候就可以愉快地玩耍啦!
SSH移植
上面两步已经让我们的开发板具有无线网络环境了。有必要搭建一个实用的环境:ssh环境。
Secure Shell(SSH) 是由 IETF(The Internet Engineering Task Force) 制定的建立在应用层基础上的安全网络协议。它是专为远程登录会话(甚至可以用Windows远程登录Linux服务器进行文件互传)和其他网络服务提供安全性的协议,可有效弥补网络中的漏洞。 我们工作中经常使用ssh,Ubuntu主机可以很方便地与开发板进行交互。
交叉编译openssh需要依赖于zlib及openssl库,所以我们需要先交叉编译好这两个库。这些库都有很多个版本,可能会遇到版本不匹配的问题,这里我使用的版本如下:
- openssl-1.0.2zlib-1.2.3openssh-4.6p1
安全提示: openssh-4.6p1 版本较旧(发布于 2007 年),存在已知安全漏洞,仅建议在内网学习环境中使用,切勿将 SSH 端口暴露到公网。生产环境请使用更新版本的 openssh。
(1)交叉编译openssl-1.0.2
交叉编译openssl-1.0.2在上面编译wpa_supplicant-2.9已经演示过了,这里不再演示。
(2)交叉编译zlib-1.2.3
./configure --prefix=/home/LinuxZn/git_clone/zlib-1.2.3/zlib_build_arm
得到Makefile,修改里面的CC为交叉编译器:
CC=arm-linux-gnueabihf-gcc
CFLAGS=-O3 -DUSE_MMAP
#CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7
#CFLAGS=-g -DDEBUG
#CFLAGS=-O3 -Wall -Wwrite-strings -Wpointer-arith -Wconversion
# -Wstrict-prototypes -Wmissing-prototypes
LDFLAGS=-L. libz.a
LDSHARED=arm-linux-gnueabihf-gcc
CPP=arm-linux-gnueabihf-gcc -E
然后执行:
make
make install
编译得到:
zlib交叉编译产物目录
(3)交叉编译openssh-4.6p1
./configure
--host=arm-linux-gnueabihf
--with-libs
--with-zlib=/home/LinuxZn/git_clone/zlib-1.2.3/zlib_build_arm
--with-ssl-dir=/home/LinuxZn/git_clone/openssl-1.0.2/openssl_build_arm
--disable-etc-default-login
CC=/home/LinuxZn/100ask_imx6ull-sdk/ToolChain/gcc-linaro-6.2.1-2016.11-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-gcc
AR=/home/LinuxZn/100ask_imx6ull-sdk/ToolChain/gcc-linaro-6.2.1-2016.11-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-ar
make
其中,各参数含义如下:
--host 表示运行的平台。
--with-libs 表示需要的库文件。
--with-zlib 表示库文件 zlib 的安装路径。
--with-ssl-dir 表示 openssl 文件的安装路径。
--disable-etc-default-login 表示不使用当前环境变量的编译器,所以后面配置参数时,最后直接配置 CC 和 AR 这两个编译器。
CC 表示设置使用的编译器。
AR 表示设置使用的编译器的路径。
编译:
make
这时候在openssh-4.6p1目录下会生成scp 、sftp、ssh、sshd、ssh-add、ssh-agent等工具:
openssh编译生成的可执行文件列表
在板子上新建“/usr/libexec“、“/usr/local/etc ”、“/usr/local/bin ”三个目录:
mkdir -p /usr/libexec /usr/local/etc /usr/local/bin
下面把相关工具传到开发板上备用:
① 将 openssh-4.6p1 下的生成“scp 、sftp、ssh、sshd、ssh-add、ssh-agent、ssh-keygen、ssh-keyscan”等可执行文件拷贝到开发板的/usr/local/bin目录下,命令
mv scp sftp ssh sshd ssh-add ssh-agent ssh-keygen ssh-keyscan /usr/local/bin/
② 将“moduli、ssh_config、sshd_config”拷贝到开发板的/usr/local/etc目录下。
mv moduli ssh_config sshd_config /usr/local/etc
③ 将“sftp-server、ssh-keysign”拷贝到开发板的/usr/libexec目录下。
mv sftp-server ssh-keysign /usr/libexec
④ 使用“ssh-keygen”生成个四个 key 文件“ssh_host_rsa_key”“ssh_host_dsa_key” “ssh_host_ecdsa_key和“ssh_host_ed25519_key”。在openssh-4.6p1目录下,输入命令:
ssh-keygen -t rsa -f ssh_host_rsa_key -N ""
ssh-keygen -t dsa -f ssh_host_dsa_key -N ""
ssh-keygen -t ecdsa -f ssh_host_ecdsa_key -N ""
ssh-keygen -t ed25519 -f ssh_host_ed25519_key -N ""
执行完成之后,将生成的如下几个文件拷贝到开发板的/usr/local/etc/目录下:
ssh_host_rsa_key
ssh_host_dsa_key
ssh_host_ecdsa_key
ssh_host_ed25519_key
然后将它们的权限修改为 600。
mv ssh_host_rsa_key ssh_host_dsa_key ssh_host_ecdsa_key ssh_host_ed25519_key /usr/local/etc/
chmod 600 ssh_host_rsa_key ssh_host_dsa_key ssh_host_ecdsa_key ssh_host_ed25519_key
在开发板终端中,使用命令vi /etc/passwd,打开 ssh 密钥文件,在 /etc/passwd文件底行添加以下内容:
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
接着在开发板上新建 root 账户,使用命令:
passwd root
然后在开发板上运行 sshd 二进制文件,命令
/usr/local/bin/sshd
可能会报错:
/usr/local/bin/sshd: error while loading shared libraries: libnsl.so.1: cannot open shared object file: No such file or directory
拷贝交叉编译器下的相关库至板子中。再次运行,可能会报错:
Could not load host key: /usr/local/etc/ssh_host_key
Disabling protocol version 1. Could not load host key
但是不影响使用。
最后,在我们的Ubuntu主机中使用ssh登录我们的开发板。首先,需要确认我们的Ubuntu主机的ip与开发板的ip是在同一网段内,如:
Ubuntu IP:192.168.1.9
开发板IP:192.168.1.10
在我们的Ubuntu中使用如下命令登录开发板:
Ubuntu通过SSH成功登录开发板
到了这一步,我们的ssh环境就已经搭建成功了。之后就可以愉快地玩耍了!
附:一键脚本
上面的步骤比较繁琐,这里提供两个脚本,分别在Ubuntu 主机和开发板上执行,可以省去大量重复敲命令的时间。使用前请根据自己的实际环境修改脚本顶部的配置变量。
脚本一:主机端交叉编译(Ubuntu 上执行)
将以下内容保存为 build_all.sh,赋予执行权限后运行:
chmod +x build_all.sh
./build_all.sh
脚本内容:
#!/bin/bash
set -e
#========== 根据你的实际环境修改以下变量 ==========
TOOLCHAIN=/home/LinuxZn/100ask_imx6ull-sdk/ToolChain/gcc-linaro-6.2.1-2016.11-x86_64_arm-linux-gnueabihf
CROSS_COMPILE=${TOOLCHAIN}/bin/arm-linux-gnueabihf-
CC=${CROSS_COMPILE}gcc
AR=${CROSS_COMPILE}ar
WORK_DIR=$(pwd)/wifi_ssh_build
OPENSSL_SRC=openssl-1.0.2
LIBNL_SRC=libnl-3.2.23
WPA_SRC=wpa_supplicant-2.9
ZLIB_SRC=zlib-1.2.3
OPENSSH_SRC=openssh-4.6p1
#================================================
OPENSSL_INSTALL=${WORK_DIR}/${OPENSSL_SRC}/openssl_build_arm
LIBNL_INSTALL=${WORK_DIR}/${LIBNL_SRC}/libnl_build_arm
ZLIB_INSTALL=${WORK_DIR}/${ZLIB_SRC}/zlib_build_arm
OUTPUT_DIR=${WORK_DIR}/output
mkdir -p ${OUTPUT_DIR}
echo"=============================="
echo" [1/5] 交叉编译 openssl"
echo"=============================="
cd${WORK_DIR}/${OPENSSL_SRC}
./config no-asm -shared
--prefix=${OPENSSL_INSTALL}
os/compiler:${CC}
# 确保 Makefile 中交叉编译器正确
sed -i "s|^CC=.*|CC= ${CC}|" Makefile
sed -i "s|^AR=.*|AR= ${AR} $(ARFLAGS) r|" Makefile
make -j$(nproc)
make install
echo"=============================="
echo" [2/5] 交叉编译 libnl"
echo"=============================="
cd${WORK_DIR}/${LIBNL_SRC}
./configure --prefix=${LIBNL_INSTALL} --host=arm-linux-gnueabihf
make -j$(nproc)
make install
echo"=============================="
echo" [3/5] 交叉编译 wpa_supplicant"
echo"=============================="
cd${WORK_DIR}/${WPA_SRC}/wpa_supplicant
cp defconfig .config
cat >> .config << EOF
CC=${CC}
CFLAGS += -I${OPENSSL_INSTALL}/include
LIBS += -L${OPENSSL_INSTALL}/lib
CFLAGS += -I${LIBNL_INSTALL}/include/libnl3
LIBS += -L${LIBNL_INSTALL}/lib
EOF
sed -i 's/^CONFIG_CTRL_IFACE_DBUS_NEW=y/#CONFIG_CTRL_IFACE_DBUS_NEW=y/' .config
sed -i 's/^CONFIG_CTRL_IFACE_DBUS_INTRO=y/#CONFIG_CTRL_IFACE_DBUS_INTRO=y/' .config
export PKG_CONFIG_PATH=${LIBNL_INSTALL}/lib/pkgconfig:$PKG_CONFIG_PATH
make -j$(nproc)
cp wpa_supplicant wpa_cli ${OUTPUT_DIR}/
echo"=============================="
echo" [4/5] 交叉编译 zlib"
echo"=============================="
cd${WORK_DIR}/${ZLIB_SRC}
./configure --prefix=${ZLIB_INSTALL}
sed -i "s|^CC=.*|CC=${CC}|" Makefile
sed -i "s|^LDSHARED=.*|LDSHARED=${CC}|" Makefile
sed -i "s|^CPP=.*|CPP=${CC} -E|" Makefile
make -j$(nproc)
make install
echo"=============================="
echo" [5/5] 交叉编译 openssh"
echo"=============================="
cd${WORK_DIR}/${OPENSSH_SRC}
./configure
--host=arm-linux-gnueabihf
--with-libs
--with-zlib=${ZLIB_INSTALL}
--with-ssl-dir=${OPENSSL_INSTALL}
--disable-etc-default-login
CC=${CC}
AR=${AR}
make -j$(nproc)
cp scp sftp ssh sshd ssh-add ssh-agent ssh-keygen ssh-keyscan ${OUTPUT_DIR}/
cp sftp-server ssh-keysign ${OUTPUT_DIR}/
cp moduli ssh_config sshd_config ${OUTPUT_DIR}/
echo"=============================="
echo" 生成 SSH 主机密钥"
echo"=============================="
cd${OUTPUT_DIR}
ssh-keygen -t rsa -f ssh_host_rsa_key -N ""
ssh-keygen -t dsa -f ssh_host_dsa_key -N ""
ssh-keygen -t ecdsa -f ssh_host_ecdsa_key -N ""
ssh-keygen -t ed25519 -f ssh_host_ed25519_key -N ""
echo""
echo"========================================"
echo" 编译完成!所有产物位于:"
echo" ${OUTPUT_DIR}"
echo""
echo" 请将 output 目录整体拷贝到开发板,"
echo" 然后在板子上执行 deploy.sh 部署脚本。"
echo"========================================"
脚本二:开发板端部署(开发板上执行)
将 output 目录拷贝到开发板后(如通过 U 盘、NFS 或 scp),在开发板上保存以下内容为 deploy.sh 并执行:
chmod +x deploy.sh
./deploy.sh
脚本内容:
#!/bin/sh
set -e
#========== 根据你的实际环境修改以下变量 ==========
OUTPUT_DIR=$(cd"$(dirname "$0")" && pwd)
WIFI_SSID="你的WiFi名称"
WIFI_PSK="你的WiFi密码"
WIFI_IFACE="wlan1"
#================================================
echo"[1/6] 创建目录结构..."
mkdir -p /usr/libexec /usr/local/etc /usr/local/bin /var/run/wpa_supplicant /var/empty/sshd
echo"[2/6] 部署 wpa_supplicant..."
cp ${OUTPUT_DIR}/wpa_supplicant ${OUTPUT_DIR}/wpa_cli /usr/bin/
echo"[3/6] 部署 openssh..."
cp ${OUTPUT_DIR}/scp ${OUTPUT_DIR}/sftp ${OUTPUT_DIR}/ssh ${OUTPUT_DIR}/sshd
${OUTPUT_DIR}/ssh-add ${OUTPUT_DIR}/ssh-agent ${OUTPUT_DIR}/ssh-keygen
${OUTPUT_DIR}/ssh-keyscan /usr/local/bin/
cp ${OUTPUT_DIR}/sftp-server ${OUTPUT_DIR}/ssh-keysign /usr/libexec/
cp ${OUTPUT_DIR}/moduli ${OUTPUT_DIR}/ssh_config ${OUTPUT_DIR}/sshd_config /usr/local/etc/
cp ${OUTPUT_DIR}/ssh_host_rsa_key ${OUTPUT_DIR}/ssh_host_dsa_key
${OUTPUT_DIR}/ssh_host_ecdsa_key ${OUTPUT_DIR}/ssh_host_ed25519_key /usr/local/etc/
chmod 600 /usr/local/etc/ssh_host_*_key
echo"[4/6] 配置 sshd 用户..."
if ! grep -q "^sshd:" /etc/passwd; then
echo"sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin" >> /etc/passwd
echo" -> 已添加 sshd 用户到 /etc/passwd"
else
echo" -> sshd 用户已存在,跳过"
fi
echo"[5/6] 生成 WiFi 配置文件..."
cat > /etc/wpa_supplicant.conf << EOF
ctrl_interface=/var/run/wpa_supplicant
update_config=1
ctrl_interface_group=root
ap_scan=1
network={
ssid="${WIFI_SSID}"
psk="${WIFI_PSK}"
key_mgmt=WPA-PSK
}
EOF
echo"[6/6] 启动服务..."
echo" -> 连接 WiFi..."
wpa_supplicant -Dwext -c /etc/wpa_supplicant.conf -i ${WIFI_IFACE} -B
sleep 3
echo" -> 获取 IP 地址..."
udhcpc -i ${WIFI_IFACE}
echo" -> 启动 sshd..."
/usr/local/bin/sshd
echo""
echo"========================================"
echo" 部署完成!"
echo""
IP_ADDR=$(ifconfig ${WIFI_IFACE} | grep 'inet addr' | awk -F: '{print $2}' | awk '{print $1}')
if [ -n "${IP_ADDR}" ]; then
echo" 开发板 IP: ${IP_ADDR}"
echo" 在主机执行: ssh root@${IP_ADDR}"
else
echo" 未获取到 IP,请检查 WiFi 配置。"
fi
echo"========================================"
使用说明:先在 Ubuntu 主机上把各源码包解压到同一个工作目录下,修改 build_all.sh顶部的路径变量,然后执行脚本完成所有交叉编译。编译完成后,将生成的
output目录整体拷贝到开发板。
在开发板上修改
deploy.sh顶部的 WiFi 名称和密码,执行脚本即可一键完成部署、联网、启动 SSH 服务。
206