您尚未登录。

楼主 #1 2020-11-21 21:23:35

libc0607
会员
注册时间: 2018-12-13
已发帖子: 24
积分: 47.5

关于联盛德W600 Wi-Fi部分的一点探索:自由通信接口、2.2G~2.8G中心频率、5/10MHz传输带宽

注1:这些内容同时发在了 Github 上, https://github.com/libc0607/w60x-rf-hacking 
注2:内容仅供学习,请遵守当地无线电法规,调试请上衰减器,搞事和楼主无关
注3:超出芯片设计工作范围外可能会造成损坏,和楼主无关

0. 简介
W600 是个对标 ESP8266 的 Wi-Fi 芯片, 晕哥早先的贴子里有介绍 https://whycan.com/t_1928.html
楼主通过逆向 SDK 中的 libwlan,得以扩展了一下它的中心频率
这里记录一下整个过程,万一有人用得上。。

2312

1. 关于中心频率
W600 的 SDK 仅有 libwlan 没有开源,但是保留了符号。
首先用 7z 解压,其中的 1.txt 记录了每个 .o 文件中对外提供的函数接口,如图

7z

list

通过搜索channel等关键词,觉得tls_wl_rf.o中应该有比较有趣的东西
载入IDA Pro,看到函数列表

ida

wm_rf_set_channel很是显眼,反编译出如下

int *__fastcall wm_rf_set_channel(int a1, unsigned int a2)
{
  unsigned int v2; // r4
  int v3; // r5
  int v4; // r0
  int v5; // r1
  unsigned int v6; // r0
  int v7; // r6
  int v8; // r0
  int *result; // r0

  v2 = a2;
  v3 = a1;
  if ( a2 <= 1 )
  {
    rf_spi_write(rf_chan24g_20m[2 * a1]);
    rf_spi_write(rf_chan24g_20m[2 * v3 + 1]);
    v4 = wm_rf_band_switch(0);
    v5 = tls_os_set_critical(v4);
    v6 = MEMORY[0x40001400] & 0xFFFFFFDF;
LABEL_8:
    MEMORY[0x40001400] = v6;
    tls_os_release_critical(v5);
    goto LABEL_9;
  }
  if ( a2 <= 3 )
  {
    if ( a2 == 2 )
      v7 = central_freq[2 * a1];
    else
      v7 = central_freq[2 * a1 + 1];
    rf_spi_write(rf_chan24g_20m[2 * v7]);
    rf_spi_write(rf_chan24g_20m[2 * v7 + 1]);
    v8 = wm_rf_band_switch(1);
    v5 = tls_os_set_critical(v8);
    if ( v2 == 2 )
      v6 = MEMORY[0x40001400] & 0xFFFEFF3F | 0xA0;
    else
      v6 = MEMORY[0x40001400] & 0xFFFFFF3F | 0x100E0;
    goto LABEL_8;
  }
LABEL_9:
  result = &hed_rf_current_channel;
  hed_rf_current_channel = v3;
  *(_DWORD *)&hed_rf_chan_type = v2;
  return result;
}

这里明显调用了一个 rf_spi_write()

int __fastcall rf_spi_write(int a1)
{
  MEMORY[0x40011408] = a1 << 10;
  tls_wl_delay(1);
  MEMORY[0x40011400] = 1;
  while ( MEMORY[0x40011404] & 0x40000 )
    ;
  return tls_wl_delay(1);
}
int __fastcall rf_spi_read(int a1)
{
  MEMORY[0x40011408] = (a1 << 27) | 0x4000000;
  tls_wl_delay(10);
  MEMORY[0x40011400] = 1;
  while ( MEMORY[0x40011404] & 0x40000 )
    ;
  tls_wl_delay(200);
  return MEMORY[0x4001140C] >> 16;
}

看到这里直接操作了寄存器,查找手册中的寄存器分布

reg1

reg2

可以猜测,他们在Wi-Fi部分使用的频率合成器是通过SPI接口控制的,他们在APB上挂了一个简易的SPI控制器用来控制频率合成器
根据读写函数,容易猜测该简易SPI控制器的寄存器 MEMORY[0x40011408] 的结构为

5'b<addr> + 1'b<read/write> + 16'b<data> + 10'b <unknown/padding>

那接下来的方向就是找出他们往频率合成器中写了什么数据
wm_rf_set_channel 这个函数中涉及了两个表:rf_chan24g_20m[] 与 central_freq[]

