前言
该软件用于将不同型号的无线通信设备隔离开,由于目前的无线 WIFI 都是通过 SSID 和 KEY 来连接的。虽然有黑名单系统,但是黑名单系统从底层看是禁止了特定 MAC 地址的设备连接。这样就有一个问题,不可能每次生产一批设备,都要去改变之前卖给客户的设备的黑名单吧???
所以需要在连接时进行快速认证,认证结果将保存在进程中,掉电后会重新认证。这是考虑到我们的设备用于远距离基站互联,一般不会掉电,并且约定了后续会不断提供升级版本,并且特殊的机制可以预防一切客户的奇葩操作。
一、主线交互设计
需要注意的是黑名单是自写的双链接结构,因为 WIFI 移植时标配的 wpa_supplicant 工具的黑名单是写进硬盘的,掉电不可重置。
由于每个设备的 SSID 是客户设定的,所以通过 80211cfg 接口获取设备的 MAC 地址。
而对于设备的型号,每个厂商都有提供写号工具,我所见过的就有例如:高通、MTK、瑞芯微。
写号工具一般是将一段信息写进一个二进制文件中,这个二进制文件在系统中是不可改的类型。
各种应用程序会通过读取这个型号,完成不同的初始化,例如:webui ,这个就可以直观的让客户以为是差异性非常大的设备。我的这个无线网络隔离软件,也是通过型号来完成不同的功能的。
总之,型号可以做到一份源码兼容很多不同设备。
不过我们也可以自己写。
二、设备型号实现
我们可以将想好一段标志集,然后设计成结构体,后面有用。
typedef struct
{
char model[32]; //项目型号
char mfr[32]; //生产厂商
char sn[32]; //出厂写入SN号
char smt_sn[32]; //SMT写入SN号
char mac[32]; //MAC地址,通常是有线网口的MAC
char ssid[32]; //Wireless SSID
char password[32]; //Wireless 密码
char user_mode; //1 : 为用户模式。0:工厂模式(默认为0)
char rail_mode //可扩展设备类型 0: 普通类别(默认值)。1:XXX类别。2.3.4...
char reserve[1694]; //预留字段,device_info.bin总文件大小2KB
}T_DeviceInfo
然后用任意可以编辑二进制文件(.bin)的编辑器新建一个 .bin 文件,以 UltraEdit 为例子。
每一行即是32个字节,通过编辑右边的内容,bin 文件中的十六进制内容会做出相应的改动。
改完保存,编译系统镜像时,顺便把文件打包进系统一个安全的目录。
接下来就是如何读取这段信息了。
为了方便调试,系统中可以制作一个小工具,用于快速读取型号文件中的任何内容:
#define DEVICE_INFO_BIN "/userdata/data/config/device_info.bin" //二进制文件的路径
T_DeviceInfo *DeviceInfo = NULL; //用于承接数据
T_JwDeviceInfo *Get_DeviceInfo(void)
{
if (!DeviceInfo)
{
FILE *fp = fopen(DEVICE_INFO_BIN, "r");
if (fp)
{
char buff[2048] = {};
/* 假如该二进制文件读取出来的数据有头部,那么应该移动到头部的内存之后
fseek(fp, 1048576, SEEK_SET);
*/
fread(buff, 2048, 1, fp);
fclose(fp);
if (buff[0] && buff[0] != 0xff)
{
DeviceInfo = malloc(2048);
if (DeviceInfo)
memcpy(DeviceInfo, buff, 2048);
}
}
}
return JwDeviceInfo;
}
int Main_Devinf(int32_t argc, cint8_t **argv)
{
if (argc < 2) { LOG_PRINT("Need key string!\n"); return 1; }
if (!Get_DeviceInfo()) { LOG_PRINT("\n"); return 1; }
if (!strcmp(argv[1], "model")) LOG_PRINT("%s\n", Get_DeviceInfo()->model);
else if (!strcmp(argv[1], "mfr")) LOG_PRINT("%s\n", Get_DeviceInfo()->mfr);
else if (!strcmp(argv[1], "sn")) LOG_PRINT("%s\n", Get_DeviceInfo()->sn);
else if (!strcmp(argv[1], "smt_sn")) LOG_PRINT("%s\n", Get_DeviceInfo()->smt_sn);
else if (!strcmp(argv[1], "mac")) LOG_PRINT("%s\n", Get_DeviceInfo()->mac);
else if (!strcmp(argv[1], "ssid_60g")) LOG_PRINT("%s\n", Get_DeviceInfo()->ssid);
else if (!strcmp(argv[1], "password_60g")) LOG_PRINT("%s\n", Get_DeviceInfo()->password);
else if (!strcmp(argv[1], "user_mode")) LOG_PRINT("%c\n", Get_DeviceInfo()->user_mode);
else if (!strcmp(argv[1], "rail_mode")) LOG_PRINT("%c\n", Get_DeviceInfo()->rail_mode);
else { LOG_PRINT("\n"); return 1; }
return 0;
}
框架内部的具体实现
首先,本人并不是特别喜欢这个框架,因为这个框架有些离散,回调没有直接传递给任务需要信息,需要任务自己获取信息处理。
但是这个框架也确实在工作中制作出了一个小工具软件,并且十分稳定好用。
针对上面的传递信息的缺点,如果在一种情况:回调偏偏暂时无法获取足够的信息可以传递给任务呢?
那么只能告诉工作线程该干活了和干多少个活。
还有就是本人特别讨厌线程,凡是可以减少使用线程并且效果只要达到相近的,我都不想用线程。