中间件添加WIFI模块

中间件添加WIFI模块

距离上次更新已经过去了一个半月了,这段时间一直在忙WIFI功能的添加,此项目是直接买的两个wifi芯片,8812和8192,一个是2.4G一个是5G,手里只有一份8812的手册,再也没有其他资料,是一次学习,也是一次挑战。

此前我是没有做过WiFi相关的中间件的工作,这次因为公司没人(三个中间件开发,负责WiFi的同事离职了),由我来顶上,借此机会也对WiFi进行了基本的学习。

具体任务

BSP的同事负责修改、移植WIFI驱动。使用的平台是64位的,没有现成的驱动,需要把找到的32位驱动移植过来(为了节省资金,直接购买的芯片,没有FAE的支持,只能自己搞)

我负责把WiFi功能添加到SDK中并向上提供接口,所需接口可以大致为以下几个:

  • WiFi参数的设置和获取(SSID,密码,加密模式,信道,信道宽度等)
  • WiFi黑名单白名单的设置和获取
  • WPS PBC/PIN 模式的设置
  • WPS状态获取
  • WPS取消/关闭

每个接口又分为2.4G和5G,本次以2.4G为记录,5G和2.4G基本一样,只用改interface即可。

WIFI启动前的准备工作

此次没有使用hostapd,也没有使用脚本,采用直接操作驱动,即使用iwpriv的方式进行设置,根据需求先在数据库中建立了三张表,一张表为WiFi参数,一张表为白名单,一张表为黑名单:

  • WiFi参数

  • 黑名单

  • 白名单

参数介绍

黑白名单里均为12位mac地址,就不过多赘述了,主要看一下表中wifi参数

参数 取值 意义
enable 0-disable, 1-enable WiFi开关
hidden_ssid 0-disable, 1-enable 隐藏WiFi
ssid string WiFi名称
password string WiFi密码
max_user int WiFi最大连接数
frequency 0-2.4g, 1-5g wifi模式
auth_mode 0-open, 4-wpa2, 6-wpa/wpa2 mixed 加密类型
encryp_type 2–TKIP, 8–AES(CCMP), 10–TKIP/AES mixed 密码组
band_mode 1–11b, 2–11g, 4–11a, 8–11n, 64–11ac 波段选择,可以按位或操作
channel 0 for auto channel, 1-14 for 11b/11g 信道
band_width 0-20M, 1-40M, 2-80M 信道宽度
mac_enable 0-disable, 1-enable 黑白名单功能开关
mac_mod 0-黑名单, 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
class wifi_24g
{
public:
int m_enable;
int m_hiden_ssid;
string m_ssid;
string m_password;
int m_max_user;
int m_frequency;
int m_auth_mode;
int m_encryp_type;
int m_band_mode;
int m_channel;
int m_band_width;

public:

wifi_24g(); //初始化,将WiFi配置读取并赋值给成员变量
virtual ~wifi_24g();

void save_conf_to_db(); //保存WiFi配置
void save_mac_filter(int enable, int mod); //保存黑白名单配置
void get_mac_filter(int *enable, int *mod); //读黑白名单配置

private:
string read_config(string config_name); //读取数据库
int save_config(string config_name, string config_value); //保存到数据库
};
C++

启动WIFI