.data:000009B4                 EXPORT rf_chan24g_20m
.data:000009B4 ; _DWORD rf_chan24g_20m[30]
.data:000009B4 rf_chan24g_20m  DCD 0, 0, 0x2A203, 0x43333, 0x2A204, 0x48888, 0x2A205
.data:000009B4                                         ; DATA XREF: wm_rf_set_channel+4↑o
.data:000009B4                                         ; wm_rf_set_channel:loc_1BA↑o ...
.data:000009B4                 DCD 0x4DDDD, 0x2A207, 0x43333, 0x2A208, 0x48888, 0x2A209
.data:000009B4                 DCD 0x4DDDD, 0x2A20B, 0x43333, 0x2A20C, 0x48888, 0x2A20D
.data:000009B4                 DCD 0x4DDDD, 0x2A20F, 0x43333, 0x2A600, 0x48888, 0x2A601
.data:000009B4                 DCD 0x4DDDD, 0x2A603, 0x43333, 0x2A606, 0x46666
.constdata:000008BC                 EXPORT central_freq
.constdata:000008BC ; _DWORD central_freq[30]
.constdata:000008BC central_freq    DCD 0, 0, 3, 3, 4, 4, 1, 5, 2, 6, 3, 7, 4, 8, 5, 9, 6
.constdata:000008BC                                         ; DATA XREF: wm_rf_set_channel+3C↑o
.constdata:000008BC                                         ; wm_rf_init:off_438↑o ...
.constdata:000008BC                 DCD 0xA, 7, 0xB, 8, 0xC, 9, 0xD, 0xA, 0xA, 0xB, 0xB, 0 ; Alternative name is 'BuildAttributes$$THM_ISAv4$P$D$K$B$S$PE$A:L22UL41UL21$X:L11$S22US41US21$IEEE1$IW$USESV6$~STKCKD$USESV7$~SHL$OSPACE$EBA8$REQ8$PRES8$EABIv2'
.constdata:000008BC                 DCD 0
.constdata:000008BC ; .constdata    ends
.constdata:000008BC

这种 0x3333, 0x8888, 0xDDDD 的感觉很像是频率合成器的小数部分,而central_freq这个一看就明白了是给ht40-和ht40+用的。。
这样 wm_rf_set_channel 的两个参数就容易明白了,分别为频道与带宽模式
结合前面猜出的结构,整理往 rf synth 中某个寄存器可能写入的数据如下:

const uint32_t rf_chan24g_20m[] = {
	
//	<reg:0x1>	<reg:0x2>	chan 	freq	reg			    int		frac
	0x2A203, 	0x43333, //1		  2412	0xA2033333	40		0x33333
	0x2A204, 	0x48888, // 2		  2417	0xA2048888	40		0x48888
	0x2A205, 	0x4DDDD, // 3		  2422	0xA205DDDD	40		0x5DDDD
	0x2A207, 	0x43333, // 4		  2427	0xA2073333	40		0x73333
	0x2A208, 	0x48888, // 5		  2432	0xA2088888	40		0x88888
	0x2A209, 	0x4DDDD, // 6		  2437	0xA209DDDD	40		0x9DDDD
	0x2A20B, 	0x43333, // 7		  2442	0xA20B3333	40		0xB3333
	0x2A20C, 	0x48888, // 8		  2447	0xA20C8888	40		0xC8888
	0x2A20D, 	0x4DDDD, // 9		  2452	0xA20DDDDD	40		0xDDDDD
	0x2A20F, 	0x43333, // 10		2457	0xA20F3333	40		0xF3333
	0x2A600, 	0x48888, // 11		2462	0xA6008888	41		0x08888
	0x2A601, 	0x4DDDD, // 12		2467	0xA601DDDD	41		0x1DDDD
	0x2A603, 	0x43333, // 13		2472	0xA6033333	41		0x33333
	0x2A606, 	0x46666, // 14		2484	0xA6066666	41		0x66666
}

这里的推导过程省略,主要是观察到
1.在2457-2462之间发生了进位
2. 在1-10频道中每次增加的小数分频值代表5MHz
最终得出 W60x 的频率合成器计算公式为

F = 60 MHz * (int + frac/0xFFFFF)

并且该寄存器的结构为

6'b<int> + 6'b<unknown???> + 20'b<frac>

