中间件添加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 (); virtual ~wifi_24g (); void save_conf_to_db () ; 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 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" ); 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" ); 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" ); tmp = "iwpriv wlan0 set_mib hiddenAP=" + to_string (m_wifi_24g->m_hiden_ssid); cmd_list.push_back (tmp); tmp = "iwpriv wlan0 set_mib ssid=" + m_wifi_24g->m_ssid; cmd_list.push_back (tmp); tmp = "iwpriv wlan1 set_mib stanum=" + m_wifi_24g->m_max_user; cmd_list.push_back (tmp); 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); } } cmd_list.push_back ("iwpriv wlan0 set_mib authtype=2" ); 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" ); 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); } 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 ); } sigemptyset (&chldmask); sigaddset (&chldmask, SIGCHLD); if (sigprocmask (SIG_BLOCK, &chldmask, &savemask)) { return (-2 ); } pid = fork(); if (pid < 0 ) { rc = -3 ; } else if (pid == 0 ) { int n = 0 ; char **argv; int argc = 0 ; char **p; va_list args; n = 1 ; va_start (args, exec_file); for (; va_arg (args, char *);) { ++n; } va_end (args); p = argv = (char **)malloc ((n + 1 ) * sizeof (char *)); 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++