启动分为加载驱动,设置参数,up interface,建立网桥这几步,具体实现如下:

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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
//m_wifi_24g 为wifi_24g的实例
//m_mac_mod,m_mac_enable为黑白名单参数,wifi驱动中只定义了aclmode,0-disable, 1-白名单, 2-黑名单
//m_mac_list_black m_mac_list_white 为黑白名单mac地址列表
void start_wifi_24g()
{
list<string> cmd_list;
list<string> mac_list;
string tmp;
int mod = m_mac_mod + 1;

cmd_list.push_back("insmod /lib/modules/rtl8192es.ko");
cmd_list.push_back("iwpriv wlan0 set_mib wsc_enable=2");
cmd_list.push_back("iwpriv wlan0 set_mib regdomain=3");
cmd_list.push_back("iwpriv wlan0 set_mib opmode=16");
//RF
tmp = "iwpriv wlan0 set_mib channel=" + to_string(m_wifi_24g->m_channel);
cmd_list.push_back(tmp);
cmd_list.push_back("iwpriv wlan0 set_mib ch_hi=14");
cmd_list.push_back("iwpriv wlan0 set_mib ch_low=1");
cmd_list.push_back("iwpriv wlan0 set_mib MIMO_TR_mode=3");
cmd_list.push_back("iwpriv wlan0 set_mib tssi1=0");
cmd_list.push_back("iwpriv wlan0 set_mib tssi2=0");
cmd_list.push_back("iwpriv wlan0 set_mib trswitch=0");
cmd_list.push_back("iwpriv wlan0 set_mib rfe_type=0");
//rate
cmd_list.push_back("iwpriv wlan0 set_mib basicrates=15");
cmd_list.push_back("iwpriv wlan0 set_mib oprates=4095");
cmd_list.push_back("iwpriv wlan0 set_mib autorate=1");
cmd_list.push_back("iwpriv wlan0 set_mib rtsthres=2347");
cmd_list.push_back("iwpriv wlan0 set_mib fragthres=2346");
cmd_list.push_back("iwpriv wlan0 set_mib expired_time=30000");
cmd_list.push_back("iwpriv wlan0 set_mib bcnint=100");
cmd_list.push_back("iwpriv wlan0 set_mib dtimperiod=1");
cmd_list.push_back("iwpriv wlan0 set_mib preamble=0");

//hiden SSID
tmp = "iwpriv wlan0 set_mib hiddenAP=" + to_string(m_wifi_24g->m_hiden_ssid);
cmd_list.push_back(tmp);

//SSID
tmp = "iwpriv wlan0 set_mib ssid=" + m_wifi_24g->m_ssid;
cmd_list.push_back(tmp);

//max client number
tmp = "iwpriv wlan1 set_mib stanum=" + m_wifi_24g->m_max_user;
cmd_list.push_back(tmp);

//acl start
cmd_list.push_back("iwpriv wlan0 set_mib aclnum=0");
if (!m_mac_enable)
{
mod = 0;
}

tmp = "iwpriv wlan0 set_mib aclmode=" + to_string(mod);
cmd_list.push_back(tmp);

if (mod == 1)
{
mac_list = m_mac_list_white;
}
else
{
mac_list = m_mac_list_black;
}

if (mac_list.size() > 0)
{
for (list<string>::iterator it = mac_list.begin(); it != mac_list.end(); ++it)
{
tmp = "iwpriv wlan0 set_mib acladdr=" + (*it);
cmd_list.push_back(tmp);
}
}
//acl end

//Set to 2 to use open system or shared key automatically
cmd_list.push_back("iwpriv wlan0 set_mib authtype=2");

//auth_mode
if (m_wifi_24g->m_auth_mode == 0)
{
cmd_list.push_back("iwpriv wlan0 set_mib encmode=0");
}
else
{
cmd_list.push_back("iwpriv wlan0 set_mib encmode=2");
}

cmd_list.push_back("iwpriv wlan0 set_mib 802_1x=0");

//band
tmp = "iwpriv wlan0 set_mib band=" + to_string(m_wifi_24g->m_band_mode);
cmd_list.push_back(tmp);
cmd_list.push_back("iwpriv wlan0 set_mib deny_legacy=0");

tmp = "iwpriv wlan0 set_mib use40M=" + to_string(m_wifi_24g->m_band_width);
cmd_list.push_back(tmp);

cmd_list.push_back("iwpriv wlan0 set_mib 2ndchoffset=1");
cmd_list.push_back("iwpriv wlan0 set_mib shortGI20M=1");
cmd_list.push_back("iwpriv wlan0 set_mib shortGI40M=1");
cmd_list.push_back("iwpriv wlan0 set_mib shortGI80M=1");
cmd_list.push_back("iwpriv wlan0 set_mib ampdu=1");
cmd_list.push_back("iwpriv wlan0 set_mib amsdu=0");
cmd_list.push_back("iwpriv wlan0 set_mib stbc=1");
cmd_list.push_back("iwpriv wlan0 set_mib coexist=1");
cmd_list.push_back("iwpriv wlan0 set_mib disable_protection=0");

cmd_list.push_back("iwpriv wlan0 set_mib groupID=0");
cmd_list.push_back("iwpriv wlan0 set_mib block_relay=0");
cmd_list.push_back("iwpriv wlan0 set_mib wifi_specific=1");
cmd_list.push_back("iwpriv wlan0 set_mib qos_enable=1");
cmd_list.push_back("iwpriv wlan0 set_mib guest_access=0");
cmd_list.push_back("iwpriv wlan0 set_mib countrycode=CN");

switch (m_wifi_24g->m_auth_mode)
{
case 0:
cmd_list.push_back("iwpriv wlan0 set_mib psk_enable=0");
break;
case 4:
cmd_list.push_back("iwpriv wlan0 set_mib psk_enable=2");
break;
case 6:
cmd_list.push_back("iwpriv wlan0 set_mib psk_enable=3");
break;

default:
cmd_list.push_back("iwpriv wlan0 set_mib psk_enable=3");
break;
}

if (m_wifi_24g->m_auth_mode == 2 || m_wifi_24g->m_auth_mode == 6)
{
tmp = "iwpriv wlan0 set_mib wpa_cipher=" + to_string(m_wifi_24g->m_encryp_type);
cmd_list.push_back(tmp);
}

if (m_wifi_24g->m_auth_mode == 4 || m_wifi_24g->m_auth_mode == 6)
{
tmp = "iwpriv wlan0 set_mib wpa2_cipher=" + to_string(m_wifi_24g->m_encryp_type);
cmd_list.push_back(tmp);
}

//password
tmp = "iwpriv wlan0 set_mib passphrase=" + m_wifi_24g->m_password;
cmd_list.push_back(tmp);

cmd_list.push_back("iwpriv wlan0 set_mib gk_rekey=86400");

cmd_list.push_back("ifconfig wlan0 up");
cmd_list.push_back("brctl addif br-lan wlan0");

do_command("start_wifi.sh", cmd_list);
}
C++