(楼主有个想法,新出的那个 W800 如果用的也是相同的 IPCore……

最后作为老缝合怪,可以在 arduino 环境中糊出一堆勉强能用的测试代码
在我的这块 TB-01 开发板上,频率范围在 2161MHz~2931MHz 之间调节时,频谱都没有出现明显不对劲(PLL锁上了大概
但射频性能在 Wi-Fi 频段以外会明显劣化,故不建议使用偏移过远的中心频率

// Notice that 'extern "C"' 
extern "C" {
  #include <wm_wifi.h>
  #include <wm_osal.h>
}

void _rf_spi_w(int arg)
{
  *((uint32_t*)0x40011408) = arg << 10;    
  delayMicroseconds(1);
  *((uint32_t*)0x40011400) = 1;
  while(*((uint32_t*)0x40011404) & 0x40000);
  delayMicroseconds(1);
  return;
}

void w60x_set_center_frequency_20mbw(uint32_t freq_mhz) 
{
  uint32_t spi_reg1, spi_reg2, reg_synth;
  uint32_t chan_div_int, chan_div_frac;
  uint32_t cpu_sr;
  
  chan_div_int = 0x0000003F & (freq_mhz/60);
  chan_div_frac = 0x000FFFFF & ( ((freq_mhz-(chan_div_int*60)) * (0xFFFFF)) / 60 );
  
  reg_synth = 0x02000000 | (chan_div_int << 26) | (chan_div_frac);
  spi_reg1 = 0x00020000 | (reg_synth >> 16);
  spi_reg2 = 0x00040000 | (reg_synth & 0x0000FFFF);
  
  _rf_spi_w(spi_reg1);
  _rf_spi_w(spi_reg2);

  // wm_rf_band_switch @20MHz BW
  _rf_spi_w(0x102640);  //write(0x8, 0x2640)
  _rf_spi_w(0x146967);  //write(0xA, 0x6967)
  _rf_spi_w(0x102641);  //write(0x8, 0x2641)
  delayMicroseconds(180);
  _rf_spi_w(0x102740);  //write(0x8, 0x2740)
  _rf_spi_w(0x145327);  //write(0xA, 0x5327)
  _rf_spi_w(0x102741);  //write(0x8, 0x2741)
  delayMicroseconds(180);
  _rf_spi_w(0x1027C1);  //write(0x8, 0x27C1)
  _rf_spi_w(0x10CDC0);  //write(0x8, 0xCDC0)
  // end of wm_rf_band_switch @20MHz BW

  // I don't know what's 0x40001400 controls
  cpu_sr  = tls_os_set_critical();
  *((uint32_t*)0x40001400) = *((uint32_t*)0x40001400) & 0xFFFFFFDF;
  tls_os_release_critical(cpu_sr);  

  return;
}

2. 关于频宽
W60X 传输时占用的频宽可以通过调节 WLAN 系统根时钟分频系数来改变。
蛋疼的事是APB时钟又从这个时钟分频而来,改变这里的时钟会导致APB下面挂的所有设备跟着改变;
即,假如写了 Serial.begin(230400); 又写了 w60x_set_wlan_channel_bw(10); 那串口实际只有 115200。

关于更改时钟分频系数的部分,寄存器手册里说得比较清楚;
直接上代码,可以实现 5/10/20MHz 传输带宽:

// usable bw_mhz: 20(default), 10, 5
// note1: this func assume cpu is running at 80MHz
// note2: this func affect all devices' clock under APB
// (e.g. set channel bw to 10MHz & set UART to 115200 ==> you'll get a 57600 UART)
void w60x_set_wlan_channel_bw(uint32_t bw_mhz)
{
  uint32_t reg, clk_mhz;
  uint8_t wlan_div, bus2_factor; 
  
  reg = *((uint32_t*)0x40000710);
  clk_mhz = bw_mhz * 8;
  
  switch(clk_mhz) {
  case 80:
    wlan_div = 2;
    bus2_factor = 4;
  break;
  case 40:
    wlan_div = 4;
    bus2_factor = 8;
  break;
  default:  // 160mhz
    wlan_div = 1;
    bus2_factor = 2;
  break;
  }
  
  reg &= ~(0x00000FF0);
  reg |= (wlan_div <<4);
  reg |= (bus2_factor <<8);

  *((uint32_t*)0x40000710) = reg;
  delayMicroseconds(1);
  *((uint32_t*)0x40000710) = reg | 0x80000000;
  delayMicroseconds(1);
  
  return;
}

3.自由通信接口 & 一个测试 Demo

官方给了个文档叫  《WM_WiFi_自由通信接口使用指导》,参考这个接口糊了一堆测试代码
在 2.17GHz~2.87GHz 之间,以 100MHz 步进, 10MHz 频宽通信,跳频点灯,亲测可用,需要两块板子

代码见
https://github.com/libc0607/w60x-rf-hacking/tree/main/w60x-rf-rx

https://github.com/libc0607/w60x-rf-hacking/tree/main/w60x-rf-tx

(楼主代码水平不行 轻喷(

离线

楼主 #8 2020-11-23 22:30:39

libc0607
会员
注册时间: 2018-12-13
已发帖子: 24
积分: 47.5

Re: 关于联盛德W600 Wi-Fi部分的一点探索:自由通信接口、2.2G~2.8G中心频率、5/10MHz传输带宽

rick lou 说:

ida使用给下截图

呃 是指使用过程么。。觉得麻烦就没全截图
关键部分我都摘出来了,如果需要的话我截个大致的步骤

离线

楼主 #9 2020-11-23 22:34:10

libc0607
会员
注册时间: 2018-12-13
已发帖子: 24
积分: 47.5

Re: 关于联盛德W600 Wi-Fi部分的一点探索:自由通信接口、2.2G~2.8G中心频率、5/10MHz传输带宽

dgtg 说:

厉害了!
是不是说可以使用非标的2.4G频率来通信了?
可以避免wifi干扰?

是,很多网桥像ubnt之类的,就有2.3~2.7G的频率范围
还有像是openhd这类图传,用ath9k也可以解锁一些频率
不过要小心避开LTE频段,也不要搞大功率,小心喝茶。。(

离线

楼主 #13 2021-02-21 15:26:02

libc0607
会员
注册时间: 2018-12-13
已发帖子: 24
积分: 47.5

Re: 关于联盛德W600 Wi-Fi部分的一点探索:自由通信接口、2.2G~2.8G中心频率、5/10MHz传输带宽

拍打323 说:

大佬有研究wifibroadcast吗?这种通过监听模式实施通讯的方式,包注入和接收,他有经常丢包的问题吗?我研究了一阵子不用fec和用fec都会丢包.用fec也有0.001-0.01的丢包率.

有可能你的网卡(或网卡驱动)丢掉了crc错误的包?
大半年没碰这个了,不少都忘了XD

离线

楼主 #15 2021-03-03 20:52:24

libc0607
会员
注册时间: 2018-12-13
已发帖子: 24
积分: 47.5

Re: 关于联盛德W600 Wi-Fi部分的一点探索:自由通信接口、2.2G~2.8G中心频率、5/10MHz传输带宽

拍打323 说:
libc0607 说:
拍打323 说:

大佬有研究wifibroadcast吗?这种通过监听模式实施通讯的方式,包注入和接收,他有经常丢包的问题吗?我研究了一阵子不用fec和用fec都会丢包.用fec也有0.001-0.01的丢包率.

有可能你的网卡(或网卡驱动)丢掉了crc错误的包?
大半年没碰这个了,不少都忘了XD

监听模式接收端收到错的不会发送重传?还是说监听模式不按802.11协议来?还是说发送这边哪里设置成广播,单播?
监听模式也可以使用udp协议发送数据?

监听模式接收端收到错的不会发送重传
重传应该是MAC的协议层做的事,可能在mac80211里,也可能在fullmac的驱动里,mac80211的做法应该是收到数据包之后加上radiotap头并传给所有的监听接口

通过监听接口发包你可以就理解为……FM广播之类的(?),从监听接口送了数据进去就会有对应的数据包在空中传输
虽然发包的时候也会有CCA之类的机制,但重传是(比监听接口更上的)上层协议栈做的事,
空中传输的时候会有不可预知的情况,比如楼下有个微波炉路过,那这期间传送的包很可能就会出现校验错误

另,记得W60x系列芯片的文档里提到,调用他们的自由通信接口时收到的包不含FCS错误的包;
Linux下是否上报FCS错误的包取决于设置监听模式时的flag,具体可以看下 iw monitor mode flags 这篇;但如果驱动没按这个实现那也没办法orz

另2,像ezwifibroadcast这种项目也绝对不可能使用802.11的ACK机制,因为如果发射端和接收端的物理距离大于无线电波在一个SIFS时间内于该情况下可以传播的距离的话那就会一直卡死在重传……SIFS大概是10us这个级别的,无线电波也就刚飞了几公里而已((

UDP那个我也不知道怎么一两句话解释明白,这俩概念离得太远了……x 要不再具体问下

最近编辑记录 libc0607 (2021-03-03 22:43:27)

离线

楼主 #18 2021-03-05 12:20:52

libc0607
会员
注册时间: 2018-12-13
已发帖子: 24
积分: 47.5

Re: 关于联盛德W600 Wi-Fi部分的一点探索:自由通信接口、2.2G~2.8G中心频率、5/10MHz传输带宽

拍打323 说:

我用的网卡是ar9271,,我怀疑人家ez-wifibroadcast的树梅派的ath9k驱动做了修改,错误包没有丢弃,让fec来纠正.
dev <devname> set monitor <flag>*
        Set monitor flags. Valid flags are:
        none:     no special flags
        fcsfail:  show frames with FCS errors
        control:  show control frames
        otherbss: show frames from other BSSes
        cook:     use cooked mode
        active:   use active mode (ACK incoming unicast packets)
人家profile里监听模式flags没用 otherbss fcsfail ,用的none.我玩的wifibroadcast用了otherbss fcsfail.

这个我觉得可以在树莓派上用wireshark抓包验证一下


拍打323 说:

但是为什么遵循DCF,一直占用信道不是更好.

我的理解,发包的时候可以选择发RTS包,驱动里也可以魔改调节随机退避的窗口大小,就相当于可以在DCF规则下作弊

离线

楼主 #21 2021-03-07 16:13:38

libc0607
会员
注册时间: 2018-12-13
已发帖子: 24
积分: 47.5

Re: 关于联盛德W600 Wi-Fi部分的一点探索:自由通信接口、2.2G~2.8G中心频率、5/10MHz传输带宽

拍打323 说:

经过对比代码,EZ设置监听模式时没用fcsfail,但是radioflags有检测crc,而openHD不检测radioflags的crc,都是丢掉crc错误的,反正也不能根据错误包纠正?而是根据fec找回丢的包?我抓包发现原始的wifibroadcast项目有的sum sequence 没有,应该是mac80211层根据radioflags的crc错误标志丢弃了!

我的理解,
Wi-Fi硬件的OFDM物理层也有类似FEC的机制(如802.11g 6Mbps 的 1/2),包内的错误应该是靠这个纠正;
包内错误无法纠正的时候包crc就会错,导致丢包;
当一组包,例如FEC设置为 8数据/4FEC ,即一组12个包中,丢失4个以内时,通过FEC算法可以恢复出8个正确的数据包;
当12个包中丢失超过4个则无法恢复这组共8包的数据,导致H264码流中某个NALU损坏,视频的某个或某些Slice损坏;
视频解码器把这些个Slice显示成花屏,剩下的再继续显示……
(我也不知道这么个流程对不对x


拍打323 说:

监听模式丢包应该是正常的,2.4g太拥挤了!那他们的图像不花屏应该用了另外的措施?openhd有用rtp?视频编码打包时用了rtp或者解码时判断帧有丢包,丢的用xx填充,否则全花……

我之前用EZ倒是经常遇到花屏,现象为从屏幕某个高度的一行开始,往下全部重复该行的颜色
搜了一下ytb,比如这样:https://youtu.be/teTOSCb_4kE?t=472 (这人用的2.3G)

另外在QOpenHD那边README看到一段话,

On the GroundPi, the app is simply an overlay on hello_video just like the original OSD, so video should work exactly the same as it always has, though there is an additional PiP overlay available for the 2nd camera if one is being used.

如果用的也是hello_video那和EZ应该没区别
但我没读过hello_video源码,不知道它的内部怎么处理的坏包,不知道坛子里有没有大佬看过……orz

离线

楼主 #27 2021-10-18 17:06:23

libc0607
会员
注册时间: 2018-12-13
已发帖子: 24
积分: 47.5

Re: 关于联盛德W600 Wi-Fi部分的一点探索:自由通信接口、2.2G~2.8G中心频率、5/10MHz传输带宽

kxhui 说:

哥,请问下你的IDA PRO是哪个版本?

硬盘深处翻出来的 7.0,忘了在哪下载到的了。。
下载的话去 Github 搜搜估计就有了,也可以考虑一下 Ghidra

离线

页脚

工信部备案:粤ICP备20025096号 Powered by FluxBB

感谢为中文互联网持续输出优质内容的各位老铁们。 QQ: 516333132, 微信(wechat): whycan_cn (哇酷网/挖坑网/填坑网) service@whycan.cn