请注意,这篇文章不是针对第一次接触内网穿透的读者的教学,而是《从零搭建一个又快又安全的
VNC 服务》这篇文章的后续内容。
问题引入
如果你点进了这篇文章,你应该是可以借助通过公网服务器来进行内网穿透的。但是我白嫖的
Azure
服务器不在国内,即使能连接我的工位电脑,速度也有些影响使用体验。
在前序文章《从零搭建一个又快又安全的 VNC
服务》中我提到自己的寝室使用宽带拨号后,有动态公网IP,可以相当程度上解决使用云服务器连接工位速度慢的问题。但最近我通过询问读研的学长,得知研究生宿舍的网线并不支持公网IP,这就意味着我目前远程连接工位电脑的解决方案,将在我本科毕业之后完全失效——这怎么可以忍?但我当时并没有想出一个好的解决方案。
这糟糕的现实,因近期科研需要购买支持 RVV 1.0 CPU
的开发板,便有了一丝转机:我可以将我现在电脑作为 ssh
跳板机的职能转移给刚买的开发板,并在我毕业之后将开发板交给自己的学弟,让他继续将开发板接入宽带,从而我得以继续实现“居家办公”的美好生活。
目标分解
现在我们需要这样的一种开发板,我们需要让它完成以下四种功能:
开机自动启动系统。
开机自动实现 PPPoE 拨号。
开机自动运行先前写好的 ddns 脚本。
我可以在开发板进行与 RVV 1.0 相关的开发。
为了满足第四个需求,经过了几个小时的
STFW,我排除了市面上绝大多数现成的开发板,我发现只有嘉楠的 CanMV-K230
满足我的需求(虽然之后有人告诉我“进迭时空”也有一种型号支持 RVV
1.0,但由于其面积太大并且价格太贵而排除)。再综合一下嘉楠的用户文档,我又梳理出一下具体的实现步骤:
购买 CanMV-K230 开发板。
购买合适的 SD 卡并插入开发板。
刷写官方提供的系统镜像。
启动系统,将网线插入开发板,测试拨号是否正常。
将主机的 ddns 脚本拷贝至开发板,测试 ddns 服务是否正常。
从其他设备 ssh
自己的域名,看看是否可以连接到开发板和自己的工位电脑。
感觉似乎没那么难,但其实每一步都是坑。
踩坑经历
购买 CanMV-K230 开发板
首先的第一步当然就是买开发板了,我在淘宝上面搜索
CanMV-K230,就跳出来一堆开发板。然后点了购买量最多的一个,是 01studio
官方旗舰店,然后一看——诶,居然内存是1G,而不是官方所说的512M?太棒了,现在工艺升级换代这么快,赶紧买买买!于是,从打开淘宝开始,我花了不到两分钟就下单了,只是确认一下型号是不是
K230,CPU的版本是不是 C908(支持 RVV 1.0)的版本而已。
三天之后我收到货,商家也附带了一份 32G 的 SD
卡。于是我开始按照嘉楠的文档刷写镜像,我首先选择了带 01studio
字样的镜像去刷写,没遇到什么问题。然后接好电源,minicom
一打开——诶?怎么是个 python 的 shell?我想敲
exit
,结果不支持这个命令,我想按Ctrl+D
,怎么屏幕一闪又重启到python?难道我花了
284 就是买了 python shell?
我问了朋友,得知你看到的 python shell 其实是
micropython,他尝试了一下
jailbreak,但没有成功。然后我又试了一下嘉楠官网其他的镜像,发现除了带
01studio
字样的镜像,其他都不行。更为严重的问题是,这个开发板不带以太网接口,需要单独购买
USB 转以太网的转接头。我当时就有了想退货的打算。
在随后的几天,我尝试了手动编译嘉楠给 CanMV-K230 提供的 K230-SDK 和 K230-linux-SDK
并生成镜像,但无一例外要么就是启动不了,要么就是一打开就是讨厌的
micropython 界面。我也问了淘宝客服,客服把皮球踢给 01studio 的交流群,01
又踢给嘉楠,嘉楠最后让我尝试用 USB 编程器尝试连接 linux
的调试串口,但我也没有成功。
我寻思毕竟 01studio
算是嘉楠的下游,而且他的主打客户是那批要炼丹的人(CanMV K230 AI
开发板),不是我。而且相比嘉楠官方的开发板这个东西“有点山寨”,继续调试可能有更多不受官方支持的问题。于是在串口调试失败的第二天,也就是收到货的第五天(因为七天无理由退货,只用交运费),我正式提出了退货申请。
感觉现在啥东西都要扯个 AI 才有销量一般,感觉 AI
是真成流量密码了。
购买合适的 SD 卡并插入开发板
在退款的当天,我又重新买了一个嘉楠官方的开发板,价格 283(原价
323,不带 SD 卡),然后顺便也同时买了 64G 的 SD 卡,价格 17(原价
25)。
有经验的人应该发现 SD
卡的价格不太对,也确实是这样。当时的我其实是信奉“好货不便宜,便宜无好货”这个准则的,于是开发板挑了价格贵的买,但
SD
卡就没想那么多了。因为我看好评比例很高,心想如果买到假货,退了然后附近马上买一个贵一点的,也不亏。
然后神奇的是,SD
卡这边的物流是实时更新的,而开发版那边物流就是:已发货、已揽件、派送中。然后过了整整三天也没有任何更新,而
SD
卡这边已经显示运到当地的转运中心了。我当时一度以为自己的开发板又买到假货了,便在第三天的早上给派送员打了个电话,结果派送员说也到了转运中心,我才放心了一点。
到了第三天晚上,我的 SD
卡到了,而开发板依旧没有任何动静,但我想现在已经是非工作时间,再去打扰配送员似乎不太好,于是我等到了第四天早上又问了一遍。结果派送员说已经到了,她告诉了我取件码。我当时就很疑惑——为什么东西到了淘宝都不说一声?但之后拆封一看,开发板确实跟嘉楠官网一模一样,我也没什么好气的。
然后便是用我昨天到的 SD 卡装系统,用的是嘉楠官网的 debian 镜像。使用
dd
烧录之后,首先用了 gparted 把 linux 分区从 1G 扩容到
58G,然后我就从开发板启动 linux,接着就出现了这样的错误:
1 2 3 4 5 6 junyu33@zjy-canmv:~$ sudo apt install net-tools [sudo] password for junyu33: E: dpkg was interrupted, you must manually run 'sudo dpkg --configure -a' to correct the problem. junyu33@zjy-canmv:~$ sudo dpkg --configure -a dpkg: error: parsing file '/var/lib/dpkg/updates/0000' near line 0 : MSDOS end of file (^Z) in field name ''
这个错误我之前没有见到过,于是我开始怀疑自己的 SD
卡是不是坏了,把错误丢给了
ChatGPT,它让我把/var/lib/dpkg/updates/0000
删了。于是,就有了接下来的一幕:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 junyu33@zjy-canmv:~$ sudo rm /var/lib/dpkg/updates/* [ 151.617623] EXT4-fs error (device mmcblk1p3) : ext4_lookup:1708 : inode #13720: comm rm: deleted inode referenced: 6563 [ 151.631373 ] EXT4-fs error (device mmcblk1p3): ext4_lookup:1708 : inode #13720: comm rm: deleted inode referenced: 6563 rm: cannot remove '/[ 153.220073 ] EXT4-fs error (device mmcblk1p3): ext4_lookup:1708 : inode #1372 0: comm rm: deleted inode referenced: 6719 var/lib/dpkg/updates/0007 ': Stru[ 153.234325 ] EXT4-fs error (device mmcblk1p3): ext4_lookup:1708 : inode #13720: comm rm: deleted inode referenced: 6719 cture needs cleaning rm: cannot remove '/[ 153.248629 ] EXT4-fs error (device mmcblk1p3): ext4_lookup:1708 : inode #1372 0: comm rm: deleted inode referenced: 8089 var/lib/dpkg/updates/0008 ': Structure needs cleaning [ 153.321093 ] EXT4-fs error (device mmcblk1p3): ext4_lookup:1708 : inode #13720: comm rm: deleted inode referenced: 8089 rm: cannot remove '/[ 153.334419 ] EXT4-fs error (device mmcblk1p3): ext4_lookup:1708 : inode #1372 0: comm rm: deleted inode referenced: 8144 var/lib/dpkg/updates/0010 ': Stru[ 153.348760 ] EXT4-fs error (device mmcblk1p3): ext4_lookup:1708 : inode #13720: comm rm: deleted inode referenced: 8144 cture needs cleaning rm: cannot remove '/var/lib/dpkg/updates/0011 ': Structure needs cleaning [ 153.457330 ] EXT4-fs error (device mmcblk1p3): ext4_lookup:1708 : inode #13720: comm rm: deleted inode referenced: 6557 [ 153.470351 ] EXT4-fs error (device mmcblk1p3): ext4_lookup:1708 : inode #13720: comm rm: deleted inode referenced: 6557 rm: cannot remove '/var/lib/dpkg/updates/0013 ': Structure needs cleaning rm: cannot remove '/var/lib/dpkg/updates/0014 ': Structure needs cleaning rm: cannot remove '/var/lib/dpkg/updates/0015 ': Structure needs cleaning rm: cannot remove '/var/lib/dpkg/updates/0016 ': Structure needs cleaning rm: cannot remove '/var/lib/dpkg/updates/0017 ': Structure needs cleaning rm: cannot remove '/var/lib/dpkg/updates/0018 ': Structure needs cleaning rm: cannot remove '/var/lib/dpkg/updates/0019 ': Structure needs cleaning
当时我的想法就是想法就是:完犊子了,要准备退货了。但是我还是尝试用
fsck
修了一下,暂时没啥问题。结果之后装了一堆东西之后,重启了一下,又出现了“dpkg
was interrupted”的错误。我心想,这下得准备检查 SD
卡是否又被注水了(上次买到扩容的东西是在初中的时候,买了个 128G 的
U盘,实际上只有 8G),去网上搜工具,然后找到了这个链接 。
我根据这个链接看了一下方法二,确实背面有个数字
"08",然后看了看品牌叫“Jinsudun”(没错,长得很像
Kingston,但不是),这下绝对跑不掉了,马上找扩容软件开始测试。
Windows 这边的话我看的链接说用 MyDiskTest,我用 Windows
虚拟机测了一下,结果一测就闪退了,然后用室友的电脑测了一下,照样闪退。感觉是商家做了手脚,让这个软件运行不起来。
Linux 这边我首先用 badblocks 扫了一遍(只读),没有问题。然后我又用
f3 测了一遍,最后发现了问题,结果如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 F3 read 8 .0 Copyright (C) 2010 Digirati Internet LTDA.This is free software; see the source for copying conditions. SECTORS ok/corrupted/changed/overwritten Validating file 1 .h2w ... 2097152 / 0 / 0 / 0 Validating file 2 .h2w ... 2097152 / 0 / 0 / 0 Validating file 3 .h2w ... 2050304 / 46848 / 0 / 0 Validating file 4 .h2w ... 0 / 2097152 / 0 / 0 Validating file 5 .h2w ... 0 / 2097152 / 0 / 0 Validating file 6 .h2w ... 0 / 2097152 / 0 / 0 Validating file 7 .h2w ... 0 / 2097152 / 0 / 0 Validating file 8 .h2w ... 0 / 2097152 / 0 / 0 Validating file 9 .h2w ... 0 / 2097152 / 0 / 0 Validating file 10 .h2w ... 0 / 2097152 / 0 / 0 Validating file 11 .h2w ... 0 / 2097152 / 0 / 0 Validating file 12 .h2w ... 0 / 2097152 / 0 / 0 Validating file 13 .h2w ... 0 / 2097152 / 0 / 0 Validating file 14 .h2w ... 0 / 2097152 / 0 / 0 Validating file 15 .h2w ... 0 / 2097152 / 0 / 0 Validating file 16 .h2w ... 0 / 2097152 / 0 / 0 Validating file 17 .h2w ... 0 / 2097152 / 0 / 0 Validating file 18 .h2w ... 0 / 2097152 / 0 / 0 Validating file 19 .h2w ... 0 / 2097152 / 0 / 0 Validating file 20 .h2w ... 0 / 2097152 / 0 / 0 Validating file 21 .h2w ... 0 / 2097152 / 0 / 0 Validating file 22 .h2w ... 0 / 2097152 / 0 / 0 Validating file 23 .h2w ... 0 / 2097152 / 0 / 0 Validating file 24 .h2w ... 0 / 2097152 / 0 / 0 Validating file 25 .h2w ... 0 / 2097152 / 0 / 0 Validating file 26 .h2w ... 0 / 2097152 / 0 / 0 Validating file 27 .h2w ... 0 / 2097152 / 0 / 0 Validating file 28 .h2w ... 0 / 2097152 / 0 / 0 Validating file 29 .h2w ... 0 / 2097152 / 0 / 0 Validating file 30 .h2w ... 0 / 2097152 / 0 / 0 Validating file 31 .h2w ... 0 / 2097152 / 0 / 0 Validating file 32 .h2w ... 0 / 2097152 / 0 / 0 Validating file 33 .h2w ... 0 / 2097152 / 0 / 0 Validating file 34 .h2w ... 0 / 2097152 / 0 / 0 Validating file 35 .h2w ... 0 / 2097152 / 0 / 0 Validating file 36 .h2w ... 0 / 2097152 / 0 / 0 Validating file 37 .h2w ... 0 / 2097152 / 0 / 0 Validating file 38 .h2w ... 0 / 2097152 / 0 / 0 Validating file 39 .h2w ... 0 / 2097152 / 0 / 0 Validating file 40 .h2w ... 0 / 2097152 / 0 / 0 Validating file 41 .h2w ... 0 / 2097152 / 0 / 0 Validating file 42 .h2w ... 0 / 2097152 / 0 / 0 Validating file 43 .h2w ... 0 / 2097152 / 0 / 0 Validating file 44 .h2w ... 0 / 2097152 / 0 / 0 Validating file 45 .h2w ... 0 / 2097152 / 0 / 0 Validating file 46 .h2w ... 0 / 2097152 / 0 / 0 Validating file 47 .h2w ... 0 / 2097152 / 0 / 0 Validating file 48 .h2w ... 0 / 2097152 / 0 / 0 Validating file 49 .h2w ... 0 / 2097152 / 0 / 0 Validating file 50 .h2w ... 0 / 2097152 / 0 / 0 Validating file 51 .h2w ... 0 / 2097152 / 0 / 0 Validating file 52 .h2w ... 0 / 2097152 / 0 / 0 Validating file 53 .h2w ... 0 / 2097152 / 0 / 0 Validating file 54 .h2w ... 0 / 2097152 / 0 / 0 Validating file 55 .h2w ... 1947392 / 149760 / 0 / 0 Validating file 56 .h2w ... 2097152 / 0 / 0 / 0 Validating file 57 .h2w ... 2097152 / 0 / 0 / 0 Validating file 58 .h2w ... 2097152 / 0 / 0 / 0 Validating file 59 .h2w ... 1212160 / 0 / 0 / 0 Data OK: 7 .48 GB (15695616 sectors) Data LOST: 51 .09 GB (107151360 sectors) Corrupted : 51 .09 GB (107151360 sectors) Slightly changed: 0 .00 Byte (0 sectors) Overwritten : 0 .00 Byte (0 sectors) Average reading speed: 16 .12 MB/s
结果果然是 8G 的注水 SD 卡,只有前面 3G、后面 5G
是可以用的。我马上把全额退款申请发过去(不退货),然后不到一分钟,我的
17 块就回来了。
另外,我顺便看了一下淘宝的评论,发现只有几十条差评(相对于几万条的好评确实挺少),并且差评内容都是说
SD
卡的质量问题,还有咒骂无良商家的。现在我终于明白我姐为什么说“在淘宝买东西只看差评”这句话了。
在写作之日,我又看了一眼那个商品的评论区,结果连那几十个差评也找不到了,我不想多说什么。
当然,虽然被假冒 SD
卡折腾了半天,但我的任务还是要继续完成的。我寻思这种东西应该随处都能买得到,于是我又在第二天早上看了一下美团外卖,选了个大品牌(SanDisk),外卖不到半个小时就到了,但是我一看——诶,这个SD卡怎么这么大?我又上网搜了一下,原来我理解的“小SD卡”是TF卡(或者叫
microSD 卡),所以我很不幸又买错了。
我寻思店铺离我寝室就几百米,可能还是直接走路去退货比较方便,到了商家那里,我解释了自己把商品搞错了,她也很愿意给我退货。然后我问你们有没有
TF 卡,她说不清楚,可以找找。最后她找到了,是 ThinkPlus
的牌子,感觉虽然不如那些大品牌,但肯定是比什么 Jinsudun
好得多的。商家说她这里只有 32G 和 128G 的,我想到时肯定要下载一堆
toolchain,编译一堆东西,还是买个 128G 比较稳妥。
然后一看商家那边的价格是 90 块,而我这边只要花 50
出头就可以买到。不知道美团是哪里来的钱给这 40 块买单的。
拿着 128G 的 TF 卡回去,我还是用 f3 测了前面
5GB,没有问题。然后我就开始烧录镜像了,直到写作之日,依旧没有出现什么问题,注水的嫌疑基本上可以排除了。
刷写官方提供的系统镜像
如前文所说,官方有两种不同的镜像,一种是大核搭载 micropython 的
RTOS,小核搭载 linux 的镜像。另一种是安装在基于 debian, ubuntu
这两个发行版的镜像。当然,后者更满足我的需求,于是我还是将之前的 debian
镜像烧到我的 TF 卡,我终于在 minicom 的输出中看到了 debian 的字样。
就这样结束了吗?还早呢!
然后,我就发现了一个致命的缺陷——这个 debian 系统没有 WiFi
的接口(interface)!但是,根据嘉楠的文档,这个开发板是肯定有 WiFi
硬件的。我又马上刷了一遍前者的镜像,进入小核的调试串口。结果我发现:
小核是基于 buildroot 的 linux
小核有 WiFi 接口,并且可以正常连接 WiFi
小核的内存只有 128M
于是我们陷入了一种 dilemma:使用 micropython 镜像,你可以通过 WiFi
ssh 来调试之后接入 PPPoE
的过程,但是之后你就无法使用包管理器,并且手动编译 toolchain 就只能忍受
128M 的内存;反之使用 debian 镜像,你可以比较舒服地进行开发,但调试
PPPoE 的时候就只能抓瞎(因为你没法一边连接有线网络一边调试
PPPoE)。所以我们应该选择哪一个镜像呢?答案是——只有小孩子才做选择。
自己构造系统镜像
根据前面的观察,我们可以排除硬件以及 linux
驱动适配的问题,这就意味着,这个问题肯定是可以通过自己的力量解决的。也就是,我们可以通过恰当地“组装”
micropython 镜像和 debian 镜像来解决这个问题。
至于具体的解决方案,我尝试的路线有以下几点:
原地对这两个镜像进行 hack
尝试修改镜像编译的 SDK 源码,企图得到满足自己需求的镜像
尝试修改镜像编译的 SDK 源码,并对得到的镜像进行 hack
原地 hack
我们可以观察一下这两个镜像的结构:
micropython 镜像:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 > mmls CanMV-K230_sdcard_v1.8_nncase_v2.9.0.img GUID Partition Table (EFI) Offset Sector: 0 Units are in 512-byte sectors Slot Start End Length Description 000: Meta 0000000000 0000000000 0000000001 Safety Table 001: ------- 0000000000 0000020479 0000020480 Unallocated 002: Meta 0000000001 0000000001 0000000001 GPT Header 003: Meta 0000000002 0000000033 0000000032 Partition Table 004: 000 0000020480 0000061439 0000040960 rtt 005: 001 0000061440 0000163839 0000102400 linux 006: ------- 0000163840 0000262143 0000098304 Unallocated 007: 002 0000262144 0000425983 0000163840 rootfs 008: 003 0000425984 0000950271 0000524288 fat32appfs 009: ------- 0000950272 0000950304 0000000033 Unallocated
debian 镜像:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 > mmls CanMV-K230_debian_sdcard_sdk_1.3.img GUID Partition Table (EFI) Offset Sector: 0 Units are in 512-byte sectors Slot Start End Length Description 000: Meta 0000000000 0000000000 0000000001 Safety Table 001: ------- 0000000000 0000020479 0000020480 Unallocated 002: Meta 0000000001 0000000001 0000000001 GPT Header 003: Meta 0000000002 0000000033 0000000032 Partition Table 004: 000 0000020480 0000061439 0000040960 rtt 005: 001 0000061440 0000163839 0000102400 linux 006: ------- 0000163840 0000262143 0000098304 Unallocated 007: 002 0000262144 0003515591 0003253448 rootfs 008: ------- 0003515592 0003515624 0000000033 Unallocated
所以我们可以发现,似乎只有 rootfs 分区大小不同,而 debian 镜像没有
fat32appfs,通过先前的 research
可以得知是用来放炼丹的应用的,这个跟我没有关系,不要也罢,所以也可以看作是
rootfs
的一部分。因此,两个镜像的结构完全相同,可以按照分区为单位来进行替换。
根据先前的判断,在 micropython 镜像中 WiFi 可以正常使用,而 WiFi
作为驱动的一部分,要么是由 linux kernel 加载的,要么是由 dkms 在
/lib/modules
中加载的。保险起见,
我挂载了 micropython 镜像的 rootfs 分区的 /lib/modules
提取出来,写入到 debian 镜像的对应分区,大小不变。
我将 micropython 镜像的 linux 分区原样 copy 到 debian
镜像的对应分区。
然后烧入 TF 卡,启动开发板。dmesg 报错缺少 WiFi 固件,内容有
/etc/firmware/config.txt
,
/etc/firmware/fw_bcm43438a1.bin
和
/etc/firmware/nvram.txt
。我又在 micropython
镜像中找到了对应的路径,拷贝过去,再次重新启动,又报错了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 [ OK ] Started NetworkManager .service - Network Manager . [ 32.925997 ] [dhd] failed to power up DHD generic adapter, 0 retry left [ OK ] Started NetworkManag [ 32.955283 ] [dhd] wifi_platform_set_power = 0 , delay: 0 msec er-dispatcher.�[ 32.961896 ] [dhd] ======== PULL WL_REG_ON (1 ) LOW ! ======== � Manager Sc [ 32.968726 ] [dhd] wifi_platform_bus_enumerate device present 0 ript Dispatcher [ 32.975930 ] [dhd] ======== Card detection to remove SDIO card! ======== Service .[ 32.983935 ] [dhd] failed to power up DHD generic adapter, max retry reached** [ 32.992006 ] [dhd] unregister wifi platform drivers [ 32.996807 ] [dhd] wifi_platform_bus_enumerate device present 0 [ 33.002648 ] [dhd] ======== Card detection to remove SDIO card! ======== [ 33.009272 ] [dhd] dhd_wlan_deinit_gpio: gpio_free(WL_REG_ON 1 ) [ 33.015121 ] [dhd] _dhd_module_init : Failed to load the driver, try cnt 0 [ 33.021848 ] [dhd] _dhd_module_init : Failed to load driver max retry reached** [ 33.028996 ] [dhd] STATIC -MSG ) dhd_static_buf_exit : Enter [ 33.034468 ] [dhd] _dhd_module_init : Exit err=-19 [*** ] Job ifupdown-pre.service/start running (23 s / 3 min 3 s) [ 39.325657 ] [dhd] _dhd_module_init : in Dongle Host Driver , version 101.10 .361 .33 (wlan=r892223-20230607 -2 ) [ 39.325657 ] drivers/net/wireless/bcmdhd compiled on Aug 26 2024 at 15 :28 :32 [ 39.325657 ] [ 39.343823 ] [dhd] STATIC -MSG ) dhd_static_buf_init : 101.10 .361 .31 (wlan=r892223-20230427 -1 ) [ 39.352249 ] [dhd] STATIC -MSG ) dhd_init_wlan_mem : prealloc ok for index 0 : 1100800 (1075 K ) [ 39.360468 ] [dhd] ======== Get GPIO from DTS (android,bcmdhd_wlan) ======== [ 39.367383 ] of_get_named_gpiod_flags: parsed 'gpio_wl_reg_on' property of node '/soc/sdhci0@91580000/bcmdhd_wlan[0]' - status (0 ) [ 39.379060 ] [dhd] dhd_wlan_init_gpio: WL_REG_ON =1 [ 39.383772 ] [dhd] dhd_wifi_platform_load: Enter [ 39.388309 ] [dhd] Power -up adapter 'DHD generic adapter' [ 39.395030 ] dummy_sdmmc: probe of mmc0:0001 :1 failed with error -110 [ 39.401552 ] dummy_sdmmc: probe of mmc0:0001 :2 failed with error -110 [ 39.408008 ] [dhd] wifi_platform_set_power = 1 , delay: 200 msec [ 39.413855 ] [dhd] ======== PULL WL_REG_ON (1 ) HIGH ! ======== [ 39.625906 ] [dhd] wifi_platform_bus_enumerate device present 1 [ *] Job ifupdown-pre.service/start running (25 s / 3 min 3 s) [ 41.661915 ] [dhd] failed to power up DHD generic adapter, 0 retry left [ 41.685982 ] [dhd] wifi_platform_set_power = 0 , delay: 0 msec [ 41.691662 ] [dhd] ======== PULL WL_REG_ON (1 ) LOW ! ======== [ 41.697179 ] [dhd] wifi_platform_bus_enumerate device present 0 [ 41.703022 ] [dhd] ======== Card detection to remove SDIO card! ======== [ 41.709653 ] [dhd] failed to power up DHD generic adapter, max retry reached** [ 41.716795 ] [dhd] unregister wifi platform drivers [ 41.721592 ] [dhd] wifi_platform_bus_enumerate device present 0 [ 41.727435 ] [dhd] ======== Card detection to remove SDIO card! ======== [ 41.734059 ] [dhd] dhd_wlan_deinit_gpio: gpio_free(WL_REG_ON 1 ) [ 41.739903 ] [dhd] _dhd_module_init : Failed to load the driver, try cnt 0 [ 41.746641 ] [dhd] Error creating socket. [ 41.750584 ] [dhd] _dhd_module_init : Failed to load driver max retry reached** [ 41.757732 ] [dhd] STATIC -MSG ) dhd_static_buf_exit : Enter [ OK ] Finished ifupdown-pre.service - He …o synchronize boot up for ifupdown.
上网搜了一下,没有找到合适的解决方案,并且还引发了一个新的问题:我的
debian 的内存也变成了 128M!
于是我又提取 linux 分区中的 dtb 文件,将其反编译为 dts
文件,尝试去修改给 linux 配置的内存大小,然后又编译回去并嵌入到 linux
分区中,重新写入 TF 卡,再次重启——sha256sum 又不对啦!
要继续做下去的话,就要去读镜像的生成源码去理清 sha256
的生成逻辑——既然都要读源码了,那还不如直接从 SDK
重新编译一个!于是,我们来到了下一个方案:
编译 SDK
前文说过,与我的需求相关的有 K230-SDK 和
K230-linux-SDK。我尝试又编译了一遍,结果与官方镜像略微不同:一个可以生成可用
512M 内存,但无法使用 WiFi 的 debian 镜像;另一个可以生成基于 buildroot
的可以使用 WiFi,并且有 512M 内存的镜像。
基于 K230-SDK 生成的 debian
文档链接为:https://developer.canaan-creative.com/k230/dev/zh/03_other/K230_debian_ubuntu%E8%AF%B4%E6%98%8E.html
基于 K230-linux-SDK 生成的 buildroot
的文档链接为:https://developer.canaan-creative.com/k230_linux/dev/zh/01_software/K230_linux_sdk%E6%95%99%E7%A8%8B.html#sdk
显然,这里又有两条路可以选择:
去修改 K230-linux-SDK 中 rootfs 的构建过程,将 rootfs 替换为 debian
镜像。
去修改 K230-SDK 中 linux kernel 的构建过程,将 root 分区替换为支持
WiFi 驱动的状态。
显然,第一条路看上去需要调试的东西更少,事实上也的确如此。我们又可以把这个过程分为以下几个子步骤:
重新构建一个基于 debian 的 rootfs.ext4
找到利用 rootfs.ext4 并生成 buildroot 镜像的代码
手动执行这段代码,传入正确的参数与环境变量,使得生成了镜像使用了
debian 的 rootfs,而不是 linux-SDK 本身的 buildroot
构建 debian.ext4
这一点 K230-SDK 的文档告诉了我们方法,贴一下构建的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 sudo rm -rf debian13 sudo apt-get update sudo apt install qemu-user-static binfmt-support debootstrap debian-ports-archive-keyring systemd-container rsync wget sudo debootstrap --arch =riscv64 unstable debian13 https://mirrors.aliyun.com/debian/ sudo chroot debian13/ echo "root:root" | chpasswdcat >>/etc/network/interfaces <<EOF auto lo iface lo inet loopback auto eth0 iface eth0 inet dhcp EOF apt-get install -y net-tools ntpdate ntpdate ntp.ntsc.ac.cn exit sudo mkfs.ext4 -d debian13 -r 1 -N 0 -m 1 -L "rootfs" -O ^64bit debian13.ext4 1G
但注意不要忘记将之前 K230-linux-SDK 生成的镜像中的
/etc/firmware
与 /lib/modules
文件夹拷贝到
debian13.ext4
中。
找到生成镜像的代码
尝试在 K230-linux-SDK 项目中寻找含有 sysimage-sdcard.img
的字段:
1 2 3 4 5 6 7 8 9 10 11 12 13 > egrep -i --recursive "sysimage-sdcard.img" . ./.github/workflows/build.yml: rm -rf output/${CONF} /images/sysimage-sdcard.img ./.gitlab-ci.yml: - rm -rf output/${CONF} /images/sysimage-sdcard.img ./.gitlab-ci.yml: sudo cp -rf --sparse=always -L ${src_file} ${DST_DIR} /${SUB_DIR} /sysimage-sdcard.img.gz; ./.gitlab-ci.yml: sysimage_md5=$(md5sum ${DST_DIR} /${SUB_DIR} /sysimage-sdcard.img.gz | awk '{print $1}' ); ./.gitlab-ci.yml: echo "sysimage_path=${DST_DIR} /${SUB_DIR} /sysimage-sdcard.img.gz" >> $CI_PROJECT_DIR /build.env; ./.gitlab-ci.yml: - echo "sysimage-sdcard.img.gz md5 ${sysimage_md5} " ./README.md:output/k230d_canmv_defconfig/images/sysimage-sdcard.img.gz ./buildroot-overlay/board/canaan/k230-soc/genimage.cfg:image sysimage-sdcard.img { ./buildroot-overlay/board/canaan/k230-soc/post-image.sh: local image_name="$2 " ; ./buildroot-overlay/board/canaan/k230-soc/post-image.sh:gen_image ${GENIMAGE_CFG_SD} sysimage-sdcard.img ./buildroot-overlay/boot/uboot/u-boot-2022.10-overlay/include/configs/k230_evb.h: "upsdimg=usb start; dhcp; tftp 0x9000000 10.10.1.94:wjx/sysimage-sdcard.img.gz;gzwrite mmc 1 0x$fileaddr 0x$filesize ; \0" \ ......
可以发现,./buildroot-overlay/board/canaan/k230-soc/post-image.sh
比较符合我们的需求,打开文件一看:
1 2 3 4 5 6 7 8 9 10 11 > tail -n 10 ./buildroot-overlay/board/canaan/k230-soc/post-image.sh ${UBOOT_BUILD_DIR} /tools/mkimage -A riscv -O linux -T kernel -C none -a 0 -e 0 -n linux -d ${BINARIES_DIR} /fw_jump.bin boot/fw_jump_add_uboot_head.bin rm -rf boot.ext4 ;fakeroot mkfs.ext4 -d boot -r 1 -N 0 -m 1 -L "boot" -O ^64bit boot.ext4 45M } gen_uboot_bin gen_env_bin gen_boot_ext4 gen_image ${GENIMAGE_CFG_SD} sysimage-sdcard.img
顾名思义,那应该就是最终生成镜像的代码了。
手动执行这段代码
当你阅读以下这个代码:
代码篇幅还是太长了,想看可以去仓库链接
你会感觉整个人都不好了,首先这段代码的逻辑还是比较复杂的。细心看呢也没必要(毕竟我们只是想要将自己的
debian.ext4 替换原先的
rootfs.ext4);直接运行呢又对某些参数和环境变量有依赖,脚本会果断报错。于是,这里只能进行手动插桩,具体修改为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 #!/bin/bash set -eecho "###########################################################################################" echo "Command: $0 " echo "All Parameters: $@ " printenv echo "###########################################################################################" DTB="k230-canmv.dtb" LINUX_DIR=${BUILD_DIR} /linux-6.6.22 rootfs_ext4_file="" [ $# -ge 2 ] && DTB="$2 .dtb" [ $# -ge 3 ] && LINUX_DIR="$3 " [ $# -ge 4 ] && rootfs_ext4_file="$4 " echo "###########################################################################################" echo "${DTB} , ${rootfs_ext4_file} " echo "###########################################################################################" UBOOT_BUILD_DIR=${BUILD_DIR} /uboot-2022.10 K230_SDK_ROOT=$(dirname $(dirname ${BASE_DIR} )) GENIMAGE_CFG_SD=$(dirname $(realpath "$0 " ))/genimage.cfg env_dir=$(dirname $(realpath "$0 " ))
然后我们重新运行一遍顶层的 Makefile,我们会得到类似这样的结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 ########################################################################################### Command: board/canaan/k230-soc/post-image.sh All Parameters: /home/junyu33/Desktop/github/k230_linux_sdk/output/k230_canmv_defconfig/images k230-canmv /home/junyu33/Desktop/github/k230_linux_sdk/output/k230_canmv_defconfig/build/linux-3 c3f4061b727e6d0e2293357a7475b578d688d92 SHELL=/bin/bash LSCOLORS=Gxfxcxdxbxegedabagacad BR2_CONFIG=/home/junyu33/Desktop/github/k230_linux_sdk/output/k230_canmv_defconfig/.config SESSION_MANAGER=local/zjy:@/tmp/.ICE-unix/2277 ,unix/zjy:/tmp/.ICE-unix/2277 WINDOWID=121634819 QT_ACCESSIBILITY=1 COLORTERM=truecolor XDG_CONFIG_DIRS=/etc/xdg/xdg-xfce:/etc/xdg PERL=/usr/bin/perl LESS=-R XDG_SESSION_PATH=/org/freedesktop/DisplayManager/Session0 XDG_MENU_PREFIX=xfce- TERM_PROGRAM_VERSION=3.4 GTK_IM_MODULE=fcitx CONDA_EXE=/home/junyu33/anaconda3/bin/conda _CE_M= TMUX=/tmp/tmux-1000 /default,50921 ,1 LANGUAGE=en_US:en ...... HG=hg CONFIG_SHELL=/bin/bash LC_NUMERIC=en_US.UTF-8 HOSTCXX_NOCCACHE=/usr/lib/ccache/g++ OLDPWD=/home/junyu33/Desktop/github/k230_linux_sdk/buildroot-overlay TERM_PROGRAM=tmux _=/usr/bin/printenv ###########################################################################################
我们可以看到传入参数有三个:images 路径、DTB文件名称和 linux kernel
源码路径。稍微看一下源码就知道第四个参数是 rootfs.ext4 的文件路径。
环境变量这边,先把所有的环境变量拿出来,保存为A;再以不运行脚本跑一次printenv
,保存为B。把A、B的内容
sort一下,再 diff
一下,就能很清楚看到这个脚本引入了哪些新的环境变量。
最终,我们就可以写出类似的命令(使用 root 用户运行):
ACLOCAL_PATH=/home/junyu33/Desktop/github/k230_linux_sdk/output/k230_canmv_defconfig/host/riscv64-buildroot-linux-gnu/sysroot/usr/share/aclocal:/home/junyu33/Desktop/github/k230_linux_sdk/output/k230_canmv_defconfig/host/share/aclocal BINARIES_DIR=/home/junyu33/Desktop/github/k230_linux_sdk/output/k230_canmv_defconfig/images BASE_DIR=/home/junyu33/Desktop/github/k230_linux_sdk/output/k230_canmv_defconfig BR2_CONFIG=/home/junyu33/Desktop/github/k230_linux_sdk/output/k230_canmv_defconfig/.config BR2_DL_DIR=/home/junyu33/Desktop/github/k230_linux_sdk/output/buildroot-2024.02.1/../../dl BR2_VERSION=2024.02.1 BR2_VERSION_FULL=-g8d50485-dirty BR_COMPILER_PARANOID_UNSAFE_PATH=enabled BUILD_DIR=/home/junyu33/Desktop/github/k230_linux_sdk/output/k230_canmv_defconfig/build BUILDROOT_CONFIG=/tmp/deprecated/The-BUILDROOT_CONFIG-environment-variable-was-renamed-to-BR2_CONFIG BZR=bzr ./buildroot-overlay/board/canaan/k230-soc/post-image.sh /home/junyu33/Desktop/github/k230_linux_sdk/output/k230_canmv_defconfig/images k230-canmv /home/junyu33/Desktop/github/k230_linux_sdk/output/k230_canmv_defconfig/build/linux-3c3f4061b727e6d0e2293357a7475b578d688d92 /home/junyu33/Desktop/tmp/debian13.ext4
把生成的镜像写入 TF 卡,启动开发板,这次开发板既能运行
debian,也能使用 WiFi,甚至还有 512M 的内存,看上去非常完美!
但实际上,故事还没有结束。
测试拨号
然后我尝试使用 nmcli 进行拨号,然而 nmcli 又报错了:
1 2 3 4 5 root@zjy:/etc/NetworkManager/system-connections ** (generate:2357): WARNING **: 03:00:44.109: Permissions for /etc/netplan/01-netcfg.yaml are too open. Netplan configuration should NOT be accessible by others. /etc/netplan/01-netcfg.yaml:8:3: Error in network definition: unknown key 'pppoe' pppoe:
上网一搜,又没有搜到相似的问题,于是我从较低 level 的工具开始
debug,比如测试 ppp 能否正常工作:
1 2 3 junyu33@zjy:~$ sudo pon Couldn't open the /dev/ppp device: No such device or address /usr/sbin/pppd: Please load the ppp_generic kernel module.
看来又得折腾 linux kernel 了,这里又有两条路可以选择:
原地编译 ppp/pppoe 模块,尝试 insmod 进去。
修改内核配置,重新编译整个 linux kernel。
原地编译模块
我又恶补了一下 linux kernel 编译的知识,kernel.org 有写:
The command to build an external module is:
1 $ make -C <path_to_kernel_dir> M=$PWD
The kbuild system knows that an external module is being built due to
the "M=<dir>" option given in the command.
于是我如法炮制,我需要的 ppp 模块在 drivers/net/ppp
中,于是在开发板有以下编译命令:
1 make -C /home/junyu33/linux-3c3f4061b727e6d0e2293357a7475b578d688d92/ M=$PWD
然而,它又报错了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 /home/ junyu33/linux-3c3f4061b727e6d0e2293357a7475b578d688d92/M akefile:1325 : warning: overriding recipe for target 'vdso_install' arch/riscv/M akefile:144 : warning: ignoring old recipe for target 'vdso_install' CALL scripts/checksyscalls.sh LDS arch/riscv/ kernel/vdso/ vdso.lds VDSO32AS arch/riscv/ kernel/vdso/ rt_sigreturn-32 .o VDSO32AS arch/riscv/ kernel/vdso/g etcpu-32 .o VDSO32AS arch/riscv/ kernel/vdso/ flush_icache-32 .o VDSO32AS arch/riscv/ kernel/vdso/ sys_hwprobe-32 .o VDSO32AS arch/riscv/ kernel/vdso/ note-32 .o VDSO32CC arch/riscv/ kernel/vdso/ hwprobe-32 .o VDSO32LD arch/riscv/ kernel/vdso/ vdso32.so.dbg OBJCOPY arch/riscv/ kernel/vdso/ vdso32.so VDSO32SYM include /generated/ vdso32-offsets.h LDS arch/riscv/ kernel/vdso/ vdso.lds VDSO64AS arch/riscv/ kernel/vdso/ rt_sigreturn-64 .o VDSO64AS arch/riscv/ kernel/vdso/g etcpu-64 .o VDSO64AS arch/riscv/ kernel/vdso/ flush_icache-64 .o VDSO64AS arch/riscv/ kernel/vdso/ sys_hwprobe-64 .o VDSO64AS arch/riscv/ kernel/vdso/ note-64 .o VDSO64CC arch/riscv/ kernel/vdso/ vgettimeofday-64 .o VDSO64CC arch/riscv/ kernel/vdso/ hwprobe-64 .o VDSO64LD arch/riscv/ kernel/vdso/ vdso64.so.dbg OBJCOPY arch/riscv/ kernel/vdso/ vdso64.so VDSO64SYM include /generated/ vdso64-offsets.h MODPOST Module.symvers ERROR: modpost: "slhc_free" [drivers/net/ ppp/ppp_generic.ko] undefined! ERROR: modpost: "slhc_uncompress" [drivers/net/ ppp/ppp_generic.ko] undefined! ERROR: modpost: "slhc_toss" [drivers/net/ ppp/ppp_generic.ko] undefined! ERROR: modpost: "slhc_remember" [drivers/net/ ppp/ppp_generic.ko] undefined! ERROR: modpost: "slhc_compress" [drivers/net/ ppp/ppp_generic.ko] undefined! ERROR: modpost: "slhc_init" [drivers/net/ ppp/ppp_generic.ko] undefined! make[2 ]: *** [scripts/Makefile.modpost:145 : Module.symvers] Error 1 make[1 ]: *** [/home/ junyu33/linux-3c3f4061b727e6d0e2293357a7475b578d688d92/M akefile:1903 : single_modules] Error 2 make: *** [Makefile:234 : __sub-make] Error 2
我尝试原地编译和在主机上交叉编译,编译这个路径和全部路径,都出现了这个错误(或者其它更多的错误)。通过
LLM,我得知这是因为 ppp 的依赖 slhc 也没有编译进内核或成为模块,从而导致
ppp 编译失败。
我并没有又去寻找 slhc 在哪个位置,因为我担心编译 slhc
时又冒出它又依赖某某模块,于是我觉得选择第二条道路。
编译内核
最后,我还是来到了这操蛋的一步,我又面临了一系列的问题:
应当修改哪些参数?
应当使用什么编译命令,编译的产物是什么?
应当将产物放在 K230-linux-SDK 的什么位置?
修改参数
既然我们要启用 ppp_generic 功能,那根据 drivers/net/ppp
的 Makefile:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 obj-$(CONFIG_PPP) += ppp_generic.o obj-$(CONFIG_PPP_ASYNC) += ppp_async.o obj-$(CONFIG_PPP_BSDCOMP) += bsd_comp.o obj-$(CONFIG_PPP_DEFLATE) += ppp_deflate.o obj-$(CONFIG_PPP_MPPE) += ppp_mppe.o obj-$(CONFIG_PPP_SYNC_TTY) += ppp_synctty.o obj-$(CONFIG_PPPOE) += pppox.o pppoe.o obj-$(CONFIG_PPPOL2TP) += pppox.o obj-$(CONFIG_PPTP) += pppox.o pptp.o
那当然是启用 CONFIG_PPP=y
啦。
其实,为了保险,我其实把这里提到的功能全都启用了。
编译生成镜像
然后,我们得了解 linux kernel 是从哪个地方读取这些 config
的。通过相关资料的查阅,linux kernel 是从 arch/riscv/config
读取相关开发板配置的。对于 CanMV-K230 开发板,读取的文件就是
arch/riscv/config/k230_canmv_defconfig
。
另外,我想到了一个 trick 用于绕过第二个和第三个问题,原因是我在遍历
K230-linux-SDK 的文件时意外发现了在某个 linux 目录有两个
patch,其中一个内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 > cat 0003-driver-net-r8152-use-chip-ID-as-MAC-addr.patch From 588af5417c9b1fcc8e9d6d48b996656096d4c322 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E5=AD=90=E6=87=BF?= <huangziyi@canaan-creative.com> Date: Fri, 13 Sep 2024 14:57:10 +0800 Subject: [PATCH] driver: net: r8152 use chip ID as MAC addr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 黄子懿 <huangziyi@canaan-creative.com> --- drivers/net/usb/r8152.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 127b34dcc5b3..65bcef61b1ec 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -1808,8 +1808,17 @@ static int determine_ethernet_addr(struct r8152 *tp, struct sockaddr *sa) } else if (!is_valid_ether_addr(sa->sa_data)) { netif_err(tp, probe, dev, "Invalid ether addr %pM\n" , sa->sa_data); - eth_hw_addr_random(dev); - ether_addr_copy(sa->sa_data, dev->dev_addr); + void __iomem *trng_addr = ioremap(0x91213300, 0x100); + unsigned int trng_data = readl(trng_addr); + iounmap(trng_addr); + char mac_addr_hex[6] = { + 0x00, 0xe0, 0x4c, + trng_data & 0xff, + (trng_data>>8) & 0xff, + (trng_data>>16) & 0xff + }; + // eth_hw_addr_random(dev); + ether_addr_copy(sa->sa_data, mac_addr_hex); netif_info(tp, probe, dev, "Random ether addr %pM\n" , sa->sa_data); return 0; -- 2.46.0
LLM 问了一下,它告诉我这是 git patch 格式,可以通过
git format-patch -1 <commit-hash>
来生成,于是我将
linux 单独拷贝了一份,也建了一个 git 仓库,并修改了
arch/riscv/config/k230_canmv_defconfig
,加入了那几个有关于
PPP 的配置,然后 git format-patch -1
跑一波,结果如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 > cat 0002-add-ppp-for-canmv-k230.patch From 5613ac073bf8d9fcc140542458cb3d05c43228a0 Mon Sep 17 00:00:00 2001 From: junyu33 <2658799217@qq.com> Date: Wed, 6 Nov 2024 19:07:02 +0800 Subject: [PATCH] add ppp for canmv k230 --- arch /riscv/configs/k230_defconfig | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/arch/riscv/configs/k230_defconfig b/arch/riscv/configs/k230_defconfig index 6e579f78c..f4c993f12 100644 --- a/arch/riscv/configs/k230_defconfig +++ b/arch/riscv/configs/k230_defconfig @@ -303,3 +303,14 @@ CONFIG_CFG80211_WEXT=y CONFIG_MAC80211=y CONFIG_MEDIA_USB_SUPPORT=y CONFIG_USB_VIDEO_CLASS=y + +CONFIG_PPP=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_MPPE=y +CONFIG_PPP_MULTILINK=y +CONFIG_PPPOE=y +CONFIG_PPPOE_HASH_BITS=4 +CONFIG_PPP_ASYNC=y +CONFIG_PPP_SYNC_TTY=y -- 2.43.0
感觉还挺像的,于是我将其命名为
0002-add-ppp-for-canmv-k230.patch
,并和其它 patch
保存在一个路径中。然后把 K230-linux-SDK 下载的 linux
删掉,重新跑一遍项目顶层的 Makefile,生成了镜像。
再次 hack 镜像
当然,毕竟之前在 debian 的 rootfs
做了那么多工作,我是不太想把系统“恢复出厂设置的”。于是,我再一次提取了
buildroot 镜像的 linux 分区,并覆盖了 debian
镜像的对应分区,尝试启动。
使用 zcat
的结果如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 junyu33@zjy:~$ zcat /proc/config.gz | grep CONFIG_PPP CONFIG_PPP=y CONFIG_PPP_BSDCOMP=y CONFIG_PPP_DEFLATE=y CONFIG_PPP_FILTER=y CONFIG_PPP_MPPE=y CONFIG_PPP_MULTILINK=y CONFIG_PPPOE=y CONFIG_PPPOE_HASH_BITS_4=y CONFIG_PPPOE_HASH_BITS=4 CONFIG_PPP_ASYNC=y CONFIG_PPP_SYNC_TTY=y
这证明我们之前对 linux 分区的修改是有效的.
pppd
也可以正常运行:
1 2 3 junyu33@zjy:~$ sudo pppd --version [sudo] password for junyu33: pppd version 2.5.0
没有出现任何问题,看来这种 hack 是真的挺好用的。
用户端调试
通过以上层面的调试,我们在驱动层面解决了 PPPoE
无法使用的问题,现在的问题只剩下用户配置了,难度降低了很多,并且接下来的步骤都是一本道,没什么有很多种路线可以选择的情况了。
既然 NetworkManager 已经装好了,那么我们直接敲对应的命令:
1 2 sudo nmcli connection add type pppoe ifname enx00e04ca7c468 con-name mypppoe username "<username>" password "<password>" sudo nmcli connection up mypppoe
嗯,连接还是失败了,然后看了一眼 ifconfig
,发现自己的
enx00e04ca7c468
并没有 ipv4
地址。于是,我在连接命令前加了一句 DHCP。
1 2 3 sudo dhclient enx00e04ca7c468 sudo nmcli connection add type pppoe ifname enx00e04ca7c468 con-name mypppoe username "<username>" password "<password>" sudo nmcli connection up mypppoe
然后连接没有报错,再尝试用这个 ppp 接口去测试 ping,结果如下:
1 2 3 4 5 6 7 junyu33@zjy:~$ sudo ping -I ppp0 8.8.8.8 PING 8.8.8.8 (8.8.8.8) from 220.167.40.175 ppp0: 56(84) bytes of data. 64 bytes from 8.8.8.8: icmp_seq=1 ttl=56 time=33.2 ms 64 bytes from 8.8.8.8: icmp_seq=2 ttl=56 time=33.4 ms 64 bytes from 8.8.8.8: icmp_seq=3 ttl=56 time=33.4 ms 64 bytes from 8.8.8.8: icmp_seq=4 ttl=56 time=33.0 ms 64 bytes from 8.8.8.8: icmp_seq=5 ttl=56 time=33.4 ms
拨号的问题总算是完全解决了。
测试 ddns
先前我用于 ddns 的脚本已经上传到 github 。我在开发板中将其
clone 下来,并写好配置文件,然后脚本一跑,告诉我没有装
curl
。我在想 curl
难道不是很基本的工具吗,居然这都没有。
然后是 python 的包依赖问题,因为 python3.12 限制在系统环境中使用 pip
安装 package。而我并没有闲心在这个开发板中安装 anaconda 或者
virtualenv,并且这个项目的 python 依赖只有
requests
,于是一行搞定:
1 sudo apt install python3-requests
然后启动脚本,没有报错,过了几分钟我就可以从主机 ssh
我的域名到开发板了。
测试 ssh 并持久化
现在到了最重要也最关键的一步:因为学校寝室晚上会断电,因此我需要让其断电之后,在第二天早上六点来电之时自动恢复
ddns 服务。具体而言,我们需要实现以下几点:
开机启动 debian。
开机自动拨号。
开机自动 ddns。
使开发板脱离电脑运行。
开机启动 debian
这个不难,开机进一下 uboot,把等待时间从 3 改成 0 即可。
1 2 setenv bootdelay 0 saveenv
这样做的后果是我再也不能进入 uboot
了,但其实无所谓。真要想改,重新刷一遍 linux 分区即可。
开机自动拨号
写一个 systemd 服务:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 junyu33@zjy:~$ sudo cat /etc/systemd/system/pppoe-connection.service [sudo] password for junyu33: [Unit] Description=Start PPPoE Connection mypppoe After=network.target [Service] Type=oneshot ExecStartPre=dhclient enx00e04ca7c468 ExecStart=/usr/bin/nmcli connection up mypppoe RemainAfterExit=yes [Install] WantedBy=multi-user.target
重启一下,发现 nmcli 没有权限拨号,于是将用户改成以 root 运行。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 junyu33@zjy:~$ sudo cat /etc/systemd/system/pppoe-connection.service [sudo] password for junyu33: [Unit] Description=Start PPPoE Connection mypppoe After=network.target [Service] User=root Type=oneshot ExecStartPre=dhclient enx00e04ca7c468 ExecStart=/usr/bin/nmcli connection up mypppoe RemainAfterExit=yes [Install] WantedBy=multi-user.target
然后重启拨号就正常了。
开机自动ddns
因为 IP
可能会改变,首先保证开机一定更新一次,每半个小时更新一次:
1 2 3 4 5 6 7 8 9 10 11 junyu33@zjy:~$ sudo cat /etc/systemd/system/ddns-update.timer [Unit] Description=Run DDNS update script every 30 minutes [Timer] OnBootSec=5min OnUnitActiveSec=30min Persistent=true [Install] WantedBy=timers.target
然后写出具体的 service 内容,这里需要注意:
不能挂代理,否则获取公网 IP 就跑到代理那边去了
写的脚本不兼容 sh 语法,所以必须用 bash
运行
脚本中间有些地方用了相对路径,因此必须制定 PWD
1 2 3 4 5 6 7 8 9 junyu33@zjy:~$ sudo cat /etc/systemd/system/ddns-update.service [Unit] Description=Run DDNS update script [Service] Type=oneshot WorkingDirectory=/home/junyu33/netlify-dynamic-dns-py ExecStartPre=/usr/bin/env http_proxy= https_proxy= ExecStart=/bin/bash /home/junyu33/netlify-dynamic-dns-py/ddns.sh
开发板脱离电脑运行
这个是唯一个比较抓瞎的过程,因为我的电源适配器比较紧缺,于是选了一个很久没用的。结果刚好那个适配器就可能有问题,导致虽然我的电源指示灯是亮的,但是
debian 一直无法启动,也就导致我在主机这边等了半天也没 ssh 上。
然后我又把开发板接回电脑,再一次
ssh,又成功了,因此排除开发板系统问题。
然后又换了我充耳机的电源适配器,成功了,因此确定是我之前用的旧适配器的问题。
接着,我便把电源线和网线,接到了去北京实习的室友空闲不用的 USB
充电插座和宽带接口上,又成功了。此时已经快到熄灯的时间,我便索性睡一觉,看看第二天能不能通过电脑
ssh 到自己的开发板和工位电脑。
第二天起床,我马上打开自己电脑试了一下,一切正常,于是:
Congratulations,我终于再次实现了“居家办公”的美好生活!
踩坑总结
好货不便宜,便宜无好货。
网购要看差评,不要看哪个买的人多就买哪个。
一定要理清自己在做什么,否则很容易 lost in the woods。
摆脱学生思维,不要为了学某个东西而去学某个东西,这样效率很低。