do_command函数就是对我之前提到的do_system()的封装,代码如下:

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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
int do_command(string file_name, list<string> arg_list)
{
FILE *fp = NULL;
string path = "/tmp/" + file_name;

fp = fopen(path.c_str(), "w+");
if (fp == NULL)
{
return -1;
}

for (list<string>::iterator list_iterator = arg_list.begin(); list_iterator != arg_list.end(); list_iterator++)
{
fprintf(fp, "%s\n", (*list_iterator).c_str());
}

fprintf(fp, "rm -f %s\n", path.c_str());
fclose(fp);

return(do_system(1, NULL, "sh", path.c_str(), NULL));
}

int do_system(unsigned char wait, int *svc_pid, const char *exec_file, ...)
{
pid_t pid;
int status = -1;
int rc = -1;
sigset_t chldmask, savemask;
list<string>::iterator list_iterator;

if (exec_file == NULL)
{
return (-1);
}

/* now block SIGCHLD */
sigemptyset(&chldmask);
sigaddset(&chldmask, SIGCHLD);
if (sigprocmask(SIG_BLOCK, &chldmask, &savemask))
{
return (-2);
}

pid = fork();
if (pid < 0)
{
/* Error. */
rc = -3;
}
else if (pid == 0)
{
/* Child. */
int n = 0;
char **argv;
int argc = 0;
char **p;
va_list args;

n = 1; /* =1 for argv[0]. */
va_start(args, exec_file);
for (; va_arg(args, char *);)
{
++n;
}
va_end(args);

p = argv = (char **)malloc((n + 1) * sizeof(char *)); /* +1 for terminal NULL */

p[0] = (char *)exec_file;

va_start(args, exec_file);
for (; n--;)
{
*++p = va_arg(args, char *);
}
va_end(args);
*p = NULL;

sigprocmask(SIG_SETMASK, &savemask, NULL);
n = execvp(exec_file, argv);
free(argv);
exit(n);
}
else
{
usleep(1 * 1000);
if (svc_pid)
{
*svc_pid = pid;
}

if (wait)
{
do
{
rc = waitpid(pid, &status, 0);
if (rc < 0)
{
if (errno != EINTR)
{
break;
}
}
else
{
rc = WEXITSTATUS(status);
break;
}
} while (1);
}
else
{
rc = 0;
}
}

sigprocmask(SIG_SETMASK, &savemask, NULL);
return rc;
}
C++

启动WiFi的过程中,参数的意义和数据库基本一致,比较值得注意的是auth_mode

  • 如果auth_mode为0,encmode为0否则为2,2代表WPA/WPA2模式
  • auth_mode为0,psk_enable为0,否则为一一对应的值(代码中的switch为映射关系)
  • auth_mode不为0,才需要设置wpa_cipher或wpa2_cipher

WIFI接口

WIFI参数配置和获取

获取参数时只需返回wifi_24g实例的成员变量即可

配置时,将接收到的值赋给wifi_24g的成员变量,并重新加载WiFi驱动

WiFi黑名单白名单的设置和获取

获取黑白名单配置时,只需读出表中数据返回即可

设置黑白名单时,将数据保存到表中,并执行黑白名单的参数配置命令即可:

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
list<string> cmd_list;
list<string> mac_list;
string tmp;
int mod = m_mac_mod + 1;

cmd_list.push_back("ifconfig wlan0 down");
cmd_list.push_back("iwpriv wlan0 set_mib aclnum=0");

cmd_list.push_back("ifconfig wlan1 down");
cmd_list.push_back("iwpriv wlan1 set_mib aclnum=0");
if (!m_mac_enable)
{
mod = 0;
}

tmp = "iwpriv wlan0 set_mib aclmode=" + to_string(mod);
cmd_list.push_back(tmp);

tmp = "iwpriv wlan1 set_mib aclmode=" + to_string(mod);
cmd_list.push_back(tmp);

if (mod == 1)
{
mac_list = m_mac_list_white;
}
else
{
mac_list = m_mac_list_black;
}

for (list<string>::iterator it = mac_list.begin(); it != mac_list.end(); ++it)
{
tmp = "iwpriv wlan0 set_mib acladdr=" + (*it);
cmd_list.push_back(tmp);

tmp = "iwpriv wlan1 set_mib acladdr=" + (*it);
cmd_list.push_back(tmp);
}

cmd_list.push_back("ifconfig wlan0 up");
cmd_list.push_back("ifconfig wlan1 up");
do_command(CMD_WIFI_MAC_FILTER, cmd_list);
C++

wlan0为2.4GWiFi,wlan1为5GWiFi,黑白名单需要同时配置两个WiFi

WPS PBC/PIN 模式的设置

开启WPS只用下发WPS命令,PBC模式为:

1
system("wscd -sig_pbc wlan0");
C++

PIN模式为:

1
2
string cmd = "iwpriv wlan0 set_mib pin=" + pin_code;
system(cmd.c_str());
C++

WPS状态获取

WPS的状态保存在文件中,直接读取”/tmp/wscd_status”即可。状态值如下:

-1:未启动, 0:启动, 2:超时, 3:成功

WPS取消/关闭

WPS取消/关闭时只需要创建一个文件,wscd检测到文件,就会停止WPS:

1
system("touch /tmp/wscd_cancel");
C++

中间件添加WIFI模块
https://carl-5535.github.io/2021/12/14/工作总结/中间件添加WIFI模块/
作者
Carl Chen
发布于
2021年12月14日
许可协议