├── Makefile ├── QT_dhcpd.conf ├── README.md ├── ap_reset_config.conf ├── build_deb.sh ├── eloop.c ├── eloop.h ├── hs2_profile.h ├── indigo_api.c ├── indigo_api.h ├── indigo_api_callback.h ├── indigo_api_callback_dut.c ├── indigo_api_callback_sniffer.c ├── indigo_api_callback_tp.c ├── indigo_packet.c ├── indigo_packet.h ├── main.c ├── openwrt-controlappc-dut-makefile ├── openwrt-controlappc-tp-makefile ├── package.controlappc-dut.Makefile ├── package.controlappc-tp.Makefile ├── patch_nwmgr.sh ├── sta_reset_config.conf ├── test.py ├── utils.c ├── utils.h ├── vendor_specific.h ├── vendor_specific_dut.c ├── vendor_specific_sniffer.c ├── vendor_specific_tp.c ├── wpa_ctrl.c └── wpa_ctrl.h /Makefile: -------------------------------------------------------------------------------- 1 | # Type is laptop or openwrt 2 | TYPE = laptop 3 | # Role is dut or platform or sniffer 4 | ROLE = dut 5 | # Package Version 6 | VERSION = "2.3.0.238" 7 | 8 | OBJS = main.o eloop.o indigo_api.o indigo_packet.o utils.o wpa_ctrl.o 9 | CFLAGS += -g 10 | 11 | ifeq ($(TYPE),laptop) 12 | CC = gcc 13 | CFLAGS += -D_LAPTOP_ 14 | 15 | else 16 | # upstream OPENWRT 17 | # 32 bit 18 | #CC = /openwrt/QCA_Sniffer_11ax/qsdk/staging_dir/toolchain-arm_cortex-a7_gcc-5.2.0_musl-1.1.16_eabi/bin/arm-openwrt-linux-gcc 19 | #LD = /openwrt/QCA_Sniffer_11ax/qsdk/staging_dir/toolchain-arm_cortex-a7_gcc-5.2.0_musl-1.1.16_eabi/bin/arm-openwrt-linux-ld 20 | # 64 bit 21 | #CC = /openwrt/11305r3/qsdk/staging_dir/toolchain-aarch64_cortex-a53_gcc-5.2.0_musl-1.1.16/bin/aarch64-openwrt-linux-gcc 22 | #LD = /openwrt/11305r3/qsdk/staging_dir/toolchain-aarch64_cortex-a53_gcc-5.2.0_musl-1.1.16/bin/aarch64-openwrt-linux-ld 23 | # Wi-Fi 7 24 | CC = /openwrt/qsdk/staging_dir/toolchain-aarch64/bin/aarch64-openwrt-linux-musl-gcc 25 | LD = /openwrt/qsdk/staging_dir/toolchain-aarch64/bin/aarch64-openwrt-linux-ld 26 | # _OPENWRT_: Use OPENWRT 27 | CFLAGS += -D_OPENWRT_ 28 | CFLAGS += -DHOSTAPD_SUPPORT_MBSSID_WAR 29 | endif 30 | 31 | # Define the app is for DUT or platform 32 | ifeq ($(ROLE),dut) 33 | OBJS += indigo_api_callback_dut.o vendor_specific_dut.o 34 | CFLAGS += -D_DUT_ 35 | else ifeq ($(ROLE), sniffer) 36 | OBJS += indigo_api_callback_sniffer.o vendor_specific_sniffer.o 37 | CFLAGS += -D_TEST_SNIFFER_ 38 | else 39 | OBJS += indigo_api_callback_tp.o vendor_specific_tp.o 40 | CFLAGS += -DCONFIG_CTRL_IFACE_UDP 41 | CFLAGS += -D_TEST_PLATFORM_ 42 | endif 43 | 44 | # Define the package version 45 | ifneq ($(VERSION),) 46 | CFLAGS += -D_VERSION_='$(VERSION)' 47 | endif 48 | 49 | all: app 50 | 51 | %.o: %.c 52 | $(CC) $(CFLAGS) -c -o $@ $< 53 | 54 | app: $(OBJS) 55 | $(CC) $(CFLAGS) -o $@ $^ 56 | 57 | clean: 58 | rm -rf app *.o 59 | -------------------------------------------------------------------------------- /QT_dhcpd.conf: -------------------------------------------------------------------------------- 1 | # dhcpd.conf 2 | # 3 | # Sample configuration file for ISC dhcpd 4 | # 5 | # Attention: If /etc/ltsp/dhcpd.conf exists, that will be used as 6 | # configuration file instead of this file. 7 | # 8 | 9 | # option definitions common to all supported networks... 10 | option domain-name "example.org"; 11 | option domain-name-servers ns1.example.org, ns2.example.org; 12 | 13 | default-lease-time 600; 14 | max-lease-time 7200; 15 | 16 | # The ddns-updates-style parameter controls whether or not the server will 17 | # attempt to do a DNS update when a lease is confirmed. We default to the 18 | # behavior of the version 2 packages ('none', since DHCP v2 didn't 19 | # have support for DDNS.) 20 | ddns-update-style none; 21 | 22 | # If this DHCP server is the official DHCP server for the local 23 | # network, the authoritative directive should be uncommented. 24 | #authoritative; 25 | 26 | # Use this to send dhcp log messages to a different log file (you also 27 | # have to hack syslog.conf to complete the redirection). 28 | #log-facility local7; 29 | 30 | # No service will be given on this subnet, but declaring it helps the 31 | # DHCP server to understand the network topology. 32 | 33 | # This is a very basic subnet declaration. 34 | 35 | #subnet 10.254.239.0 netmask 255.255.255.224 { 36 | # range 10.254.239.10 10.254.239.20; 37 | # option routers rtr-239-0-1.example.org, rtr-239-0-2.example.org; 38 | #} 39 | 40 | # This declaration allows BOOTP clients to get dynamic addresses, 41 | # which we don't really recommend. 42 | 43 | #subnet 10.254.239.32 netmask 255.255.255.224 { 44 | # range dynamic-bootp 10.254.239.40 10.254.239.60; 45 | # option broadcast-address 10.254.239.31; 46 | # option routers rtr-239-32-1.example.org; 47 | #} 48 | 49 | # A slightly different configuration for an internal subnet. 50 | #subnet 10.5.5.0 netmask 255.255.255.224 { 51 | # range 10.5.5.26 10.5.5.30; 52 | # option domain-name-servers ns1.internal.example.org; 53 | # option domain-name "internal.example.org"; 54 | # option subnet-mask 255.255.255.224; 55 | # option routers 10.5.5.1; 56 | # option broadcast-address 10.5.5.31; 57 | # default-lease-time 600; 58 | # max-lease-time 7200; 59 | #} 60 | 61 | # Hosts which require special configuration options can be listed in 62 | # host statements. If no address is specified, the address will be 63 | # allocated dynamically (if possible), but the host-specific information 64 | # will still come from the host declaration. 65 | 66 | #host passacaglia { 67 | # hardware ethernet 0:0:c0:5d:bd:95; 68 | # filename "vmunix.passacaglia"; 69 | # server-name "toccata.example.com"; 70 | #} 71 | 72 | # Fixed IP addresses can also be specified for hosts. These addresses 73 | # should not also be listed as being available for dynamic assignment. 74 | # Hosts for which fixed IP addresses have been specified can boot using 75 | # BOOTP or DHCP. Hosts for which no fixed address is specified can only 76 | # be booted with DHCP, unless there is an address range on the subnet 77 | # to which a BOOTP client is connected which has the dynamic-bootp flag 78 | # set. 79 | #host fantasia { 80 | # hardware ethernet 08:00:07:26:c0:a5; 81 | # fixed-address fantasia.example.com; 82 | #} 83 | 84 | # You can declare a class of clients and then do address allocation 85 | # based on that. The example below shows a case where all clients 86 | # in a certain class get addresses on the 10.17.224/24 subnet, and all 87 | # other clients get addresses on the 10.0.29/24 subnet. 88 | 89 | #class "foo" { 90 | # match if substring (option vendor-class-identifier, 0, 4) = "SUNW"; 91 | #} 92 | 93 | #shared-network 224-29 { 94 | # subnet 10.17.224.0 netmask 255.255.255.0 { 95 | # option routers rtr-224.example.org; 96 | # } 97 | # subnet 10.0.29.0 netmask 255.255.255.0 { 98 | # option routers rtr-29.example.org; 99 | # } 100 | # pool { 101 | # allow members of "foo"; 102 | # range 10.17.224.10 10.17.224.250; 103 | # } 104 | # pool { 105 | # deny members of "foo"; 106 | # range 10.0.29.10 10.0.29.230; 107 | # } 108 | #} 109 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | QuickTrack Control App 2 | ------------------------------------------------------------------------ 3 | 4 | /* Copyright (c) 2020 Wi-Fi Alliance */ 5 | 6 | /* Permission to use, copy, modify, and/or distribute this software for any */ 7 | /* purpose with or without fee is hereby granted, provided that the above */ 8 | /* copyright notice and this permission notice appear in all copies. */ 9 | 10 | /* THE SOFTWARE IS PROVIDED 'AS IS' AND THE AUTHOR DISCLAIMS ALL */ 11 | /* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED */ 12 | /* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL */ 13 | /* THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR */ 14 | /* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING */ 15 | /* FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF */ 16 | /* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT */ 17 | /* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS */ 18 | /* SOFTWARE. */ 19 | 20 | ------------------------------------------------------------------------ 21 | Build & Run 22 | ------------------------------------------------------------------------ 23 | make clean ; make
24 | sudo ./app -p <port> 25 | 26 | -------------------------------------------------------------------------------- /ap_reset_config.conf: -------------------------------------------------------------------------------- 1 | ctrl_interface=/var/run/hostapd 2 | ctrl_interface_group=0 3 | interface=wlan0 4 | ssid=QuickTrack 5 | channel=36 6 | hw_mode=a 7 | wpa_passphrase=12345678 8 | ieee80211n=1 9 | wpa=2 10 | wpa_key_mgmt=WPA-PSK 11 | rsn_pairwise=CCMP 12 | -------------------------------------------------------------------------------- /build_deb.sh: -------------------------------------------------------------------------------- 1 | #!bin/bash 2 | 3 | package_name="WFA-QuickTrack-ControlAppC" 4 | version="" 5 | git_revision="" 6 | deb_name=${package_name}.deb 7 | control_file=${package_name}/DEBIAN/control 8 | postinst_file=${package_name}/DEBIAN/postinst 9 | prerm_file=${package_name}/DEBIAN/prerm 10 | postrm_file=${package_name}/DEBIAN/postrm 11 | source_folder=${package_name}/usr/local/bin/${package_name}/source 12 | installed_source_folder=/usr/local/bin/${package_name}/source 13 | 14 | create_source_folder() { 15 | rm -rf ${package_name} 16 | mkdir -p ${package_name}/DEBIAN 17 | mkdir -p ${source_folder} 18 | } 19 | 20 | copy_filter_source() { 21 | cp -rf *.c *.h Makefile ${source_folder} 22 | cp -rf patch_nwmgr.sh ${source_folder} 23 | cp -rf QT_dhcpd.conf ${source_folder} 24 | } 25 | 26 | create_control() { 27 | echo "Package: ${package_name}" >"$control_file" 28 | echo "Version: ${version}-${revision}" >>"$control_file" 29 | echo "Architecture: all" >>"$control_file" 30 | echo "Depends: build-essential, arping, isc-dhcp-server, iw" >>"$control_file" 31 | echo "Essential: no" >>"$control_file" 32 | echo "Conflicts: wfa-indigo-controlappc" >>"$control_file" 33 | echo "Priority: optional" >>"$control_file" 34 | echo "Maintainer: Wi-Fi Alliance" >>"$control_file" 35 | echo "Description: This Software is to control the DUT and test platform" >>"$control_file" 36 | echo "" >>"$control_file" 37 | } 38 | 39 | create_postinst() { 40 | echo "#!/bin/bash" >"$postinst_file" 41 | echo "echo \"Start the installation and compile the source code.\"" >>"$postinst_file" 42 | echo "cd ${installed_source_folder}" >>"$postinst_file" 43 | echo "sed -i 's/VERSION = /VERSION = \"${version}\"#VERSION = /' Makefile" >>"$postinst_file" 44 | echo "make clean >/dev/null" >>"$postinst_file" 45 | echo "make >/dev/null" >>"$postinst_file" 46 | echo "cp app ../app_dut" >>"$postinst_file" 47 | echo "make clean >/dev/null" >>"$postinst_file" 48 | 49 | echo "sed -i 's/ROLE = dut/ROLE = tp/' Makefile" >>"$postinst_file" 50 | echo "make >/dev/null" >>"$postinst_file" 51 | echo "cp app ../app_tp" >>"$postinst_file" 52 | echo "make clean >/dev/null" >>"$postinst_file" 53 | 54 | echo "sed -i 's/ROLE = tp/ROLE = sniffer/' Makefile" >>"$postinst_file" 55 | echo "make >/dev/null" >>"$postinst_file" 56 | echo "cp app ../app_sniffer" >>"$postinst_file" 57 | echo "make clean >/dev/null" >>"$postinst_file" 58 | 59 | echo "cp QT_dhcpd.conf ../QT_dhcpd.conf" >>"$postinst_file" 60 | 61 | echo "echo \"Test application version\"" >>"$postinst_file" 62 | echo "../app_dut -v" >>"$postinst_file" 63 | echo "../app_tp -v" >>"$postinst_file" 64 | echo "echo \"Complete the installation. If you would like to modify the source code for the platform-specific change, you can go to ${installed_source_folder}\"" >>"$postinst_file" 65 | echo "echo \"\"" >>"$postinst_file" 66 | echo "echo \"Start to patch NetworkManager to unmanage the wl* interface.\"" >>"$postinst_file" 67 | echo "/bin/bash ${installed_source_folder}/patch_nwmgr.sh bkup" >>"$postinst_file" 68 | chmod 755 "$postinst_file" 69 | } 70 | 71 | create_prerm() { 72 | echo "#!/bin/bash" >"$prerm_file" 73 | echo "sudo killall app_dut >/dev/null 2>/dev/null" >>"$prerm_file" 74 | echo "sudo killall app_tp >/dev/null 2>/dev/null" >>"$prerm_file" 75 | echo "sleep 3" >>"$prerm_file" 76 | 77 | echo "if [ -d \"/usr/local/bin/WFA-QuickTrack-ControlAppC/source\" ]" >>"$prerm_file" 78 | echo "then" >>"$prerm_file" 79 | echo "cd ${installed_source_folder}" >>"$prerm_file" 80 | echo "rm -rf /usr/local/bin/${package_name}/app_dut" >>"$prerm_file" 81 | echo "rm -rf /usr/local/bin/${package_name}/app_tp" >>"$prerm_file" 82 | echo "/bin/bash ${installed_source_folder}/patch_nwmgr.sh restore" >>"$prerm_file" 83 | echo "rm -rf /usr/local/bin/${package_name}/QT_dhcpd.conf" >>"$prerm_file" 84 | echo "fi" >>"$prerm_file" 85 | 86 | chmod 755 "$prerm_file" 87 | } 88 | 89 | create_deb() { 90 | dpkg -b ${package_name} >/dev/null 91 | } 92 | 93 | if [ -z "$1" ] 94 | then 95 | echo "Please specify the version. E.g., 1.0.10" 96 | exit 97 | else 98 | version="$1" 99 | revision=`git rev-parse --short HEAD` 100 | fi 101 | create_source_folder 102 | create_control 103 | copy_filter_source 104 | create_postinst 105 | create_prerm 106 | create_deb 107 | 108 | echo "Complete. Please reference to the following usage." 109 | echo "1. Please remove the package by \"sudo apt remove wfa-quicktrack-controlappc\"" 110 | echo "2. Please install the package by \"sudo apt install ./WFA-QuickTrack-ControlAppC.deb\"" 111 | -------------------------------------------------------------------------------- /eloop.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Event loop based on select() loop 3 | * Copyright (c) 2002-2005, Jouni Malinen 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License version 2 as 7 | * published by the Free Software Foundation. 8 | * 9 | * Alternatively, this software may be distributed under the terms of BSD 10 | * license. 11 | * 12 | * See README and COPYING for more details. 13 | */ 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #ifdef CONFIG_NATIVE_WINDOWS 25 | #include "common.h" 26 | #endif /* CONFIG_NATIVE_WINDOWS */ 27 | 28 | #include "eloop.h" 29 | 30 | void vendor_deinit(); 31 | 32 | struct eloop_sock { 33 | int sock; 34 | void *eloop_data; 35 | void *user_data; 36 | void (*handler)(int sock, void *eloop_ctx, void *sock_ctx); 37 | }; 38 | 39 | struct eloop_timeout { 40 | struct timeval time; 41 | void *eloop_data; 42 | void *user_data; 43 | void (*handler)(void *eloop_ctx, void *sock_ctx); 44 | struct eloop_timeout *next; 45 | }; 46 | 47 | struct eloop_signal { 48 | int sig; 49 | void *user_data; 50 | void (*handler)(int sig, void *eloop_ctx, void *signal_ctx); 51 | int signaled; 52 | }; 53 | 54 | struct eloop_data { 55 | void *user_data; 56 | 57 | int max_sock, reader_count; 58 | struct eloop_sock *readers; 59 | 60 | struct eloop_timeout *timeout; 61 | 62 | int signal_count; 63 | struct eloop_signal *signals; 64 | int signaled; 65 | int pending_terminate; 66 | 67 | int terminate; 68 | }; 69 | 70 | static struct eloop_data eloop; 71 | 72 | 73 | void eloop_init(void *user_data) 74 | { 75 | memset(&eloop, 0, sizeof(eloop)); 76 | eloop.user_data = user_data; 77 | } 78 | 79 | 80 | int eloop_register_read_sock(int sock, 81 | void (*handler)(int sock, void *eloop_ctx, 82 | void *sock_ctx), 83 | void *eloop_data, void *user_data) 84 | { 85 | struct eloop_sock *tmp; 86 | 87 | tmp = (struct eloop_sock *) 88 | realloc(eloop.readers, 89 | (eloop.reader_count + 1) * sizeof(struct eloop_sock)); 90 | if (tmp == NULL) 91 | return -1; 92 | 93 | tmp[eloop.reader_count].sock = sock; 94 | tmp[eloop.reader_count].eloop_data = eloop_data; 95 | tmp[eloop.reader_count].user_data = user_data; 96 | tmp[eloop.reader_count].handler = handler; 97 | eloop.reader_count++; 98 | eloop.readers = tmp; 99 | if (sock > eloop.max_sock) 100 | eloop.max_sock = sock; 101 | 102 | return 0; 103 | } 104 | 105 | 106 | void eloop_unregister_read_sock(int sock) 107 | { 108 | int i; 109 | 110 | if (eloop.readers == NULL || eloop.reader_count == 0) 111 | return; 112 | 113 | for (i = 0; i < eloop.reader_count; i++) { 114 | if (eloop.readers[i].sock == sock) 115 | break; 116 | } 117 | if (i == eloop.reader_count) 118 | return; 119 | if (i != eloop.reader_count - 1) { 120 | memmove(&eloop.readers[i], &eloop.readers[i + 1], 121 | (eloop.reader_count - i - 1) * 122 | sizeof(struct eloop_sock)); 123 | } 124 | eloop.reader_count--; 125 | } 126 | 127 | 128 | int eloop_register_timeout(unsigned int secs, unsigned int usecs, 129 | void (*handler)(void *eloop_ctx, void *timeout_ctx), 130 | void *eloop_data, void *user_data) 131 | { 132 | struct eloop_timeout *timeout, *tmp, *prev; 133 | 134 | timeout = (struct eloop_timeout *) malloc(sizeof(*timeout)); 135 | if (timeout == NULL) 136 | return -1; 137 | gettimeofday(&timeout->time, NULL); 138 | timeout->time.tv_sec += secs; 139 | timeout->time.tv_usec += usecs; 140 | while (timeout->time.tv_usec >= 1000000) { 141 | timeout->time.tv_sec++; 142 | timeout->time.tv_usec -= 1000000; 143 | } 144 | timeout->eloop_data = eloop_data; 145 | timeout->user_data = user_data; 146 | timeout->handler = handler; 147 | timeout->next = NULL; 148 | 149 | if (eloop.timeout == NULL) { 150 | eloop.timeout = timeout; 151 | return 0; 152 | } 153 | 154 | prev = NULL; 155 | tmp = eloop.timeout; 156 | while (tmp != NULL) { 157 | if (timercmp(&timeout->time, &tmp->time, <)) 158 | break; 159 | prev = tmp; 160 | tmp = tmp->next; 161 | } 162 | 163 | if (prev == NULL) { 164 | timeout->next = eloop.timeout; 165 | eloop.timeout = timeout; 166 | } else { 167 | timeout->next = prev->next; 168 | prev->next = timeout; 169 | } 170 | 171 | return 0; 172 | } 173 | 174 | 175 | int eloop_cancel_timeout(void (*handler)(void *eloop_ctx, void *sock_ctx), 176 | void *eloop_data, void *user_data) 177 | { 178 | struct eloop_timeout *timeout, *prev, *next; 179 | int removed = 0; 180 | 181 | prev = NULL; 182 | timeout = eloop.timeout; 183 | while (timeout != NULL) { 184 | next = timeout->next; 185 | 186 | if (timeout->handler == handler && 187 | (timeout->eloop_data == eloop_data || 188 | eloop_data == ELOOP_ALL_CTX) && 189 | (timeout->user_data == user_data || 190 | user_data == ELOOP_ALL_CTX)) { 191 | if (prev == NULL) 192 | eloop.timeout = next; 193 | else 194 | prev->next = next; 195 | free(timeout); 196 | removed++; 197 | } else 198 | prev = timeout; 199 | 200 | timeout = next; 201 | } 202 | 203 | return removed; 204 | } 205 | 206 | 207 | #ifndef CONFIG_NATIVE_WINDOWS 208 | static void eloop_handle_alarm(int sig) 209 | { 210 | fprintf(stderr, "eloop: could not process SIGINT or SIGTERM in two " 211 | "seconds. Looks like there\n" 212 | "is a bug that ends up in a busy loop that " 213 | "prevents clean shutdown.\n" 214 | "Killing program forcefully.\n"); 215 | vendor_deinit(); 216 | exit(1); 217 | } 218 | #endif /* CONFIG_NATIVE_WINDOWS */ 219 | 220 | 221 | static void eloop_handle_signal(int sig) 222 | { 223 | int i; 224 | 225 | #ifndef CONFIG_NATIVE_WINDOWS 226 | if ((sig == SIGINT || sig == SIGTERM) && !eloop.pending_terminate) { 227 | /* Use SIGALRM to break out from potential busy loops that 228 | * would not allow the program to be killed. */ 229 | eloop.pending_terminate = 1; 230 | signal(SIGALRM, eloop_handle_alarm); 231 | alarm(2); 232 | } 233 | #endif /* CONFIG_NATIVE_WINDOWS */ 234 | 235 | eloop.signaled++; 236 | for (i = 0; i < eloop.signal_count; i++) { 237 | if (eloop.signals[i].sig == sig) { 238 | eloop.signals[i].signaled++; 239 | break; 240 | } 241 | } 242 | } 243 | 244 | 245 | static void eloop_process_pending_signals(void) 246 | { 247 | int i; 248 | 249 | if (eloop.signaled == 0) 250 | return; 251 | eloop.signaled = 0; 252 | 253 | if (eloop.pending_terminate) { 254 | #ifndef CONFIG_NATIVE_WINDOWS 255 | alarm(0); 256 | #endif /* CONFIG_NATIVE_WINDOWS */ 257 | eloop.pending_terminate = 0; 258 | } 259 | 260 | for (i = 0; i < eloop.signal_count; i++) { 261 | if (eloop.signals[i].signaled) { 262 | eloop.signals[i].signaled = 0; 263 | eloop.signals[i].handler(eloop.signals[i].sig, 264 | eloop.user_data, 265 | eloop.signals[i].user_data); 266 | } 267 | } 268 | } 269 | 270 | 271 | int eloop_register_signal(int sig, 272 | void (*handler)(int sig, void *eloop_ctx, 273 | void *signal_ctx), 274 | void *user_data) 275 | { 276 | struct eloop_signal *tmp; 277 | 278 | tmp = (struct eloop_signal *) 279 | realloc(eloop.signals, 280 | (eloop.signal_count + 1) * 281 | sizeof(struct eloop_signal)); 282 | if (tmp == NULL) 283 | return -1; 284 | 285 | tmp[eloop.signal_count].sig = sig; 286 | tmp[eloop.signal_count].user_data = user_data; 287 | tmp[eloop.signal_count].handler = handler; 288 | tmp[eloop.signal_count].signaled = 0; 289 | eloop.signal_count++; 290 | eloop.signals = tmp; 291 | signal(sig, eloop_handle_signal); 292 | 293 | return 0; 294 | } 295 | 296 | 297 | void eloop_run(void) 298 | { 299 | fd_set *rfds; 300 | int i, res; 301 | struct timeval tv, now; 302 | 303 | rfds = malloc(sizeof(*rfds)); 304 | if (rfds == NULL) { 305 | printf("eloop_run - malloc failed\n"); 306 | return; 307 | } 308 | 309 | while (!eloop.terminate && 310 | (eloop.timeout || eloop.reader_count > 0)) { 311 | if (eloop.timeout) { 312 | gettimeofday(&now, NULL); 313 | if (timercmp(&now, &eloop.timeout->time, <)) 314 | timersub(&eloop.timeout->time, &now, &tv); 315 | else 316 | tv.tv_sec = tv.tv_usec = 0; 317 | #if 0 318 | printf("next timeout in %lu.%06lu sec\n", 319 | tv.tv_sec, tv.tv_usec); 320 | #endif 321 | } 322 | 323 | FD_ZERO(rfds); 324 | for (i = 0; i < eloop.reader_count; i++) 325 | FD_SET(eloop.readers[i].sock, rfds); 326 | res = select(eloop.max_sock + 1, rfds, NULL, NULL, 327 | eloop.timeout ? &tv : NULL); 328 | if (res < 0 && errno != EINTR) { 329 | perror("select"); 330 | free(rfds); 331 | return; 332 | } 333 | eloop_process_pending_signals(); 334 | 335 | /* check if some registered timeouts have occurred */ 336 | if (eloop.timeout) { 337 | struct eloop_timeout *tmp; 338 | 339 | gettimeofday(&now, NULL); 340 | if (!timercmp(&now, &eloop.timeout->time, <)) { 341 | tmp = eloop.timeout; 342 | eloop.timeout = eloop.timeout->next; 343 | tmp->handler(tmp->eloop_data, 344 | tmp->user_data); 345 | free(tmp); 346 | } 347 | 348 | } 349 | 350 | if (res <= 0) 351 | continue; 352 | 353 | for (i = 0; i < eloop.reader_count; i++) { 354 | if (FD_ISSET(eloop.readers[i].sock, rfds)) { 355 | eloop.readers[i].handler( 356 | eloop.readers[i].sock, 357 | eloop.readers[i].eloop_data, 358 | eloop.readers[i].user_data); 359 | } 360 | } 361 | } 362 | 363 | free(rfds); 364 | } 365 | 366 | 367 | void eloop_terminate(void) 368 | { 369 | eloop.terminate = 1; 370 | } 371 | 372 | 373 | void eloop_destroy(void) 374 | { 375 | struct eloop_timeout *timeout, *prev; 376 | 377 | timeout = eloop.timeout; 378 | while (timeout != NULL) { 379 | prev = timeout; 380 | timeout = timeout->next; 381 | free(prev); 382 | } 383 | free(eloop.readers); 384 | free(eloop.signals); 385 | } 386 | 387 | 388 | int eloop_terminated(void) 389 | { 390 | return eloop.terminate; 391 | } 392 | -------------------------------------------------------------------------------- /eloop.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Event loop 3 | * Copyright (c) 2002-2005, Jouni Malinen 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License version 2 as 7 | * published by the Free Software Foundation. 8 | * 9 | * Alternatively, this software may be distributed under the terms of BSD 10 | * license. 11 | * 12 | * See README and COPYING for more details. 13 | * 14 | * This file defines an event loop interface that supports processing events 15 | * from registered timeouts (i.e., do something after N seconds), sockets 16 | * (e.g., a new packet available for reading), and signals. eloop.c is an 17 | * implementation of this interface using select() and sockets. This is 18 | * suitable for most UNIX/POSIX systems. When porting to other operating 19 | * systems, it may be necessary to replace that implementation with OS specific 20 | * mechanisms. 21 | */ 22 | 23 | #ifndef ELOOP_H 24 | #define ELOOP_H 25 | 26 | /* Magic number for eloop_cancel_timeout() */ 27 | #define ELOOP_ALL_CTX (void *) -1 28 | 29 | /** 30 | * eloop_init() - Initialize global event loop data 31 | * @user_data: Pointer to global data passed as eloop_ctx to signal handlers 32 | * 33 | * This function must be called before any other eloop_* function. user_data 34 | * can be used to configure a global (to the process) pointer that will be 35 | * passed as eloop_ctx parameter to signal handlers. 36 | */ 37 | void eloop_init(void *user_data); 38 | 39 | /** 40 | * eloop_register_read_sock - Register handler for read events 41 | * @sock: File descriptor number for the socket 42 | * @handler: Callback function to be called when data is available for reading 43 | * @eloop_data: Callback context data (eloop_ctx) 44 | * @user_data: Callback context data (sock_ctx) 45 | * Returns: 0 on success, -1 on failure 46 | * 47 | * Register a read socket notifier for the given file descriptor. The handler 48 | * function will be called whenever data is available for reading from the 49 | * socket. 50 | */ 51 | int eloop_register_read_sock(int sock, 52 | void (*handler)(int sock, void *eloop_ctx, 53 | void *sock_ctx), 54 | void *eloop_data, void *user_data); 55 | 56 | /** 57 | * eloop_unregister_read_sock - Unregister handler for read events 58 | * @sock: File descriptor number for the socket 59 | * 60 | * Unregister a read socket notifier that was previously registered with 61 | * eloop_register_read_sock(). 62 | */ 63 | void eloop_unregister_read_sock(int sock); 64 | 65 | /** 66 | * eloop_register_timeout - Register timeout 67 | * @secs: Number of seconds to the timeout 68 | * @usecs: Number of microseconds to the timeout 69 | * @handler: Callback function to be called when timeout occurs 70 | * @eloop_data: Callback context data (eloop_ctx) 71 | * @user_data: Callback context data (sock_ctx) 72 | * Returns: 0 on success, -1 on failure 73 | * 74 | * Register a timeout that will cause the handler function to be called after 75 | * given time. 76 | */ 77 | int eloop_register_timeout(unsigned int secs, unsigned int usecs, 78 | void (*handler)(void *eloop_ctx, void *timeout_ctx), 79 | void *eloop_data, void *user_data); 80 | 81 | /** 82 | * eloop_cancel_timeout - Cancel timeouts 83 | * @handler: Matching callback function 84 | * @eloop_data: Matching eloop_data or %ELOOP_ALL_CTX to match all 85 | * @user_data: Matching user_data or %ELOOP_ALL_CTX to match all 86 | * Returns: Number of cancelled timeouts 87 | * 88 | * Cancel matching timeouts registered with 89 | * eloop_register_timeout(). ELOOP_ALL_CTX can be used as a wildcard for 90 | * cancelling all timeouts regardless of eloop_data/user_data. 91 | */ 92 | int eloop_cancel_timeout(void (*handler)(void *eloop_ctx, void *sock_ctx), 93 | void *eloop_data, void *user_data); 94 | 95 | /** 96 | * eloop_register_signal - Register handler for signals 97 | * @sig: Signal number (e.g., SIGHUP) 98 | * @handler: Callback function to be called when the signal is received 99 | * @user_data: Callback context data (signal_ctx) 100 | * Returns: 0 on success, -1 on failure 101 | * 102 | * Register a callback function that will be called when a signal is received. 103 | * The calback function is actually called only after the system signal handler 104 | * has returned. This means that the normal limits for sighandlers (i.e., only 105 | * "safe functions" allowed) do not apply for the registered callback. 106 | * 107 | * Signals are 'global' events and there is no local eloop_data pointer like 108 | * with other handlers. The global user_data pointer registered with 109 | * eloop_init() will be used as eloop_ctx for signal handlers. 110 | */ 111 | int eloop_register_signal(int sig, 112 | void (*handler)(int sig, void *eloop_ctx, 113 | void *signal_ctx), 114 | void *user_data); 115 | 116 | /** 117 | * eloop_run - Start the event loop 118 | * 119 | * Start the event loop and continue running as long as there are any 120 | * registered event handlers. This function is run after event loop has been 121 | * initialized with event_init() and one or more events have been registered. 122 | */ 123 | void eloop_run(void); 124 | 125 | /** 126 | * eloop_terminate - Terminate event loop 127 | * 128 | * Terminate event loop even if there are registered events. This can be used 129 | * to request the program to be terminated cleanly. 130 | */ 131 | void eloop_terminate(void); 132 | 133 | /** 134 | * eloop_destroy - Free any resources allocated for the event loop 135 | * 136 | * After calling eloop_destoy(), other eloop_* functions must not be called 137 | * before re-running eloop_init(). 138 | */ 139 | void eloop_destroy(void); 140 | 141 | /** 142 | * eloop_terminated - Check whether event loop has been terminated 143 | * Returns: 1 = event loop terminate, 0 = event loop still running 144 | * 145 | * This function can be used to check whether eloop_terminate() has been called 146 | * to request termination of the event loop. This is normally used to abort 147 | * operations that may still be queued to be run when eloop_terminate() was 148 | * called. 149 | */ 150 | int eloop_terminated(void); 151 | 152 | #endif /* ELOOP_H */ 153 | -------------------------------------------------------------------------------- /hs2_profile.h: -------------------------------------------------------------------------------- 1 | 2 | /* Copyright (c) 2021 Wi-Fi Alliance */ 3 | 4 | /* Permission to use, copy, modify, and/or distribute this software for any */ 5 | /* purpose with or without fee is hereby granted, provided that the above */ 6 | /* copyright notice and this permission notice appear in all copies. */ 7 | 8 | /* THE SOFTWARE IS PROVIDED 'AS IS' AND THE AUTHOR DISCLAIMS ALL */ 9 | /* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED */ 10 | /* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL */ 11 | /* THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR */ 12 | /* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING */ 13 | /* FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF */ 14 | /* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT */ 15 | /* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS */ 16 | /* SOFTWARE. */ 17 | 18 | #ifndef _HS2_PROFILE 19 | #define _HS2_PROFILE 20 | 21 | #define ARRAY_SIZE(x) ((sizeof x) / (sizeof *x)) 22 | 23 | struct tlv_to_profile { 24 | unsigned short tlv_id; 25 | const char **profile; 26 | int size; 27 | }; 28 | 29 | #define ADVICE_OF_CHARGE_1 \ 30 | "bc01000000d200454e475553443c3f786d6c2076657273696f6e3d22312e30222065" \ 31 | "6e636f64696e673d225554462d38223f3e3c506c616e20786d6c6e733d22687474703a2f2f77" \ 32 | "77772e77692d66692e6f72672f73706563696669636174696f6e732f686f7473706f7432646f" \ 33 | "74302f76312e302f616f637069223e3c4465736372697074696f6e3e57692d46692061636365" \ 34 | "737320666f72203120686f75722c207768696c6520796f752077616974206174207468652067" \ 35 | "6174652c2024302e39393c2f4465736372697074696f6e3e3c2f506c616e3ee3004652414341" \ 36 | "443c3f786d6c2076657273696f6e3d22312e302220656e636f64696e673d225554462d38223f" \ 37 | "3e3c506c616e20786d6c6e733d22687474703a2f2f7777772e77692d66692e6f72672f737065" \ 38 | "63696669636174696f6e732f686f7473706f7432646f74302f76312e302f616f637069223e3c" \ 39 | "4465736372697074696f6e3e416363c3a8732057692d46692070656e64616e74203120686575" \ 40 | "72652c2070656e64616e742071756520766f757320617474656e64657a20c3a0206c6120706f" \ 41 | "7274652c20302c393920243c2f4465736372697074696f6e3e3c2f506c616e3ea101010000c7" \ 42 | "00454e475553443c3f786d6c2076657273696f6e3d22312e302220656e636f64696e673d2255" \ 43 | "54462d38223f3e3c506c616e20786d6c6e733d22687474703a2f2f7777772e77692d66692e6f" \ 44 | "72672f73706563696669636174696f6e732f686f7473706f7432646f74302f76312e302f616f" \ 45 | "637069223e3c4465736372697074696f6e3e446f776e6c6f616420766964656f7320666f7220" \ 46 | "796f757220666c696768742c2024322e393920666f7220313047423c2f446573637269707469" \ 47 | "6f6e3e3c2f506c616e3ed3004652414341443c3f786d6c2076657273696f6e3d22312e302220" \ 48 | "656e636f64696e673d225554462d38223f3e3c506c616e20786d6c6e733d22687474703a2f2f" \ 49 | "7777772e77692d66692e6f72672f73706563696669636174696f6e732f686f7473706f743264" \ 50 | "6f74302f76312e302f616f637069223e3c4465736372697074696f6e3e54c3a96cc3a9636861" \ 51 | "7267657a2064657320766964c3a96f7320706f757220766f74726520766f6c2c20322c393920" \ 52 | "2420706f757220313020476f3c2f4465736372697074696f6e3e3c2f506c616e3ee40003002b" \ 53 | "736572766963652d70726f76696465722e636f6d3b66656465726174696f6e2e6578616d706c" \ 54 | "652e636f6db400454e475553443c3f786d6c2076657273696f6e3d22312e302220656e636f64" \ 55 | "696e673d225554462d38223f3e3c506c616e20786d6c6e733d22687474703a2f2f7777772e77" \ 56 | "692d66692e6f72672f73706563696669636174696f6e732f686f7473706f7432646f74302f76" \ 57 | "312e302f616f637069223e3c4465736372697074696f6e3e46726565207769746820796f7572" \ 58 | "20737562736372697074696f6e213c2f4465736372697074696f6e3e3c2f506c616e3e" 59 | 60 | const char * nai_realm[] = { 61 | "", 62 | "nai_realm=0,mail.example.com,21[2:4][5:7]\nnai_realm=0,cisco.com,21[2:4][5:7]\nnai_realm=0,wi-fi.org,13[5:6],21[2:4][5:7]\nnai_realm=0,example.com,13[5:6]\n", 63 | "nai_realm=0,wi-fi.org,21[2:4][5:7]\n", 64 | "nai_realm=0,cisco.com,21[2:4][5:7]\nnai_realm=0,wi-fi.org,13[5:6],21[2:4][5:7]\nnai_realm=0,example.com,13[5:6]\n", 65 | "nai_realm=0,mail.example.com,13[5:6],21[2:4][5:7]\n", 66 | "nai_realm=0,wi-fi.org,21[2:4][5:7]\nnai_realm=0,ruckuswireless.com,21[2:4][5:7]\n", 67 | "nai_realm=0,wi-fi.org,21[2:4][5:7]\nnai_realm=0,mail.example.com,21[2:4][5:7]\n", 68 | "nai_realm=0,wi-fi.org,13[5:6],21[2:4][5:7]\n", 69 | }; 70 | 71 | const char * oper_friendly_name[] = { 72 | "", 73 | "hs20_oper_friendly_name=eng:Wi-Fi Alliance\nhs20_oper_friendly_name=chi:Wi-Fi联盟\n", 74 | }; 75 | 76 | const char * venue_name[] = { 77 | "", 78 | "venue_name=eng:Wi-Fi Alliance 3408 Garrett Drive Santa Clara, CA 950514, USA\nvenue_name=chi:Wi-Fi聯盟實驗室 三四零八 加洛路 聖克拉拉, 加利福尼亞 950514, 美國\n", 79 | "", 80 | "", 81 | }; 82 | 83 | const char * network_auth_type[] = { 84 | "", 85 | "network_auth_type=00https://tandc-server.wi-fi.org\n", 86 | "network_auth_type=01\n", 87 | }; 88 | 89 | const char * ipaddr_type_avail[] = { 90 | "", 91 | "ipaddr_type_availability=0c\n", 92 | }; 93 | 94 | const char * hs20_wan_metrics[] = { 95 | "", 96 | "hs20_wan_metrics=01:2500:384:0:0:10\n", 97 | "hs20_wan_metrics=01:1500:384:20:20:10\n", 98 | "hs20_wan_metrics=01:2000:1000:20:20:10\n", 99 | "hs20_wan_metrics=01:8000:1000:20:20:10\n", 100 | "hs20_wan_metrics=01:9000:5000:20:20:10\n", 101 | }; 102 | 103 | const char * hs20_conn_capab[] = { 104 | "", 105 | "hs20_conn_capab=6:20:1\nhs20_conn_capab=6:80:1\nhs20_conn_capab=6:443:1\nhs20_conn_capab=17:500:1\nhs20_conn_capab=50:0:1\n", 106 | "", 107 | "hs20_conn_capab=6:80:1\nhs20_conn_capab=6:443:1\n", 108 | "hs20_conn_capab=6:80:1\nhs20_conn_capab=6:443:1\nhs20_conn_capab=6:5060:1\nhs20_conn_capab=17:5060:1\n", 109 | "", 110 | }; 111 | 112 | const char * operating_class_indication[] = { 113 | "", 114 | "hs20_operating_class=51\n", 115 | "hs20_operating_class=73\n", 116 | "hs20_operating_class=5173\n", 117 | }; 118 | 119 | const char * osu_providers_list[] = { 120 | "", 121 | "osu_ssid=\"OSU\"\nosu_server_uri=https://osu-server.r2-testbed.wi-fi.org/\nosu_friendly_name=eng:SP Red Test Only\nosu_friendly_name=kor:SP 빨강 테스트 전용\nosu_method_list=1\nosu_icon=icon_red_eng.png\nosu_icon=icon_red_zxx.png\nosu_service_desc=eng:Free service for test purpose\nosu_service_desc=kor:테스트 목적으로 무료 서비스\n", 122 | "", 123 | "", 124 | "", 125 | "", 126 | }; 127 | 128 | const char * osu_providers_nai_list[] = { 129 | "", 130 | "osu_nai2=anonymous@hotspot.net\n", 131 | "", 132 | "", 133 | "", 134 | }; 135 | 136 | const char * bss_load[] = { 137 | "", 138 | "bss_load_test=1:50:65535\n", 139 | "bss_load_test=1:200:65535\n", 140 | "bss_load_test=1:75:65535\n", 141 | }; 142 | 143 | const char * venue_url[] = { 144 | "", 145 | "venue_url=1:https://venue-server.r2m-testbed.wi-fi.org/floorplans/index.html\nvenue_url=1:https://venue-server.r2m-testbed.wi-fi.org/directory/index.html\n", 146 | "", 147 | }; 148 | 149 | const char * operator_icon_metadata[] = { 150 | "", 151 | "operator_icon=icon_red_eng.png\n", 152 | }; 153 | 154 | const char * advice_of_charge[] = { 155 | "", 156 | "anqp_elem=278:" ADVICE_OF_CHARGE_1 "\n", 157 | }; 158 | 159 | // ::::: 160 | const char * hs20_icon[] = { 161 | "hs20_icon=160:76:eng:image/png:icon_red_eng.png:/overlay/passpoint/icon_red_eng.png\n", 162 | "hs20_icon=128:61:zxx:image/png:icon_red_zxx.png:/overlay/passpoint/icon_red_zxx.png\n", 163 | }; 164 | 165 | struct tlv_to_profile hs2_profile[] = { 166 | { TLV_VENUE_NAME, venue_name, ARRAY_SIZE(venue_name) }, 167 | { TLV_NAI_REALM, nai_realm, ARRAY_SIZE(nai_realm) }, 168 | { TLV_HS20_OPERATOR_FRIENDLY_NAME, oper_friendly_name, ARRAY_SIZE(oper_friendly_name) }, 169 | { TLV_NETWORK_AUTH_TYPE, network_auth_type, ARRAY_SIZE(network_auth_type) }, 170 | { TLV_IPADDR_TYPE_AVAILABILITY, ipaddr_type_avail, ARRAY_SIZE(ipaddr_type_avail) }, 171 | { TLV_HS20_WAN_METRICS, hs20_wan_metrics, ARRAY_SIZE(hs20_wan_metrics) }, 172 | { TLV_HS20_CONN_CAPABILITY, hs20_conn_capab, ARRAY_SIZE(hs20_conn_capab) }, 173 | { TLV_OSU_PROVIDERS_LIST, osu_providers_list, ARRAY_SIZE(osu_providers_list) }, 174 | { TLV_OSU_PROVIDERS_NAI_LIST, osu_providers_nai_list, ARRAY_SIZE(osu_providers_nai_list) }, 175 | { TLV_VENUE_URL, venue_url, ARRAY_SIZE(venue_url) }, 176 | { TLV_BSSLOAD_ENABLE, bss_load, ARRAY_SIZE(bss_load) }, 177 | { TLV_OPERATOR_ICON_METADATA, operator_icon_metadata, ARRAY_SIZE(operator_icon_metadata) }, 178 | { TLV_HS20_OPERATING_CLASS_INDICATION, operating_class_indication, ARRAY_SIZE(operating_class_indication) }, 179 | { TLV_ADVICE_OF_CHARGE, advice_of_charge, ARRAY_SIZE(advice_of_charge) }, 180 | }; 181 | 182 | struct tlv_to_profile* find_tlv_hs2_profile(int tlv_id) { 183 | int i; 184 | for (i = 0; i < ARRAY_SIZE(hs2_profile); i++) { 185 | if (tlv_id == hs2_profile[i].tlv_id) { 186 | return &hs2_profile[i]; 187 | } 188 | } 189 | return NULL; 190 | } 191 | 192 | void attach_hs20_icons(char * buffer) { 193 | int i; 194 | for (i = 0; i < ARRAY_SIZE(hs20_icon); i++) { 195 | strcat(buffer, hs20_icon[i]); 196 | } 197 | return; 198 | } 199 | 200 | #endif // _HS2_PROFILE -------------------------------------------------------------------------------- /indigo_api.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2020 Wi-Fi Alliance */ 2 | 3 | /* Permission to use, copy, modify, and/or distribute this software for any */ 4 | /* purpose with or without fee is hereby granted, provided that the above */ 5 | /* copyright notice and this permission notice appear in all copies. */ 6 | 7 | /* THE SOFTWARE IS PROVIDED 'AS IS' AND THE AUTHOR DISCLAIMS ALL */ 8 | /* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED */ 9 | /* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL */ 10 | /* THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR */ 11 | /* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING */ 12 | /* FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF */ 13 | /* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT */ 14 | /* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS */ 15 | /* SOFTWARE. */ 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | #include "vendor_specific.h" 22 | #include "indigo_api.h" 23 | #include "utils.h" 24 | 25 | /* Structure to initiate the API list and handlers */ 26 | struct indigo_api indigo_api_list[] = { 27 | /* Common */ 28 | { API_CMD_RESPONSE, "CMD_RESPONSE", NULL, NULL }, 29 | { API_CMD_ACK, "CMD_ACK", NULL, NULL }, 30 | /* AP specific */ 31 | { API_AP_START_UP, "AP_START_UP", NULL, NULL }, 32 | { API_AP_STOP, "AP_STOP", NULL, NULL }, 33 | { API_AP_CONFIGURE, "AP_CONFIGURE", NULL, NULL }, 34 | { API_AP_TRIGGER_CHANSWITCH, "AP_TRIGGER_CHANSWITCH", NULL, NULL }, 35 | { API_AP_SEND_DISCONNECT, "AP_SEND_DISCONNECT", NULL, NULL }, 36 | { API_AP_SET_PARAM, "API_AP_SET_PARAM", NULL, NULL }, 37 | { API_AP_SEND_BTM_REQ, "API_AP_SEND_BTM_REQ", NULL, NULL }, 38 | { API_AP_SEND_ARP_MSGS, "API_AP_SEND_ARP_MSGS", NULL, NULL }, 39 | { API_AP_START_WPS, "AP_START_WPS", NULL, NULL }, 40 | { API_AP_CONFIGURE_WSC, "AP_CONFIGURE_WSC", NULL, NULL }, 41 | { API_AP_REKEY_GTK, "AP_REKEY_GTK", NULL, NULL }, 42 | /* Station specific */ 43 | { API_STA_START_UP, "STA_START_UP", NULL, NULL }, 44 | { API_STA_ASSOCIATE, "STA_ASSOCIATE", NULL, NULL }, 45 | { API_STA_CONFIGURE, "STA_CONFIGURE", NULL, NULL }, 46 | { API_STA_DISCONNECT, "STA_DISCONNECT", NULL, NULL }, 47 | { API_STA_SEND_DISCONNECT, "STA_SEND_DISCONNECT", NULL, NULL }, 48 | { API_STA_REASSOCIATE, "STA_REASSOCIATE", NULL, NULL }, 49 | { API_STA_SET_PARAM, "STA_SET_PARAM", NULL, NULL }, 50 | { API_STA_SEND_BTM_QUERY, "STA_SEND_BTM_QUERY", NULL, NULL }, 51 | { API_STA_SEND_ANQP_QUERY, "STA_SEND_ANQP_QUERY", NULL, NULL }, 52 | { API_STA_SET_PHY_MODE, "STA_SET_PHY_MODE", NULL, NULL }, 53 | { API_STA_SET_CHANNEL_WIDTH, "STA_SET_CHANNEL_WIDTH", NULL, NULL }, 54 | { API_STA_POWER_SAVE, "STA_POWER_SAVE", NULL, NULL }, 55 | { API_STA_SCAN, "STA_SCAN", NULL, NULL }, 56 | { API_STA_HS2_ASSOCIATE, "API_STA_HS2_ASSOCIATE", NULL, NULL }, 57 | { API_STA_INSTALL_PPSMO, "API_STA_INSTALL_PPSMO", NULL, NULL }, 58 | { API_P2P_START_UP, "P2P_START_UP", NULL, NULL }, 59 | { API_P2P_FIND, "P2P_FIND", NULL, NULL }, 60 | { API_P2P_LISTEN, "P2P_LISTEN", NULL, NULL }, 61 | { API_P2P_ADD_GROUP, "P2P_ADD_GROUP", NULL, NULL }, 62 | { API_P2P_START_WPS, "P2P_START_WPS", NULL, NULL }, 63 | { API_P2P_CONNECT, "P2P_CONNECT", NULL, NULL }, 64 | { API_STA_ADD_CREDENTIAL, "API_STA_ADD_CREDENTIAL", NULL, NULL }, 65 | { API_P2P_GET_INTENT_VALUE, "P2P_GET_INTENT_VALUE", NULL, NULL }, 66 | { API_STA_START_WPS, "STA_START_WPS", NULL, NULL }, 67 | { API_P2P_INVITE, "P2P_INVITE", NULL, NULL }, 68 | { API_P2P_STOP_GROUP, "P2P_STOP_GROUP", NULL, NULL }, 69 | { API_P2P_SET_SERV_DISC, "P2P_SET_SERV_DISC", NULL, NULL }, 70 | { API_STA_SEND_ICON_REQ, "STA_SEND_ICON_REQ", NULL, NULL }, 71 | { API_P2P_SET_EXT_LISTEN, "P2P_SET_EXT_LISTEN", NULL, NULL }, 72 | { API_STA_ENABLE_WSC, "STA_ENABLE_WSC", NULL, NULL }, 73 | { API_STA_INJECT_START, "STA_INJECT_START", NULL, NULL }, 74 | { API_STA_INJECT_FRAME, "STA_INJECT_FRAME", NULL, NULL }, 75 | { API_STA_INJECT_STOP, "STA_INJECT_STOP", NULL, NULL }, 76 | { API_SNIFFER_START, "SNIFFER_START", NULL, NULL }, 77 | { API_SNIFFER_STOP, "SNIFFER_STOP", NULL, NULL }, 78 | { API_SNIFFER_UPLOAD_FILE, "SNIFFER_UPLOAD_FILE", NULL, NULL }, 79 | { API_SNIFFER_FILTER, "SNIFFER_FILTER", NULL, NULL }, 80 | /* Network operation. E.g., get/set IP address, get MAC address, send the UDP data and reset */ 81 | { API_GET_IP_ADDR, "GET_IP_ADDR", NULL, NULL }, 82 | { API_GET_MAC_ADDR, "GET_MAC_ADDR", NULL, NULL }, 83 | { API_GET_CONTROL_APP_VERSION, "GET_CONTROL_APP_VERSION", NULL, NULL }, 84 | { API_START_LOOP_BACK_SERVER, "START_LOOP_BACK_SERVER", NULL, NULL }, 85 | { API_STOP_LOOP_BACK_SERVER, "STOP_LOOP_BACK_SERVER", NULL, NULL }, 86 | { API_CREATE_NEW_INTERFACE_BRIDGE_NETWORK, "CREATE_NEW_INTERFACE_BRIDGE_NETWORK", NULL, NULL }, 87 | { API_ASSIGN_STATIC_IP, "ASSIGN_STATIC_IP", NULL, NULL }, 88 | { API_DEVICE_RESET, "DEVICE_RESET", NULL, NULL }, 89 | { API_SEND_LOOP_BACK_DATA, "SEND_LOOP_BACK_DATA", NULL, NULL }, 90 | { API_STOP_LOOP_BACK_DATA, "STOP_LOOP_BACK_DATA", NULL, NULL }, 91 | { API_START_DHCP, "START_DHCP", NULL, NULL }, 92 | { API_STOP_DHCP, "STOP_DHCP", NULL, NULL }, 93 | { API_GET_WSC_PIN, "GET_WSC_PIN", NULL, NULL }, 94 | { API_GET_WSC_CRED, "GET_WSC_CRED", NULL, NULL }, 95 | }; 96 | 97 | /* Structure to declare the TLV list */ 98 | struct indigo_tlv indigo_tlv_list[] = { 99 | { TLV_SSID, "SSID" }, 100 | { TLV_CHANNEL, "CHANNEL" }, 101 | { TLV_WEP_KEY0, "WEP_KEY0" }, 102 | { TLV_AUTH_ALGORITHM, "AUTH_ALGORITHM" }, 103 | { TLV_WEP_DEFAULT_KEY, "WEP_DEFAULT_KEY" }, 104 | { TLV_IEEE80211_D, "IEEE80211_D" }, 105 | { TLV_IEEE80211_N, "IEEE80211_N" }, 106 | { TLV_IEEE80211_AC, "IEEE80211_AC" }, 107 | { TLV_COUNTRY_CODE, "COUNTRY_CODE" }, 108 | { TLV_WMM_ENABLED, "WMM_ENABLED" }, 109 | { TLV_WPA, "WPA" }, 110 | { TLV_WPA_KEY_MGMT, "WPA_KEY_MGMT" }, 111 | { TLV_RSN_PAIRWISE, "RSN_PAIRWISE" }, 112 | { TLV_WPA_PASSPHRASE, "WPA_PASSPHRASE" }, 113 | { TLV_WPA_PAIRWISE, "WPA_PAIRWISE" }, 114 | { TLV_HT_CAPB, "HT_CAPB" }, 115 | { TLV_IEEE80211_H, "IEEE80211_H" }, 116 | { TLV_IEEE80211_W, "IEEE80211_W" }, 117 | { TLV_VHT_OPER_CHWIDTH, "VHT_OPER_CHWIDTH" }, 118 | { TLV_VHT_CAPB, "VHT_CAPB" }, 119 | { TLV_IEEE8021_X, "IEEE8021_X" }, 120 | { TLV_EAP_SERVER, "EAP_SERVER" }, 121 | { TLV_AUTH_SERVER_ADDR, "AUTH_SERVER_ADDR" }, 122 | { TLV_AUTH_SERVER_PORT, "AUTH_SERVER_PORT" }, 123 | { TLV_AUTH_SERVER_SHARED_SECRET, "AUTH_SERVER_SHARED_SECRET" }, 124 | { TLV_INTERFACE_NAME, "INTERFACE_NAME" }, 125 | { TLV_NEW_INTERFACE_NAME, "NEW_INTERFACE_NAME" }, 126 | { TLV_FREQUENCY, "FREQUENCY" }, 127 | { TLV_BSS_IDENTIFIER, "BSS_IDENTIFIER" }, 128 | { TLV_HW_MODE, "HW_MODE" }, 129 | { TLV_VHT_OPER_CENTR_FREQ, "VHT_OPER_CENTR_FREQ" }, 130 | { TLV_RESET_TYPE, "RESET_TYPE" }, 131 | { APP_TYPE, "APP_TYPE" }, 132 | { TLV_IE_OVERRIDE, "IE_OVERRIDE" }, 133 | { TLV_HOME_FQDN, "HOME_FQDN"}, 134 | { TLV_USERNAME, "USERNAME"}, 135 | { TLV_PREFER, "PREFER"}, 136 | { TLV_CREDENTIAL_TYPE, "CREDENTIAL_TYPE"}, 137 | { TLV_ADDRESS, "ADDRESS" }, 138 | { TLV_DISABLE_PMKSA_CACHING, "DISABLE_PMKSA_CACHING" }, 139 | { TLV_SAE_ANTI_CLOGGING_THRESHOLD, "SAE_ANTI_CLOGGING_THRESHOLD" }, 140 | { TLV_STA_SSID, "STA_SSID" }, 141 | { TLV_KEY_MGMT, "KEY_MGMT" }, 142 | { TLV_STA_WEP_KEY0, "STA_WEP_KEY0" }, 143 | { TLV_WEP_TX_KEYIDX, "WEP_TX_KEYIDX" }, 144 | { TLV_GROUP, "GROUP" }, 145 | { TLV_PSK, "PSK" }, 146 | { TLV_PROTO, "PROTO" }, 147 | { TLV_STA_IEEE80211_W, "STA_IEEE80211_W" }, 148 | { TLV_PAIRWISE, "PAIRWISE" }, 149 | { TLV_EAP, "EAP" }, 150 | { TLV_PHASE2, "PHASE2" }, 151 | { TLV_IDENTITY, "IDENTITY" }, 152 | { TLV_PASSWORD, "PASSWORD" }, 153 | { TLV_CA_CERT, "CA_CERT" }, 154 | { TLV_PHASE1, "PHASE1" }, 155 | { TLV_CLIENT_CERT, "CLIENT_CERT" }, 156 | { TLV_PRIVATE_KEY, "PRIVATE_KEY" }, 157 | { TLV_EAPOL_M3_ELEMENTS, "EAPOL_M3_ELEMENTS" }, 158 | { TLV_GTK_KDE_RANDOM_RESERVED_BITS, "GTK_KDE_RANDOM_RESERVED_BITS" }, 159 | { TLV_STA_POWER_SAVE, "STA_POWER_SAVE" }, 160 | { TLV_STATIC_IP, "STATIC_IP" }, 161 | { TLV_DEBUG_LEVEL, "DEBUG_LEVEL" }, 162 | { TLV_DUT_IP_ADDRESS, "DUT_IP_ADDRESS" }, 163 | { TLV_HOSTAPD_FILE_NAME, "HOSTAPD_FILE_NAME" }, 164 | { TLV_ROLE, "ROLE" }, 165 | { TLV_BAND, "BAND" }, 166 | { TLV_BSSID, "BSSID" }, 167 | { TLV_ARP_TRANSMISSION_RATE, "ARP_TRANSMISSION_RATE" }, 168 | { TLV_ARP_TARGET_IP, "ARP_TARGET_IP" }, 169 | { TLV_ARP_FRAME_COUNT, "ARP_FRAME_COUNT" }, 170 | { TLV_FRAME_TYPE, "FRAME_TYPE" }, 171 | { TLV_ACTION_CATEGORY, "ACTION_CATEGORY" }, 172 | { TLV_ACTION_CODE, "ACTION_CODE" }, 173 | { TLV_PACKET_COUNT, "PACKET_COUNT" }, 174 | { TLV_PACKET_TYPE, "PACKET_TYPE" }, 175 | { TLV_PACKET_RATE, "PACKET_RATE" }, 176 | { TLV_PHYMODE, "PHYMODE" }, 177 | { TLV_CHANNEL_WIDTH, "CHANNEL_WIDTH" }, 178 | { TLV_PAC_FILE, "PAC_FILE" }, 179 | { TLV_STA_SAE_GROUPS, "STA_SAE_GROUPS" }, 180 | { TLV_SAE_GROUPS, "SAE_GROUPS" }, 181 | { TLV_IEEE80211_AX, "IEEE80211_AX" }, 182 | { TLV_HE_OPER_CHWIDTH, "HE_OPER_CHWIDTH" }, 183 | { TLV_HE_OPER_CENTR_FREQ, "HE_OPER_CENTR_FREQ" }, 184 | { TLV_MBO, "MBO" }, 185 | { TLV_MBO_CELL_DATA_CONN_PREF, "MBO_CELL_DATA_CONN_PREF" }, 186 | { TLV_BSS_TRANSITION, "BSS_TRANSITION" }, 187 | { TLV_INTERWORKING, "INTERWORKING" }, 188 | { TLV_RRM_NEIGHBOR_REPORT, "RRM_NEIGHBOR_REPORT" }, 189 | { TLV_RRM_BEACON_REPORT, "RRM_BEACON_REPORT" }, 190 | { TLV_COUNTRY3, "COUNTRY3" }, 191 | { TLV_MBO_CELL_CAPA, "MBO_CELL_CAPA" }, 192 | { TLV_DOMAIN_MATCH, "TLV_DOMAIN_MATCH" }, 193 | { TLV_DOMAIN_SUFFIX_MATCH, "TLV_DOMAIN_SUFFIX_MATCH" }, 194 | { TLV_MBO_ASSOC_DISALLOW, "TLV_MBO_ASSOC_DISALLOW" }, 195 | { TLV_DISASSOC_IMMINENT, "TLV_DISASSOC_IMMINENT" }, 196 | { TLV_BSS_TERMINATION, "TLV_BSS_TERMINATION" }, 197 | { TLV_DISASSOC_TIMER, "TLV_DISASSOC_TIMER" }, 198 | { TLV_BSS_TERMINATION_TSF, "TLV_BSS_TERMINATION_TSF" }, 199 | { TLV_BSS_TERMINATION_DURATION, "TLV_BSS_TERMINATION_DURATION" }, 200 | { TLV_REASSOCIAITION_RETRY_DELAY, "TLV_REASSOCIAITION_RETRY_DELAY" }, 201 | { TLV_BTMQUERY_REASON_CODE, "TLV_BTMQUERY_REASON_CODE" }, 202 | { TLV_CANDIDATE_LIST, "TLV_CANDIDATE_LIST" }, 203 | { TLV_ANQP_INFO_ID, "TLV_ANQP_INFO_ID" }, 204 | { TLV_GAS_COMEBACK_DELAY, "TLV_GAS_COMEBACK_DELAY" }, 205 | { TLV_SAE_PWE, "TLV_SAE_PWE" }, 206 | { TLV_OWE_GROUPS, "TLV_OWE_GROUPS" }, 207 | { TLV_STA_OWE_GROUP, "TLV_STA_OWE_GROUP" }, 208 | { TLV_HE_MU_EDCA, "TLV_HE_MU_EDCA" }, 209 | { TLV_PROTECTION_TYPE, "PROTECTION_TYPE" }, 210 | { TLV_RSNXE_OVERRIDE_EAPOL, "TLV_RSNXE_OVERRIDE_EAPOL" }, 211 | { TLV_TRANSITION_DISABLE, "TLV_TRANSITION_DISABLE" }, 212 | { TLV_SAE_CONFIRM_IMMEDIATE, "SAE_CONFIRM_IMMEDIATE" }, 213 | { TLV_SERVER_CERT, "SERVER_CERT" }, 214 | { TLV_CONTROL_INTERFACE, "CONTROL_INTERFACE" }, 215 | { TLV_PACKET_SIZE, "PACKET_SIZE" }, 216 | { TLV_DUT_UDP_PORT, "DUT_UDP_PORT" }, 217 | { TLV_OWE_TRANSITION_BSS_IDENTIFIER, "OWE_TRANSITION_BSS_IDENTIFIER" }, 218 | { TLV_MESSAGE, "MESSAGE" }, 219 | { TLV_STATUS, "STATUS" }, 220 | { TLV_DUT_WLAN_IP_ADDR, "DUT_WLAN_IP_ADDR" }, 221 | { TLV_DUT_MAC_ADDR, "DUT_MAC_ADDR" }, 222 | { TLV_CONTROL_APP_VERSION, "CONTROL_APP_VERSION" }, 223 | { TLV_FREQ_LIST, "FREQ_LIST" }, 224 | { TLV_OP_CLASS, "OP_CLASS" }, 225 | { TLV_HE_6G_ONLY, "HE_6G_ONLY"}, 226 | { TLV_HE_UNSOL_PR_RESP_CADENCE, "UNSOL_PR_RESP_CADENCE" }, 227 | { TLV_HE_FILS_DISCOVERY_TX, "FILS_DISCOERY_TX" }, 228 | { TLV_SKIP_6G_BSS_SECURITY_CHECK, "SKIP_6G_BSS_SECURITY_CHECK" }, 229 | { TLV_RAND_MAC_ADDR, "RAND_MAC_ADDR" }, 230 | { TLV_PREASSOC_RAND_MAC_ADDR, "PREASSOC_RAND_MAC_ADDR" }, 231 | { TLV_RAND_ADDR_LIFETIME, "RAND_ADDR_LIFETIME" }, 232 | { TLV_HS20, "HS20" }, 233 | { TLV_ACCESS_NETWORK_TYPE, "ACCESS_NETWORK_TYPE" }, 234 | { TLV_INTERNET, "INTERNET" }, 235 | { TLV_VENUE_GROUP, "VENUE_GROUP" }, 236 | { TLV_VENUE_TYPE, "VENUE_TYPE" }, 237 | { TLV_HESSID, "HESSID" }, 238 | { TLV_ANQP_3GPP_CELL_NETWORK_INFO, "ANQP_3GPP_CELL_NETWORK_INFO" }, 239 | { TLV_OSU_SSID, "OSU_SSID" }, 240 | { TLV_PROXY_ARP, "PROXY_ARP" }, 241 | { TLV_BSSLOAD_ENABLE, "BSSLOAD_ENABLE" }, 242 | { TLV_ROAMING_CONSORTIUM, "ROAMING_CONSORTIUM" }, 243 | { TLV_NETWORK_AUTH_TYPE, "NETWORK_AUTH_TYPE" }, 244 | { TLV_DOMAIN_LIST, "DOMAIN_LIST" }, 245 | { TLV_HS20_OPERATOR_FRIENDLY_NAME, "HS20_OPERATOR_FRIENDLY_NAME" }, 246 | { TLV_NAI_REALM, "NAI_REALM" }, 247 | { TLV_VENUE_NAME, "VENUE_NAME" }, 248 | { TLV_IPADDR_TYPE_AVAILABILITY, "IPADDR_TYPE_AVAILABILITY" }, 249 | { TLV_HS20_WAN_METRICS, "HS20_WAN_METRICS" }, 250 | { TLV_HS20_CONN_CAPABILITY, "HS20_CONN_CAPABILITY"}, 251 | { TLV_VENUE_URL, "VENUE_URL" }, 252 | { TLV_OPERATOR_ICON_METADATA, "OPERATOR_ICON_METADATA" }, 253 | { TLV_OSU_PROVIDERS_LIST, "OSU_PROVIDERS_LIST" }, 254 | { TLV_OSU_PROVIDERS_NAI_LIST, "OSU_PROVIDERS_NAI_LIST" }, 255 | { TLV_REALM, "REALM" }, 256 | { TLV_IMSI, "IMSI" }, 257 | { TLV_MILENAGE, "MILENAGE" }, 258 | { TLV_BSSID_FILTER_LIST, "BSSID_FILTER_LIST" }, 259 | { TLV_PPSMO_FILE, "PPSMO_FILE" }, 260 | { TLV_OSU_SERVER_URI, "OSU_SERVER_URI" }, 261 | { TLV_OSU_METHOD, "OSU_METHOD" }, 262 | { TLV_GO_INTENT, "GO_INTENT" }, 263 | { TLV_WSC_METHOD, "WSC_METHOD" }, 264 | { TLV_PIN_METHOD, "PIN_METHOD" }, 265 | { TLV_PIN_CODE, "PIN_CODE" }, 266 | { TLV_P2P_CONN_TYPE, "P2P_CONN_TYPE" }, 267 | { TLV_HS20_OPERATING_CLASS_INDICATION, "HS20_OPERATING_CLASS_INDICATION"}, 268 | { TLV_WPS_ENABLE, "WPS_ENABLE" }, 269 | { TLV_UPDATE_CONFIG, "UPDATE_CONFIG" }, 270 | { TLV_EAP_FRAG_SIZE, "EAP_FRAG_SIZE" }, 271 | { TLV_PERFORM_WPS_IE_FRAG, "PERFORM_WPS_IE_FRAG" }, 272 | { TLV_ADVICE_OF_CHARGE, "ADVICE_OF_CHARGE"}, 273 | { TLV_IGNORE_BROADCAST_SSID, "IGNORE_BROADCAST_SSID"}, 274 | { TLV_PERSISTENT, "PERSISTENT_GROUP" }, 275 | { TLV_WSC_CONFIG_ONLY, "WSC_CONFIG_ONLY" }, 276 | { TLV_ICON_FILE, "ICON_FILE" }, 277 | { TLV_P2P_DISABLED, "P2P_DISABLED" }, 278 | { TLV_MANAGE_P2P, "MANAGE_P2P" }, 279 | { TLV_AP_STA_COEXIST, "AP_STA_COEXIST" }, 280 | { TLV_WPS_INDEPENDENT, "WPS_INDEPENDENT" }, 281 | { TLV_LOCAL_PWR_CONST, "LOCAL_PWR_CONST" }, 282 | { TLV_SPECTRUM_MGMT_REQ, "SPECTRUM_MGMT_REQ" }, 283 | { TLV_CAPTURE_FILE, "CAPTURE_FILE" }, 284 | { TLV_CAPTURE_FILTER, "CAPTURE_FILTER" }, 285 | { TLV_CAPTURE_INFILE, "CAPTURE_INFILE" }, 286 | { TLV_CAPTURE_OUTFILE, "CAPTURE_OUTFILE" }, 287 | { TLV_TP_IP_ADDRESS, "TP_IP_ADDRESS" }, 288 | { TLV_WPS_ER_SUPPORT, "WPS_ER_SUPPORT" }, 289 | { TLV_TEST_PLATFORM_ID, "TEST_PLATFORM_ID" }, 290 | { TLV_PMK, "PMK" }, 291 | { TLV_GROUP_MGMT_CIPHER, "GROUP_MGMT_CIPHER" }, 292 | { TLV_GROUP_MGMT, "GROUP_MGMT" }, 293 | { TLV_OPENSSL_CIPHERS, "OPENSSL_CIPHERS" }, 294 | { TLV_BEACON_PROT, "BEACON_PROTECTION" }, 295 | { TLV_IEEE80211_BE, "IEEE80211_BE" }, 296 | { TLV_MLD_AP, "MLD_AP" }, 297 | { TLV_EHT_OPER_CHWIDTH, "EHT_OPER_CHWIDTH" }, 298 | { TLV_EHT_OPER_CENTR_FREQ, "EHT_OPER_CENTR_FREQ" }, 299 | { TLV_SAE_PASSWORD, "SAE_PASSWORD" }, 300 | { TLV_SAE_PK_MODIFIER, "SAE_PK_MODIFIER" }, 301 | { TLV_SAE_PK_FILE, "SAE_PK_FILE" }, 302 | { TLV_WPA_GROUP_REKEY, "WPA_GROUP_REKEY" }, 303 | { TLV_WPA_STRICT_REKEY, "WPA_STRICT_REKEY" }, 304 | { TLV_OCV, "OCV" }, 305 | { TLV_MLD_FORCE_SINGLE_LINK, "MLD_FORCE_SINGLE_LINK" }, 306 | { TLV_MLD_CONNECT_BAND_PREF, "MLD_CONNECT_BAND_PREF" }, 307 | }; 308 | 309 | /* Find the type of the API stucture by the ID from the list */ 310 | char* get_api_type_by_id(int id) { 311 | int i = 0; 312 | for (i = 0; i < sizeof(indigo_api_list)/sizeof(struct indigo_api); i++) { 313 | if (id == indigo_api_list[i].type) { 314 | return indigo_api_list[i].name; 315 | } 316 | } 317 | return "Unknown"; 318 | } 319 | 320 | /* Find the API stucture by the ID from the list */ 321 | struct indigo_api* get_api_by_id(int id) { 322 | int i = 0; 323 | for (i = 0; i < sizeof(indigo_api_list)/sizeof(struct indigo_api); i++) { 324 | if (id == indigo_api_list[i].type) { 325 | return &indigo_api_list[i]; 326 | } 327 | } 328 | return NULL; 329 | } 330 | 331 | /* Find the TLV by the ID from the list */ 332 | struct indigo_tlv* get_tlv_by_id(int id) { 333 | int i = 0; 334 | 335 | for (i = 0; i < sizeof(indigo_tlv_list)/sizeof(struct indigo_tlv); i++) { 336 | if (id == indigo_tlv_list[i].id) { 337 | return &indigo_tlv_list[i]; 338 | } 339 | } 340 | return NULL; 341 | } 342 | 343 | /* The generic function generates the ACK/NACK response */ 344 | /* seq: integer which should match the sequence of the request */ 345 | /* status: 0 - ACK, 1 - NACK */ 346 | /* reason: string for the reason code */ 347 | void fill_wrapper_ack(struct packet_wrapper *wrapper, int seq, int status, char *reason) { 348 | wrapper->hdr.version = API_VERSION; 349 | wrapper->hdr.type = API_CMD_ACK; 350 | wrapper->hdr.seq = seq; 351 | wrapper->hdr.reserved = API_RESERVED_BYTE; 352 | wrapper->hdr.reserved2 = API_RESERVED_BYTE; 353 | 354 | wrapper->tlv_num = 2; 355 | wrapper->tlv[0] = malloc(sizeof(struct tlv_hdr)); 356 | wrapper->tlv[0]->id = TLV_STATUS; 357 | wrapper->tlv[0]->len = 1; 358 | wrapper->tlv[0]->value = (char*)malloc(wrapper->tlv[0]->len); 359 | wrapper->tlv[0]->value[0] = status; 360 | 361 | wrapper->tlv[1] = malloc(sizeof(struct tlv_hdr)); 362 | wrapper->tlv[1]->id = TLV_MESSAGE; 363 | wrapper->tlv[1]->len = strlen(reason); 364 | wrapper->tlv[1]->value = (char*)malloc(wrapper->tlv[1]->len); 365 | memcpy(wrapper->tlv[1]->value, reason, wrapper->tlv[1]->len); 366 | } 367 | 368 | /* Provide the function to register the API handler */ 369 | void register_api(int id, api_callback_func verify, api_callback_func handle) { 370 | struct indigo_api *api = NULL; 371 | 372 | api = get_api_by_id(id); 373 | if (api) { 374 | api->verify = verify; 375 | api->handle = handle; 376 | } else { 377 | indigo_logger(LOG_LEVEL_ERROR, "API 0x%04x has no callback function", id); 378 | } 379 | } 380 | 381 | /* Fill the message header structure to the wrapper */ 382 | void fill_wrapper_message_hdr(struct packet_wrapper *wrapper, int msg_type, int seq) { 383 | wrapper->hdr.version = API_VERSION; 384 | wrapper->hdr.type = msg_type; 385 | wrapper->hdr.seq = seq; 386 | wrapper->hdr.reserved = API_RESERVED_BYTE; 387 | wrapper->hdr.reserved2 = API_RESERVED_BYTE; 388 | } 389 | 390 | /* Fill the TLV structure to the wrapper (for one byte value) */ 391 | void fill_wrapper_tlv_byte(struct packet_wrapper *wrapper, int id, char value) { 392 | wrapper->tlv[wrapper->tlv_num] = malloc(sizeof(struct tlv_hdr)); 393 | wrapper->tlv[wrapper->tlv_num]->id = id; 394 | wrapper->tlv[wrapper->tlv_num]->len = 1; 395 | wrapper->tlv[wrapper->tlv_num]->value = (char*)malloc(1); 396 | wrapper->tlv[wrapper->tlv_num]->value[0] = value; 397 | wrapper->tlv_num++; 398 | } 399 | 400 | /* Fill the TLV structure to the wrapper (for multiple bytes value) */ 401 | void fill_wrapper_tlv_bytes(struct packet_wrapper *wrapper, int id, int len, char* value) { 402 | wrapper->tlv[wrapper->tlv_num] = malloc(sizeof(struct tlv_hdr)); 403 | wrapper->tlv[wrapper->tlv_num]->id = id; 404 | wrapper->tlv[wrapper->tlv_num]->len = len; 405 | wrapper->tlv[wrapper->tlv_num]->value = (char*)malloc(len); 406 | memcpy(wrapper->tlv[wrapper->tlv_num]->value, value, len); 407 | wrapper->tlv_num++; 408 | } 409 | -------------------------------------------------------------------------------- /indigo_api.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2020 Wi-Fi Alliance */ 2 | 3 | /* Permission to use, copy, modify, and/or distribute this software for any */ 4 | /* purpose with or without fee is hereby granted, provided that the above */ 5 | /* copyright notice and this permission notice appear in all copies. */ 6 | 7 | /* THE SOFTWARE IS PROVIDED 'AS IS' AND THE AUTHOR DISCLAIMS ALL */ 8 | /* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED */ 9 | /* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL */ 10 | /* THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR */ 11 | /* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING */ 12 | /* FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF */ 13 | /* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT */ 14 | /* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS */ 15 | /* SOFTWARE. */ 16 | 17 | #ifndef _INDIGO_API_ 18 | #define _INDIGO_API_ 19 | #include "indigo_packet.h" 20 | 21 | /* API */ 22 | #define NAME_SIZE 64 23 | 24 | struct indigo_tlv { 25 | unsigned short id; 26 | char name[NAME_SIZE]; 27 | }; 28 | 29 | struct indigo_api { 30 | unsigned short type; 31 | char name[NAME_SIZE]; 32 | int (*verify)(struct packet_wrapper *req, struct packet_wrapper *resp); 33 | int (*handle)(struct packet_wrapper *req, struct packet_wrapper *resp); 34 | }; 35 | 36 | /* API definition */ 37 | #define API_VERSION 0x01 38 | #define API_RESERVED_BYTE 0xff 39 | 40 | /* Message type definition */ 41 | #define API_CMD_RESPONSE 0x0000 42 | #define API_CMD_ACK 0x0001 43 | 44 | #define API_AP_START_UP 0x1000 45 | #define API_AP_STOP 0x1001 46 | #define API_AP_CONFIGURE 0x1002 47 | #define API_AP_TRIGGER_CHANSWITCH 0x1003 48 | #define API_AP_SEND_DISCONNECT 0x1004 49 | #define API_AP_SET_PARAM 0x1005 50 | #define API_AP_SEND_BTM_REQ 0x1006 51 | #define API_AP_SEND_ARP_MSGS 0x1007 52 | #define API_AP_START_WPS 0x1008 53 | #define API_AP_CONFIGURE_WSC 0x1009 54 | #define API_AP_REKEY_GTK 0x100a 55 | 56 | #define API_STA_ASSOCIATE 0x2000 57 | #define API_STA_CONFIGURE 0x2001 58 | #define API_STA_DISCONNECT 0x2002 59 | #define API_STA_SEND_DISCONNECT 0x2003 60 | #define API_STA_REASSOCIATE 0x2004 61 | #define API_STA_SET_PARAM 0x2005 62 | #define API_STA_SEND_BTM_QUERY 0x2006 63 | #define API_STA_SEND_ANQP_QUERY 0x2007 64 | #define API_STA_START_UP 0x2008 65 | #define API_STA_SET_PHY_MODE 0x2009 66 | #define API_STA_SET_CHANNEL_WIDTH 0x200a 67 | #define API_STA_POWER_SAVE 0x200b 68 | #define API_P2P_START_UP 0x200c 69 | #define API_P2P_FIND 0x200d 70 | #define API_P2P_LISTEN 0x200e 71 | #define API_P2P_ADD_GROUP 0x200f 72 | #define API_P2P_START_WPS 0x2010 73 | #define API_P2P_CONNECT 0x2011 74 | #define API_STA_HS2_ASSOCIATE 0x2012 75 | #define API_STA_ADD_CREDENTIAL 0x2013 76 | #define API_STA_SCAN 0x2014 77 | #define API_P2P_GET_INTENT_VALUE 0x2015 78 | #define API_STA_START_WPS 0x2016 79 | #define API_STA_INSTALL_PPSMO 0x2017 80 | #define API_P2P_INVITE 0x2018 81 | #define API_P2P_STOP_GROUP 0x2019 82 | #define API_P2P_SET_SERV_DISC 0x201a 83 | #define API_STA_SEND_ICON_REQ 0x201b 84 | #define API_P2P_SET_EXT_LISTEN 0x201c 85 | #define API_STA_ENABLE_WSC 0x201d 86 | #define API_STA_INJECT_START 0x201e 87 | #define API_STA_INJECT_FRAME 0x201f 88 | #define API_STA_INJECT_STOP 0x2020 89 | 90 | #define API_SNIFFER_START 0x3000 91 | #define API_SNIFFER_STOP 0x3001 92 | #define API_SNIFFER_UPLOAD_FILE 0x3002 93 | #define API_SNIFFER_FILTER 0x3003 94 | 95 | #define API_GET_IP_ADDR 0x5000 96 | #define API_GET_MAC_ADDR 0x5001 97 | #define API_GET_CONTROL_APP_VERSION 0x5002 98 | #define API_START_LOOP_BACK_SERVER 0x5003 99 | #define API_STOP_LOOP_BACK_SERVER 0x5004 100 | #define API_CREATE_NEW_INTERFACE_BRIDGE_NETWORK 0x5005 101 | #define API_ASSIGN_STATIC_IP 0x5006 102 | #define API_DEVICE_RESET 0x5007 103 | #define API_SEND_LOOP_BACK_DATA 0x5008 104 | #define API_STOP_LOOP_BACK_DATA 0x5009 105 | #define API_START_DHCP 0x500a 106 | #define API_STOP_DHCP 0x500b 107 | #define API_GET_WSC_PIN 0x500c 108 | #define API_GET_WSC_CRED 0x500d 109 | 110 | /* TLV definition */ 111 | #define TLV_SSID 0x0001 112 | #define TLV_CHANNEL 0x0002 113 | #define TLV_WEP_KEY0 0x0003 114 | #define TLV_AUTH_ALGORITHM 0x0004 115 | #define TLV_WEP_DEFAULT_KEY 0x0005 116 | #define TLV_IEEE80211_D 0x0006 117 | #define TLV_IEEE80211_N 0x0007 118 | #define TLV_IEEE80211_AC 0x0008 119 | #define TLV_COUNTRY_CODE 0x0009 120 | #define TLV_WMM_ENABLED 0x000a 121 | #define TLV_WPA 0x000b 122 | #define TLV_WPA_KEY_MGMT 0x000c 123 | #define TLV_RSN_PAIRWISE 0x000d 124 | #define TLV_WPA_PASSPHRASE 0x000e 125 | #define TLV_WPA_PAIRWISE 0x000f 126 | #define TLV_HT_CAPB 0x0010 127 | #define TLV_IEEE80211_H 0x0011 128 | #define TLV_IEEE80211_W 0x0012 129 | #define TLV_VHT_OPER_CHWIDTH 0x0013 130 | #define TLV_VHT_CAPB 0x0014 131 | #define TLV_IEEE8021_X 0x0015 132 | #define TLV_EAP_SERVER 0x0016 133 | #define TLV_AUTH_SERVER_ADDR 0x0017 134 | #define TLV_AUTH_SERVER_PORT 0x0018 135 | #define TLV_AUTH_SERVER_SHARED_SECRET 0x0019 136 | #define TLV_INTERFACE_NAME 0x001a 137 | #define TLV_NEW_INTERFACE_NAME 0x001b 138 | #define TLV_FREQUENCY 0x001c 139 | #define TLV_BSS_IDENTIFIER 0x001d 140 | #define TLV_HW_MODE 0x001e 141 | #define TLV_VHT_OPER_CENTR_FREQ 0x001f 142 | #define TLV_RESET_TYPE 0x0020 143 | #define APP_TYPE 0x0021 144 | #define TLV_OP_CLASS 0x0022 145 | #define TLV_IE_OVERRIDE 0x0023 146 | #define TLV_HOME_FQDN 0x0024 147 | #define TLV_USERNAME 0x0025 148 | #define TLV_PREFER 0x0026 149 | #define TLV_CREDENTIAL_TYPE 0x0027 150 | #define TLV_ADDRESS 0x0028 151 | #define TLV_DISABLE_PMKSA_CACHING 0x0033 152 | #define TLV_SAE_ANTI_CLOGGING_THRESHOLD 0x0034 153 | #define TLV_STA_SSID 0x0035 154 | #define TLV_KEY_MGMT 0x0036 155 | #define TLV_STA_WEP_KEY0 0x0037 156 | #define TLV_WEP_TX_KEYIDX 0x0038 157 | #define TLV_GROUP 0x0039 158 | #define TLV_PSK 0x003a 159 | #define TLV_PROTO 0x003b 160 | #define TLV_STA_IEEE80211_W 0x003c 161 | #define TLV_PAIRWISE 0x003d 162 | #define TLV_EAP 0x003e 163 | #define TLV_PHASE2 0x003f 164 | #define TLV_IDENTITY 0x0040 165 | #define TLV_PASSWORD 0x0041 166 | #define TLV_CA_CERT 0x0042 167 | #define TLV_PHASE1 0x0043 168 | #define TLV_CLIENT_CERT 0x0044 169 | #define TLV_PRIVATE_KEY 0x0045 170 | #define TLV_EAPOL_M3_ELEMENTS 0x0046 171 | #define TLV_GTK_KDE_RANDOM_RESERVED_BITS 0x0047 172 | #define TLV_STA_POWER_SAVE 0x0052 173 | #define TLV_STATIC_IP 0x0055 174 | #define TLV_DEBUG_LEVEL 0x0057 175 | #define TLV_DUT_IP_ADDRESS 0x0058 176 | #define TLV_HOSTAPD_FILE_NAME 0x0059 177 | #define TLV_ROLE 0x005c 178 | #define TLV_BAND 0x005d 179 | #define TLV_BSSID 0x005e 180 | #define TLV_ARP_TRANSMISSION_RATE 0x005f 181 | #define TLV_ARP_TARGET_IP 0x0060 182 | #define TLV_ARP_FRAME_COUNT 0x0062 183 | #define TLV_FRAME_TYPE 0x0063 184 | #define TLV_ACTION_CATEGORY 0x0064 185 | #define TLV_ACTION_CODE 0x0065 186 | #define TLV_PACKET_COUNT 0x0067 187 | #define TLV_PACKET_TYPE 0x0068 188 | #define TLV_PACKET_RATE 0x0069 189 | #define TLV_PHYMODE 0x006a 190 | #define TLV_CHANNEL_WIDTH 0x006b 191 | #define TLV_PAC_FILE 0x006d 192 | #define TLV_STA_SAE_GROUPS 0x006e 193 | #define TLV_SAE_GROUPS 0x0071 194 | #define TLV_IEEE80211_AX 0x0072 195 | #define TLV_HE_OPER_CHWIDTH 0x0073 196 | #define TLV_HE_OPER_CENTR_FREQ 0x0074 197 | #define TLV_MBO 0x0075 198 | #define TLV_MBO_CELL_DATA_CONN_PREF 0x0076 199 | #define TLV_BSS_TRANSITION 0x0077 200 | #define TLV_INTERWORKING 0x0078 201 | #define TLV_RRM_NEIGHBOR_REPORT 0x0079 202 | #define TLV_RRM_BEACON_REPORT 0x007a 203 | #define TLV_COUNTRY3 0x007b 204 | #define TLV_MBO_CELL_CAPA 0x007c 205 | #define TLV_DOMAIN_MATCH 0x007d 206 | #define TLV_DOMAIN_SUFFIX_MATCH 0x007e 207 | #define TLV_MBO_ASSOC_DISALLOW 0x007f 208 | #define TLV_DISASSOC_IMMINENT 0x0081 209 | #define TLV_BSS_TERMINATION 0x0082 210 | #define TLV_DISASSOC_TIMER 0x0083 211 | #define TLV_BSS_TERMINATION_TSF 0x0084 212 | #define TLV_BSS_TERMINATION_DURATION 0x0085 213 | #define TLV_REASSOCIAITION_RETRY_DELAY 0x0086 214 | #define TLV_BTMQUERY_REASON_CODE 0x0087 215 | #define TLV_CANDIDATE_LIST 0x0088 216 | #define TLV_ANQP_INFO_ID 0x0089 217 | #define TLV_GAS_COMEBACK_DELAY 0x008a 218 | #define TLV_SAE_PWE 0x008d 219 | #define TLV_OWE_GROUPS 0x008e 220 | #define TLV_STA_OWE_GROUP 0x008f 221 | #define TLV_HE_MU_EDCA 0x0090 222 | #define TLV_PROTECTION_TYPE 0x0091 223 | #define TLV_RSNXE_OVERRIDE_EAPOL 0x0092 224 | #define TLV_TRANSITION_DISABLE 0x0093 225 | #define TLV_SAE_CONFIRM_IMMEDIATE 0x0094 226 | #define TLV_RAND_MAC_ADDR 0x0095 227 | #define TLV_PREASSOC_RAND_MAC_ADDR 0x0096 228 | #define TLV_RAND_ADDR_LIFETIME 0x0097 229 | #define TLV_DROP_SA 0x0098 230 | #define TLV_SERVER_CERT 0x0099 231 | 232 | #define TLV_CONTROL_INTERFACE 0x009c 233 | #define TLV_PACKET_SIZE 0x009d 234 | #define TLV_DUT_UDP_PORT 0x009e 235 | #define TLV_SKIP_6G_BSS_SECURITY_CHECK 0x00a1 236 | #define TLV_OWE_TRANSITION_BSS_IDENTIFIER 0x00a2 237 | #define TLV_FREQ_LIST 0x00a3 238 | #define TLV_BSSID_FILTER_LIST 0x00a4 239 | #define TLV_HE_BEACON_TX_SU_PPDU 0x00a5 240 | #define TLV_HE_6G_ONLY 0x00a6 241 | #define TLV_HE_UNSOL_PR_RESP_CADENCE 0x00a7 242 | #define TLV_HE_FILS_DISCOVERY_TX 0x00a8 243 | #define TLV_HS20 0x00a9 244 | #define TLV_ACCESS_NETWORK_TYPE 0x00aa 245 | #define TLV_INTERNET 0x00ab 246 | #define TLV_VENUE_GROUP 0x00ac 247 | #define TLV_VENUE_TYPE 0x00ad 248 | #define TLV_HESSID 0x00ae 249 | #define TLV_OSU_SSID 0x00af 250 | #define TLV_ANQP_3GPP_CELL_NETWORK_INFO 0x00b0 251 | #define TLV_PROXY_ARP 0x00b1 252 | #define TLV_BSSLOAD_ENABLE 0x00b2 253 | #define TLV_ROAMING_CONSORTIUM 0x00b3 254 | #define TLV_NETWORK_AUTH_TYPE 0x00b4 255 | #define TLV_DOMAIN_LIST 0x00b5 256 | #define TLV_HS20_OPERATOR_FRIENDLY_NAME 0x00b6 257 | #define TLV_NAI_REALM 0x00b7 258 | #define TLV_VENUE_NAME 0x00b8 259 | #define TLV_IPADDR_TYPE_AVAILABILITY 0x00b9 260 | #define TLV_HS20_WAN_METRICS 0x00ba 261 | #define TLV_HS20_CONN_CAPABILITY 0x00bb 262 | #define TLV_VENUE_URL 0x00bc 263 | #define TLV_OPERATOR_ICON_METADATA 0x00bd 264 | #define TLV_OSU_PROVIDERS_LIST 0x00be 265 | #define TLV_OSU_PROVIDERS_NAI_LIST 0x00bf 266 | #define TLV_REALM 0x00c0 267 | #define TLV_IMSI 0x00c1 268 | #define TLV_MILENAGE 0x00c2 269 | #define TLV_PPSMO_FILE 0x00c3 270 | #define TLV_OSU_SERVER_URI 0x00c4 271 | #define TLV_OSU_METHOD 0x00c5 272 | #define TLV_GO_INTENT 0x00c6 273 | #define TLV_WSC_METHOD 0x00c7 274 | #define TLV_PIN_METHOD 0x00c8 275 | #define TLV_PIN_CODE 0x00c9 276 | #define TLV_P2P_CONN_TYPE 0x00ca 277 | #define TLV_HS20_OPERATING_CLASS_INDICATION 0x00cb 278 | #define TLV_WPS_ENABLE 0x00cc 279 | #define TLV_UPDATE_CONFIG 0x00cd 280 | #define TLV_EAP_FRAG_SIZE 0x00ce 281 | #define TLV_PERFORM_WPS_IE_FRAG 0x00cf 282 | #define TLV_ADVICE_OF_CHARGE 0x00d0 283 | #define TLV_IGNORE_BROADCAST_SSID 0x00d1 284 | #define TLV_PERSISTENT 0x00d2 285 | #define TLV_WSC_CONFIG_ONLY 0x00d3 286 | #define TLV_ICON_FILE 0x00d4 287 | #define TLV_P2P_DISABLED 0x00d5 288 | #define TLV_MANAGE_P2P 0x00d6 289 | #define TLV_AP_STA_COEXIST 0x00d7 290 | #define TLV_WPS_INDEPENDENT 0x00d8 291 | #define TLV_LOCAL_PWR_CONST 0x00d9 292 | #define TLV_SPECTRUM_MGMT_REQ 0x00da 293 | #define TLV_CAPTURE_FILE 0x00db 294 | #define TLV_CAPTURE_FILTER 0x00dc 295 | #define TLV_CAPTURE_INFILE 0x00dd 296 | #define TLV_CAPTURE_OUTFILE 0x00de 297 | #define TLV_TP_IP_ADDRESS 0x00df 298 | #define TLV_WPS_ER_SUPPORT 0x00e0 299 | #define TLV_TEST_PLATFORM_ID 0x00e1 300 | // 00e2 - 00e5: used by sniffer agent 301 | #define TLV_PMK 0x00e6 302 | #define TLV_GROUP_MGMT_CIPHER 0x00e7 303 | #define TLV_GROUP_MGMT 0x00e8 304 | #define TLV_OPENSSL_CIPHERS 0x00e9 305 | #define TLV_BEACON_PROT 0x00ea 306 | #define TLV_IEEE80211_BE 0x00eb 307 | #define TLV_MLD_AP 0x00ec 308 | #define TLV_EHT_OPER_CHWIDTH 0x00ed 309 | #define TLV_EHT_OPER_CENTR_FREQ 0x00ee 310 | #define TLV_SAE_PASSWORD 0x00ef 311 | #define TLV_SAE_PK_MODIFIER 0x00f0 312 | #define TLV_SAE_PK_FILE 0x00f1 313 | #define TLV_WPA_GROUP_REKEY 0x00f2 314 | #define TLV_WPA_STRICT_REKEY 0x00f3 315 | #define TLV_OCV 0x00f4 316 | #define TLV_MLD_FORCE_SINGLE_LINK 0x00f5 317 | #define TLV_MLD_CONNECT_BAND_PREF 0x00f6 318 | 319 | // class ResponseTLV 320 | // List of TLV used in the QuickTrack API response and ACK messages from the DUT 321 | #define TLV_MESSAGE 0xa000 322 | #define TLV_STATUS 0xa001 323 | #define TLV_DUT_WLAN_IP_ADDR 0xa002 324 | #define TLV_DUT_MAC_ADDR 0xa003 325 | #define TLV_CONTROL_APP_VERSION 0xa004 326 | #define TLV_LOOP_BACK_DATA_RECEIVED 0xa005 327 | #define TLV_LOOP_BACK_DATA_SENT 0xa006 328 | #define TLV_ARP_RECV_NUM 0xa007 329 | #define TLV_TEST_PLATFORM_APP_VERSION 0xa008 330 | #define TLV_LOOP_BACK_SERVER_PORT 0xa009 331 | #define TLV_WSC_PIN_CODE 0xa00a 332 | #define TLV_P2P_INTENT_VALUE 0xa00b 333 | #define TLV_WSC_SSID 0xa00c 334 | #define TLV_WSC_WPA_KEY_MGMT 0xa00d 335 | #define TLV_WSC_WPA_PASSPHRASE 0xa00e 336 | #define TLV_PASSPOINT_ICON_CHECKSUM 0xa00f 337 | #define TLV_TEST_SNIFFER_APP_VERSION 0xa010 338 | // a011 - a013: used by sniffer agent 339 | #define TLV_TEST_PLATFORM_WLAN_IP_ADDR 0xa014 340 | 341 | /* TLV Value */ 342 | #define DUT_TYPE_STAUT 0x01 343 | #define DUT_TYPE_APUT 0x02 344 | #define DUT_TYPE_P2PUT 0x03 345 | 346 | #define TLV_BAND_24GHZ "2.4GHz" 347 | #define TLV_BAND_5GHZ "5GHz" 348 | #define TLV_BAND_6GHZ "6GHz" 349 | 350 | #define TLV_VALUE_APP_VERSION "v2.1" 351 | #define TLV_VALUE_OK "OK" 352 | #define TLV_VALUE_NOT_OK "Failed" 353 | #define TLV_VALUE_INSUFFICIENT_TLV "TLV is insufficient to run the command" 354 | #define TLV_VALUE_STATUS_OK 0x30 355 | #define TLV_VALUE_STATUS_NOT_OK 0x31 356 | #define TLV_VALUE_LOOP_BACK_STOP_OK "Loopback server in idle state" 357 | #define TLV_VALUE_HOSTAPD_STOP_OK "AP stop completed : Hostapd service is inactive." 358 | #define TLV_VALUE_HOSTAPD_STOP_NOT_OK "Failed to stop hostapd service." 359 | #define TLV_VALUE_WPA_SET_PARAMETER_OK "Set parameter action was successful." 360 | #define TLV_VALUE_WPA_SET_PARAMETER_NO_OK "Failed to set parameter." 361 | #define TLV_VALUE_WPA_PARAMETER_NOT_SUPPORT "The set parameter is not supported" 362 | #define TLV_VALUE_HOSTAPD_START_OK "AP is up : Hostapd service is active" 363 | #define TLV_VALUE_ASSIGN_STATIC_IP_OK "Static IP successfully assigned to wireless interface" 364 | #define TLV_VALUE_ASSIGN_STATIC_IP_NOT_OK "Static IP failed to be assigned to wireless interface" 365 | #define TLV_VALUE_LOOPBACK_SVR_START_OK "Loop back server initialized" 366 | #define TLV_VALUE_LOOPBACK_SVR_START_NOT_OK "Failed to initialise loop back server" 367 | #define TLV_VALUE_SEND_LOOPBACK_DATA_OK "Send Loop back data successful" 368 | #define TLV_VALUE_SEND_LOOPBACK_DATA_NOT_OK "Send Loop back data failed" 369 | #define TLV_VALUE_WIRELESS_INTERFACE_NOT_OK "Wireless interface is not available" 370 | #define TLV_VALUE_HOSTAPD_CTRL_NOT_OK "Failed to connect to hostapd control interface" 371 | #define TLV_VALUE_HOSTAPD_NOT_OK "Failed to find hostapd PID" 372 | #define TLV_VALUE_HOSTAPD_RESP_NOT_OK "Hostapd response is failed" 373 | #define TLV_VALUE_BROADCAST_ARP_TEST_OK "Broadcast ARP test successful" 374 | #define TLV_VALUE_BROADCAST_ARP_TEST_NOT_OK "Broadcast ARP test failed" 375 | #define TLV_VALUE_CREATE_BRIDGE_OK "Bridge network is created successfully" 376 | #define TLV_VALUE_CREATE_BRIDGE_NOT_OK "Failed to create bridge network" 377 | #define TLV_VALUE_START_DHCP_NOT_OK "Failed to start DHCP server or client" 378 | 379 | #define TLV_VALUE_WPA_S_START_UP_OK "wpa_supplicant is initialized successfully" 380 | #define TLV_VALUE_WPA_S_START_UP_NOT_OK "The wpa_supplicant was unable to initialize." 381 | #define TLV_VALUE_WPA_S_ADD_CRED_OK "Add credential to the STA successfully" 382 | #define TLV_VALUE_WPA_S_ADD_CRED_NOT_OK "Failed to add credential to the STA." 383 | #define TLV_VALUE_WPA_S_STOP_NOT_OK "Failed to stop wpa supplicant service." 384 | #define TLV_VALUE_WPA_S_STOP_OK "QuickTrack tool STA was successfully disconnected" 385 | #define TLV_VALUE_WPA_S_ASSOC_OK "STA is up: WPA supplicant associated" 386 | #define TLV_VALUE_WPA_S_ASSOC_NOT_OK "WPA supplicant cannot associate with AP" 387 | #define TLV_VALUE_WPA_S_DISCONNECT_OK "Sent DISCONNECT message" 388 | #define TLV_VALUE_WPA_S_DISCONNECT_NOT_OK "Failed to send DISCONNECT message" 389 | #define TLV_VALUE_WPA_S_RECONNECT_OK "Sent RECONNECT message" 390 | #define TLV_VALUE_WPA_S_RECONNECT_NOT_OK "Failed to send RECONNECT message" 391 | #define TLV_VALUE_WPA_S_CTRL_NOT_OK "Failed to connect to WPA supplicant control interface" 392 | #define TLV_VALUE_WPA_S_BTM_QUERY_OK "Sent WNM_BSS_QUERY" 393 | #define TLV_VALUE_WPA_S_BTM_QUERY_NOT_OK "Failed to WNM_BSS_QUERY" 394 | #define TLV_VALUE_WPA_S_SCAN_NOT_OK "Failed to trigger SCAN" 395 | #define TLV_VALUE_RESET_OK "Device reset successfully" 396 | #define TLV_VALUE_RESET_NOT_OK "Failed to run Device reset" 397 | #define TLV_VALUE_POWER_SAVE_OK "Set power save value successfully" 398 | #define TLV_VALUE_POWER_SAVE_NOT_OK "Failed to set power save value" 399 | 400 | #define TLV_VALUE_P2P_FIND_NOT_OK "Failed to trigger P2P find" 401 | #define TLV_VALUE_P2P_LISTEN_NOT_OK "Failed to trigger P2P listen" 402 | #define TLV_VALUE_P2P_ADD_GROUP_NOT_OK "Failed to add P2P group" 403 | #define TLV_VALUE_P2P_START_WPS_NOT_OK "Failed to start WPS on GO interface" 404 | #define TLV_VALUE_P2P_CONNECT_NOT_OK "Failed to trigger P2P connect" 405 | #define TLV_VALUE_P2P_INVITE_NOT_OK "Failed to invite P2P device" 406 | #define TLV_VALUE_P2P_SET_SERV_DISC_NOT_OK "Failed to set service discovery" 407 | #define TLV_VALUE_P2P_SET_EXT_LISTEN_NOT_OK "Failed to set extended listen timing" 408 | 409 | #define TLV_VALUE_HS2_INSTALL_PPSMO_OK "PPSMO file is installed" 410 | #define TLV_VALUE_HS2_INSTALL_PPSMO_NOT_OK "Failed to install PPSMO file" 411 | 412 | #define TLV_VALUE_AP_START_WPS_NOT_OK "Failed to start WPS on AP interface" 413 | #define TLV_VALUE_AP_WSC_PIN_CODE_NOT_OK "AP detects invalid PIN code" 414 | 415 | #define RESET_TYPE_INIT 0x01 416 | #define RESET_TYPE_TEARDOWN 0x02 417 | #define RESET_TYPE_RECONFIGURE 0x03 418 | 419 | #define WPA_CTRL_OK "OK" 420 | #define WPA_CTRL_FAIL "FAIL" 421 | 422 | #define P2P_CONN_TYPE_JOIN 0x01 423 | #define P2P_CONN_TYPE_AUTH 0x02 424 | 425 | #define WPS_ENABLE_NORMAL 0x01 426 | #define WPS_ENABLE_OOB 0x02 427 | 428 | struct indigo_api* get_api_by_id(int id); 429 | struct indigo_tlv* get_tlv_by_id(int id); 430 | char* get_api_type_by_id(int id); 431 | 432 | typedef int (*api_callback_func)(struct packet_wrapper *req, struct packet_wrapper *resp); 433 | void register_api(int id, api_callback_func verify, api_callback_func handle); 434 | 435 | void fill_wrapper_ack(struct packet_wrapper *wrapper, int seq, int status, char *reason); 436 | 437 | void register_api(int id, api_callback_func verify, api_callback_func handle); 438 | void fill_wrapper_message_hdr(struct packet_wrapper *wrapper, int msg_type, int seq); 439 | void fill_wrapper_tlv_byte(struct packet_wrapper *wrapper, int id, char value); 440 | void fill_wrapper_tlv_bytes(struct packet_wrapper *wrapper, int id, int len, char* value); 441 | 442 | /* Solution Vendor */ 443 | void register_apis(); 444 | #endif // __INDIGO_API_ 445 | -------------------------------------------------------------------------------- /indigo_api_callback.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2020 Wi-Fi Alliance */ 2 | 3 | /* Permission to use, copy, modify, and/or distribute this software for any */ 4 | /* purpose with or without fee is hereby granted, provided that the above */ 5 | /* copyright notice and this permission notice appear in all copies. */ 6 | 7 | /* THE SOFTWARE IS PROVIDED 'AS IS' AND THE AUTHOR DISCLAIMS ALL */ 8 | /* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED */ 9 | /* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL */ 10 | /* THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR */ 11 | /* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING */ 12 | /* FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF */ 13 | /* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT */ 14 | /* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS */ 15 | /* SOFTWARE. */ 16 | 17 | #ifndef _INDIGO_API_CALLBACK 18 | #define _INDIGO_API_CALLBACK 19 | 20 | 21 | #define LOOPBACK_TIMEOUT 180 22 | 23 | struct tlv_to_config_name { 24 | unsigned short tlv_id; 25 | char config_name[NAME_SIZE]; 26 | int quoted; 27 | }; 28 | 29 | struct anqp_tlv_to_config_name { 30 | char element[NAME_SIZE]; 31 | char config[NAME_SIZE]; 32 | }; 33 | 34 | struct tlv_to_config_name maps[] = { 35 | /* hapds */ 36 | { TLV_SSID, "ssid", 0 }, 37 | { TLV_CHANNEL, "channel", 0 }, 38 | { TLV_WEP_KEY0, "wep_key0", 0 }, 39 | { TLV_HW_MODE, "hw_mode", 0 }, 40 | { TLV_AUTH_ALGORITHM, "auth_algs", 0 }, 41 | { TLV_WEP_DEFAULT_KEY, "wep_default_key", 0 }, 42 | { TLV_IEEE80211_D, "ieee80211d", 0 }, 43 | { TLV_IEEE80211_N, "ieee80211n", 0 }, 44 | { TLV_IEEE80211_AC, "ieee80211ac", 0 }, 45 | { TLV_COUNTRY_CODE, "country_code", 0 }, 46 | { TLV_WMM_ENABLED, "wmm_enabled", 0 }, 47 | { TLV_WPA, "wpa", 0 }, 48 | { TLV_WPA_KEY_MGMT, "wpa_key_mgmt", 0 }, 49 | { TLV_RSN_PAIRWISE, "rsn_pairwise", 0 }, 50 | { TLV_WPA_PASSPHRASE, "wpa_passphrase", 0 }, 51 | { TLV_WPA_PAIRWISE, "wpa_pairwise", 0 }, 52 | { TLV_HT_CAPB, "ht_capab", 0 }, 53 | { TLV_IEEE80211_W, "ieee80211w", 0 }, 54 | { TLV_IEEE80211_H, "ieee80211h", 0 }, 55 | { TLV_VHT_OPER_CHWIDTH, "vht_oper_chwidth", 0 }, 56 | { TLV_VHT_OPER_CENTR_FREQ, "vht_oper_centr_freq_seg0_idx", 0 }, 57 | { TLV_VHT_CAPB, "vht_capab", 0 }, 58 | { TLV_IEEE8021_X, "ieee8021x", 0 }, 59 | { TLV_EAP_SERVER, "eap_server", 0 }, 60 | { TLV_AUTH_SERVER_ADDR, "auth_server_addr", 0 }, 61 | { TLV_AUTH_SERVER_PORT, "auth_server_port", 0 }, 62 | { TLV_AUTH_SERVER_SHARED_SECRET, "auth_server_shared_secret", 0 }, 63 | { TLV_IE_OVERRIDE, "own_ie_override", 0 }, // HostAPD Python Interface 64 | { TLV_SAE_ANTI_CLOGGING_THRESHOLD, "sae_anti_clogging_threshold", 0 }, // HostAPD Python Interface 65 | { TLV_DISABLE_PMKSA_CACHING, "disable_pmksa_caching", 0 }, // HostAPD Python Interface 66 | { TLV_EAPOL_M3_ELEMENTS, "eapol_m3_elements", 0 }, 67 | { TLV_GTK_KDE_RANDOM_RESERVED_BITS, "gtk_kde_random_reserved_bits", 0 }, 68 | { TLV_SAE_GROUPS, "sae_groups", 0 }, 69 | { TLV_IEEE80211_AX, "ieee80211ax", 0 }, 70 | { TLV_HE_OPER_CHWIDTH, "he_oper_chwidth", 0 }, 71 | { TLV_HE_OPER_CENTR_FREQ, "he_oper_centr_freq_seg0_idx", 0 }, 72 | { TLV_MBO, "mbo", 0 }, 73 | { TLV_MBO_CELL_DATA_CONN_PREF, "mbo_cell_data_conn_pref", 0 }, 74 | { TLV_BSS_TRANSITION, "bss_transition", 0 }, 75 | { TLV_INTERWORKING, "interworking", 0 }, 76 | { TLV_RRM_NEIGHBOR_REPORT, "rrm_neighbor_report", 0 }, 77 | { TLV_RRM_BEACON_REPORT, "rrm_beacon_report", 0 }, 78 | { TLV_COUNTRY3, "country3", 0 }, 79 | { TLV_MBO_CELL_CAPA, "mbo_cell_capa", 0 }, 80 | { TLV_MBO_ASSOC_DISALLOW, "mbo_assoc_disallow", 0 }, 81 | { TLV_GAS_COMEBACK_DELAY, "gas_comeback_delay", 0 }, 82 | { TLV_SAE_PWE, "sae_pwe", 0 }, 83 | { TLV_OWE_GROUPS, "owe_groups", 0 }, 84 | { TLV_HE_MU_EDCA, "he_mu_edca_qos_info_param_count", 0 }, 85 | { TLV_TRANSITION_DISABLE, "transition_disable", 0 }, 86 | { TLV_CONTROL_INTERFACE, "ctrl_interface", 0 }, 87 | { TLV_RSNXE_OVERRIDE_EAPOL, "rsnxe_override_eapol", 0 }, 88 | { TLV_SAE_CONFIRM_IMMEDIATE, "sae_confirm_immediate", 0 }, 89 | { TLV_OWE_TRANSITION_BSS_IDENTIFIER, "owe_transition_ifname", 0 }, 90 | { TLV_OP_CLASS, "op_class", 0 }, 91 | { TLV_HE_UNSOL_PR_RESP_CADENCE, "unsol_bcast_probe_resp_interval", 0 }, 92 | { TLV_HE_FILS_DISCOVERY_TX, "fils_discovery_max_interval", 0 }, 93 | { TLV_SKIP_6G_BSS_SECURITY_CHECK, "skip_6g_bss_security_check", 0 }, 94 | { TLV_HS20, "hs20", 0 }, 95 | { TLV_ACCESS_NETWORK_TYPE, "access_network_type", 0 }, 96 | { TLV_INTERNET, "internet", 0 }, 97 | { TLV_VENUE_GROUP, "venue_group", 0 }, 98 | { TLV_VENUE_TYPE, "venue_type", 0 }, 99 | { TLV_HESSID, "hessid", 0 }, 100 | { TLV_ANQP_3GPP_CELL_NETWORK_INFO, "anqp_3gpp_cell_net", 0 }, 101 | { TLV_OSU_SSID, "osu_ssid", 0 }, 102 | { TLV_PROXY_ARP, "proxy_arp", 0 }, 103 | { TLV_OSU_SERVER_URI, "osu_server_uri", 0 }, 104 | { TLV_OSU_METHOD, "osu_method_list", 0 }, 105 | { TLV_DOMAIN_LIST, "domain_name", 0 }, 106 | { TLV_IGNORE_BROADCAST_SSID, "ignore_broadcast_ssid", 0 }, 107 | { TLV_MANAGE_P2P, "manage_p2p", 0 }, 108 | { TLV_WPS_INDEPENDENT, "wps_independent", 0 }, 109 | { TLV_LOCAL_PWR_CONST, "local_pwr_constraint", 0 }, 110 | { TLV_SPECTRUM_MGMT_REQ, "spectrum_mgmt_required", 0 }, 111 | { TLV_GROUP_MGMT_CIPHER, "group_mgmt_cipher", 0 }, 112 | { TLV_IEEE80211_BE, "ieee80211be", 0 }, 113 | { TLV_MLD_AP, "mld_ap", 0 }, 114 | { TLV_EHT_OPER_CHWIDTH, "eht_oper_chwidth", 0 }, 115 | { TLV_EHT_OPER_CENTR_FREQ, "eht_oper_centr_freq_seg0_idx", 0 }, 116 | { TLV_WPA_GROUP_REKEY, "wpa_group_rekey", 0 }, 117 | { TLV_WPA_STRICT_REKEY, "wpa_strict_rekey", 0 }, 118 | 119 | /* wpas, seperate? */ 120 | { TLV_STA_SSID, "ssid", 1 }, 121 | { TLV_KEY_MGMT, "key_mgmt", 0 }, 122 | { TLV_STA_WEP_KEY0, "wep_key0", 0 }, 123 | { TLV_WEP_TX_KEYIDX, "wep_tx_keyidx", 0 }, 124 | { TLV_GROUP, "group", 0 }, 125 | { TLV_PSK, "psk", 1 }, 126 | { TLV_PROTO, "proto", 0 }, 127 | { TLV_STA_IEEE80211_W, "ieee80211w", 0 }, 128 | { TLV_PAIRWISE, "pairwise", 0 }, 129 | { TLV_EAP, "eap", 0 }, 130 | { TLV_PHASE1, "phase1", 1 }, 131 | { TLV_PHASE2, "phase2", 1 }, 132 | { TLV_IDENTITY, "identity", 1 }, 133 | { TLV_PASSWORD, "password", 1 }, 134 | { TLV_CA_CERT, "ca_cert", 1 }, 135 | { TLV_SERVER_CERT, "ca_cert", 1 }, 136 | { TLV_PRIVATE_KEY, "private_key", 1 }, 137 | { TLV_CLIENT_CERT, "client_cert", 1 }, 138 | { TLV_DOMAIN_MATCH, "domain_match", 1 }, 139 | { TLV_DOMAIN_SUFFIX_MATCH, "domain_suffix_match", 1 }, 140 | { TLV_PAC_FILE, "pac_file", 1 }, 141 | { TLV_STA_OWE_GROUP, "owe_group", 0 }, 142 | { TLV_BSSID, "bssid", 0 }, 143 | { TLV_REALM, "realm", 1 }, 144 | { TLV_IMSI, "imsi", 1 }, 145 | { TLV_MILENAGE, "milenage", 1 }, 146 | { TLV_BSSID_FILTER_LIST, "bssid_filter", 0 }, 147 | { TLV_USERNAME, "username", 1 }, 148 | { TLV_HOME_FQDN, "domain", 1 }, 149 | { TLV_PREFER, "priority", 0 }, 150 | { TLV_GROUP_MGMT, "group_mgmt", 0 }, 151 | { TLV_SAE_PASSWORD, "sae_password", 1 }, 152 | 153 | /* hapd + wpas */ 154 | { TLV_EAP_FRAG_SIZE, "fragment_size", 0 }, 155 | { TLV_OPENSSL_CIPHERS, "openssl_ciphers", 1 }, 156 | { TLV_BEACON_PROT, "beacon_prot", 0 }, 157 | { TLV_OCV, "ocv", 0}, 158 | }; 159 | 160 | struct tlv_to_config_name semicolon_list[] = { 161 | { TLV_ROAMING_CONSORTIUM, "roaming_consortium", 0 }, 162 | }; 163 | 164 | struct anqp_tlv_to_config_name anqp_maps[] = { 165 | { "NeighborReportReq", "272" }, 166 | { "QueryListWithCellPref", "mbo:2" }, 167 | { "ANQPCapaList", "257" }, 168 | { "VenueNameInfo", "258" }, 169 | { "NetworkAuthTypeInfo", "260" }, 170 | { "RoamingConsortium", "261" }, 171 | { "IPAddrTypeInfo", "262" }, 172 | { "NAIRealm", "263" }, 173 | { "3GPPCellNetwork", "264" }, 174 | { "DomainName", "268" }, 175 | { "VenueUrl", "277" }, 176 | { "AdviceOfCharge", "278" }, 177 | { "HSCapaList", "hs20:2" }, 178 | { "OperFriendlyName", "hs20:3" }, 179 | { "WANMetrics", "hs20:4" }, 180 | { "ConnCapa", "hs20:5" }, 181 | { "NAIHomeRealm", "hs20:6" }, 182 | { "OperatingClass", "hs20:7" }, 183 | { "OSUProvidersList", "hs20:8" }, 184 | { "IconReq", "hs20:10" }, 185 | { "IconBinaryFile", "hs20:11" }, 186 | { "OperatorIcon", "hs20:12" }, 187 | { "OSUProvidersNaiList", "hs20:13" }, 188 | }; 189 | 190 | struct tlv_to_config_name wifi7_maps[] = { 191 | { TLV_IEEE80211_BE, "ieee80211be", 0 }, 192 | { TLV_MLD_AP, "mld_ap", 0 }, 193 | { TLV_EHT_OPER_CHWIDTH, "eht_oper_chwidth", 0 }, 194 | { TLV_EHT_OPER_CENTR_FREQ, "eht_oper_centr_freq_seg0_idx", 0 }, 195 | }; 196 | 197 | char* find_tlv_config_name(int tlv_id) { 198 | int i; 199 | for (i = 0; i < sizeof(maps)/sizeof(struct tlv_to_config_name); i++) { 200 | if (tlv_id == maps[i].tlv_id) { 201 | return maps[i].config_name; 202 | } 203 | } 204 | return NULL; 205 | } 206 | 207 | struct tlv_to_config_name* find_tlv_config(int tlv_id) { 208 | int i; 209 | for (i = 0; i < sizeof(maps)/sizeof(struct tlv_to_config_name); i++) { 210 | if (tlv_id == maps[i].tlv_id) { 211 | return &maps[i]; 212 | } 213 | } 214 | return NULL; 215 | } 216 | 217 | struct tlv_to_config_name* find_tlv_11be_config(int tlv_id) { 218 | int i; 219 | for (i = 0; i < sizeof(wifi7_maps)/sizeof(struct tlv_to_config_name); i++) { 220 | if (tlv_id == wifi7_maps[i].tlv_id) { 221 | return &wifi7_maps[i]; 222 | } 223 | } 224 | return NULL; 225 | } 226 | 227 | struct tlv_to_config_name wpas_global_maps[] = { 228 | { TLV_STA_SAE_GROUPS, "sae_groups", 0 }, 229 | { TLV_MBO_CELL_CAPA, "mbo_cell_capa", 0 }, 230 | { TLV_SAE_PWE, "sae_pwe", 0 }, 231 | { TLV_CONTROL_INTERFACE, "ctrl_interface", 0 }, 232 | { TLV_RAND_MAC_ADDR, "mac_addr", 0 }, 233 | { TLV_PREASSOC_RAND_MAC_ADDR, "preassoc_mac_addr", 0 }, 234 | { TLV_RAND_ADDR_LIFETIME, "rand_addr_lifetime", 0 }, 235 | { TLV_HS20, "hs20", 0 }, 236 | { TLV_INTERWORKING, "interworking", 0 }, 237 | { TLV_HESSID, "hessid", 0 }, 238 | { TLV_ACCESS_NETWORK_TYPE, "access_network_type", 0 }, 239 | { TLV_FREQ_LIST, "freq_list", 0 }, 240 | { TLV_UPDATE_CONFIG, "update_config", 0 }, 241 | { TLV_P2P_DISABLED, "p2p_disabled", 0 }, 242 | { TLV_MLD_FORCE_SINGLE_LINK, "mld_force_single_link", 0 }, 243 | { TLV_MLD_CONNECT_BAND_PREF, "mld_connect_band_pref", 0 }, 244 | }; 245 | 246 | struct tlv_to_config_name* find_wpas_global_config_name(int tlv_id) { 247 | int i; 248 | for (i = 0; i < sizeof(wpas_global_maps)/sizeof(struct tlv_to_config_name); i++) { 249 | if (tlv_id == wpas_global_maps[i].tlv_id) { 250 | return &wpas_global_maps[i]; 251 | } 252 | } 253 | return NULL; 254 | } 255 | 256 | struct tlv_to_config_name* find_generic_tlv_config(int tlv_id, struct tlv_to_config_name* arr, int arr_size) { 257 | int i; 258 | for (i = 0; i < arr_size; i++) { 259 | if (tlv_id == (arr + i)->tlv_id) { 260 | return (arr + i); 261 | } 262 | } 263 | return NULL; 264 | } 265 | 266 | /* Basic */ 267 | static int get_control_app_handler(struct packet_wrapper *req, struct packet_wrapper *resp); 268 | static int start_loopback_server(struct packet_wrapper *req, struct packet_wrapper *resp); 269 | static int stop_loop_back_server_handler(struct packet_wrapper *req, struct packet_wrapper *resp); 270 | static int send_loopback_data_handler(struct packet_wrapper *req, struct packet_wrapper *resp); 271 | static int stop_loopback_data_handler(struct packet_wrapper *req, struct packet_wrapper *resp); 272 | static int create_bridge_network_handler(struct packet_wrapper *req, struct packet_wrapper *resp); 273 | static int assign_static_ip_handler(struct packet_wrapper *req, struct packet_wrapper *resp); 274 | static int get_mac_addr_handler(struct packet_wrapper *req, struct packet_wrapper *resp); 275 | static int get_ip_addr_handler(struct packet_wrapper *req, struct packet_wrapper *resp); 276 | static int reset_device_handler(struct packet_wrapper *req, struct packet_wrapper *resp); 277 | static int start_dhcp_handler(struct packet_wrapper *req, struct packet_wrapper *resp); 278 | static int stop_dhcp_handler(struct packet_wrapper *req, struct packet_wrapper *resp); 279 | static int get_wsc_pin_handler(struct packet_wrapper *req, struct packet_wrapper *resp); 280 | static int get_wsc_cred_handler(struct packet_wrapper *req, struct packet_wrapper *resp); 281 | /* AP */ 282 | static int stop_ap_handler(struct packet_wrapper *req, struct packet_wrapper *resp); 283 | static int configure_ap_handler(struct packet_wrapper *req, struct packet_wrapper *resp); 284 | static int start_ap_handler(struct packet_wrapper *req, struct packet_wrapper *resp); 285 | static int send_ap_disconnect_handler(struct packet_wrapper *req, struct packet_wrapper *resp); 286 | static int set_ap_parameter_handler(struct packet_wrapper *req, struct packet_wrapper *resp); 287 | static int send_ap_btm_handler(struct packet_wrapper *req, struct packet_wrapper *resp); 288 | static int trigger_ap_channel_switch(struct packet_wrapper *req, struct packet_wrapper *resp); 289 | static int send_ap_arp_handler(struct packet_wrapper *req, struct packet_wrapper *resp); 290 | static int start_wps_ap_handler(struct packet_wrapper *req, struct packet_wrapper *resp); 291 | static int configure_ap_wsc_handler(struct packet_wrapper *req, struct packet_wrapper *resp); 292 | static int rekey_ap_gtk_handler(struct packet_wrapper *req, struct packet_wrapper *resp); 293 | /* STA */ 294 | static int stop_sta_handler(struct packet_wrapper *req, struct packet_wrapper *resp); 295 | static int configure_sta_handler(struct packet_wrapper *req, struct packet_wrapper *resp); 296 | static int associate_sta_handler(struct packet_wrapper *req, struct packet_wrapper *resp); 297 | static int start_up_sta_handler(struct packet_wrapper *req, struct packet_wrapper *resp); 298 | static int send_sta_disconnect_handler(struct packet_wrapper *req, struct packet_wrapper *resp); 299 | static int send_sta_reconnect_handler(struct packet_wrapper *req, struct packet_wrapper *resp); 300 | static int send_sta_btm_query_handler(struct packet_wrapper *req, struct packet_wrapper *resp); 301 | static int send_sta_anqp_query_handler(struct packet_wrapper *req, struct packet_wrapper *resp); 302 | static int sta_scan_handler(struct packet_wrapper *req, struct packet_wrapper *resp); 303 | static int set_sta_parameter_handler(struct packet_wrapper *req, struct packet_wrapper *resp); 304 | static int set_sta_hs2_associate_handler(struct packet_wrapper *req, struct packet_wrapper *resp); 305 | static int sta_add_credential_handler(struct packet_wrapper *req, struct packet_wrapper *resp); 306 | static int set_sta_install_ppsmo_handler(struct packet_wrapper *req, struct packet_wrapper *resp); 307 | static int set_sta_phy_mode_handler(struct packet_wrapper *req, struct packet_wrapper *resp); 308 | static int set_sta_channel_width_handler(struct packet_wrapper *req, struct packet_wrapper *resp); 309 | static int set_sta_power_save_handler(struct packet_wrapper *req, struct packet_wrapper *resp); 310 | static int start_wps_sta_handler(struct packet_wrapper *req, struct packet_wrapper *resp); 311 | static int send_sta_icon_req_handler(struct packet_wrapper *req, struct packet_wrapper *resp); 312 | static int enable_wsc_sta_handler(struct packet_wrapper *req, struct packet_wrapper *resp); 313 | static int set_sta_inject_start_handler(struct packet_wrapper *req, struct packet_wrapper *resp); 314 | static int set_sta_inject_frame_handler(struct packet_wrapper *req, struct packet_wrapper *resp); 315 | static int set_sta_inject_stop_handler(struct packet_wrapper *req, struct packet_wrapper *resp); 316 | /* P2P */ 317 | static int start_up_p2p_handler(struct packet_wrapper *req, struct packet_wrapper *resp); 318 | static int p2p_find_handler(struct packet_wrapper *req, struct packet_wrapper *resp); 319 | static int p2p_listen_handler(struct packet_wrapper *req, struct packet_wrapper *resp); 320 | static int add_p2p_group_handler(struct packet_wrapper *req, struct packet_wrapper *resp); 321 | static int stop_p2p_group_handler(struct packet_wrapper *req, struct packet_wrapper *resp); 322 | static int p2p_start_wps_handler(struct packet_wrapper *req, struct packet_wrapper *resp); 323 | static int p2p_connect_handler(struct packet_wrapper *req, struct packet_wrapper *resp); 324 | static int get_p2p_intent_value_handler(struct packet_wrapper *req, struct packet_wrapper *resp); 325 | static int p2p_invite_handler(struct packet_wrapper *req, struct packet_wrapper *resp); 326 | static int set_p2p_serv_disc_handler(struct packet_wrapper *req, struct packet_wrapper *resp); 327 | static int set_p2p_ext_listen_handler(struct packet_wrapper *req, struct packet_wrapper *resp); 328 | /* Sniffer */ 329 | static int sniffer_start_handler(struct packet_wrapper *req, struct packet_wrapper *resp); 330 | static int sniffer_stop_handler(struct packet_wrapper *req, struct packet_wrapper *resp); 331 | static int sniffer_filter_handler(struct packet_wrapper *req, struct packet_wrapper *resp); 332 | static int sniffer_upload_file_handler(struct packet_wrapper *req, struct packet_wrapper *resp); 333 | #endif // __INDIGO_API_CALLBACK 334 | -------------------------------------------------------------------------------- /indigo_api_callback_sniffer.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2020 Wi-Fi Alliance */ 2 | 3 | /* Permission to use, copy, modify, and/or distribute this software for any */ 4 | /* purpose with or without fee is hereby granted, provided that the above */ 5 | /* copyright notice and this permission notice appear in all copies. */ 6 | 7 | /* THE SOFTWARE IS PROVIDED 'AS IS' AND THE AUTHOR DISCLAIMS ALL */ 8 | /* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED */ 9 | /* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL */ 10 | /* THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR */ 11 | /* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING */ 12 | /* FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF */ 13 | /* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT */ 14 | /* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS */ 15 | /* SOFTWARE. */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include "indigo_api.h" 26 | #include "vendor_specific.h" 27 | #include "utils.h" 28 | #include "wpa_ctrl.h" 29 | #include "indigo_api_callback.h" 30 | 31 | extern struct sockaddr_in *tool_addr; 32 | 33 | void register_apis() { 34 | /* Basic */ 35 | register_api(API_GET_CONTROL_APP_VERSION, NULL, get_control_app_handler); 36 | register_api(API_SNIFFER_START, NULL, sniffer_start_handler); 37 | register_api(API_SNIFFER_STOP, NULL, sniffer_stop_handler); 38 | register_api(API_SNIFFER_UPLOAD_FILE, NULL, sniffer_upload_file_handler); 39 | register_api(API_SNIFFER_FILTER, NULL, sniffer_filter_handler); 40 | } 41 | 42 | static int get_control_app_handler(struct packet_wrapper *req, struct packet_wrapper *resp) { 43 | char buffer[S_BUFFER_LEN]; 44 | #ifdef _VERSION_ 45 | snprintf(buffer, sizeof(buffer), "%s", _VERSION_); 46 | #else 47 | snprintf(buffer, sizeof(buffer), "%s", TLV_VALUE_APP_VERSION); 48 | #endif 49 | fill_wrapper_message_hdr(resp, API_CMD_RESPONSE, req->hdr.seq); 50 | fill_wrapper_tlv_byte(resp, TLV_STATUS, TLV_VALUE_STATUS_OK); 51 | fill_wrapper_tlv_bytes(resp, TLV_MESSAGE, strlen(TLV_VALUE_OK), TLV_VALUE_OK); 52 | fill_wrapper_tlv_bytes(resp, TLV_TEST_SNIFFER_APP_VERSION, 53 | strlen(buffer), buffer); 54 | return 0; 55 | } 56 | 57 | static int sniffer_start_handler(struct packet_wrapper *req, struct packet_wrapper *resp) { 58 | int status = TLV_VALUE_STATUS_NOT_OK; 59 | char *message = TLV_VALUE_NOT_OK; 60 | char buffer[S_BUFFER_LEN]; 61 | char channel[8]; 62 | char file_name[32]; 63 | struct tlv_hdr *tlv = NULL; 64 | 65 | memset(channel, 0, sizeof(channel)); 66 | tlv = find_wrapper_tlv_by_id(req, TLV_CHANNEL); 67 | if (tlv) { 68 | snprintf(buffer, sizeof(buffer), "ifconfig mon0 up"); 69 | system(buffer); 70 | sleep(1); 71 | memcpy(channel, tlv->value, tlv->len); 72 | snprintf(buffer, sizeof(buffer), "iw dev mon0 set channel %s 80MHz", channel); 73 | system(buffer); 74 | } else { 75 | indigo_logger(LOG_LEVEL_ERROR, "TLV CHANNEL is missing"); 76 | goto done; 77 | } 78 | 79 | memset(file_name, 0, sizeof(file_name)); 80 | tlv = find_wrapper_tlv_by_id(req, TLV_CAPTURE_FILE); 81 | if (tlv) { 82 | memcpy(file_name, tlv->value, tlv->len); 83 | unlink(file_name); 84 | snprintf(buffer, sizeof(buffer), "tcpdump -i mon0 -w %s &", file_name); 85 | system(buffer); 86 | sleep(3); 87 | } else { 88 | indigo_logger(LOG_LEVEL_ERROR, "TLV CAPTURE_FILE is missing"); 89 | goto done; 90 | } 91 | 92 | status = TLV_VALUE_STATUS_OK; 93 | message = TLV_VALUE_OK; 94 | 95 | done: 96 | fill_wrapper_message_hdr(resp, API_CMD_RESPONSE, req->hdr.seq); 97 | fill_wrapper_tlv_byte(resp, TLV_STATUS, status); 98 | fill_wrapper_tlv_bytes(resp, TLV_MESSAGE, strlen(message), message); 99 | 100 | return 0; 101 | } 102 | 103 | static int sniffer_stop_handler(struct packet_wrapper *req, struct packet_wrapper *resp) { 104 | int status = TLV_VALUE_STATUS_NOT_OK; 105 | char *message = TLV_VALUE_NOT_OK; 106 | char buffer[S_BUFFER_LEN]; 107 | 108 | snprintf(buffer, sizeof(buffer), "killall tcpdump"); 109 | if (system(buffer) != 0) { 110 | indigo_logger(LOG_LEVEL_ERROR, "Failed to shutdown tcpdump\n"); 111 | goto done; 112 | } 113 | 114 | status = TLV_VALUE_STATUS_OK; 115 | message = TLV_VALUE_OK; 116 | 117 | done: 118 | fill_wrapper_message_hdr(resp, API_CMD_RESPONSE, req->hdr.seq); 119 | fill_wrapper_tlv_byte(resp, TLV_STATUS, status); 120 | fill_wrapper_tlv_bytes(resp, TLV_MESSAGE, strlen(message), message); 121 | 122 | return 0; 123 | } 124 | 125 | static int sniffer_filter_handler(struct packet_wrapper *req, struct packet_wrapper *resp) { 126 | int status = TLV_VALUE_STATUS_NOT_OK; 127 | char *message = TLV_VALUE_NOT_OK; 128 | char buffer[BUFFER_LEN]; 129 | char filter[TLV_VALUE_SIZE]; 130 | char infile_name[TLV_VALUE_SIZE]; 131 | char outfile_name[TLV_VALUE_SIZE]; 132 | struct tlv_hdr *tlv = NULL; 133 | 134 | tlv = find_wrapper_tlv_by_id(req, TLV_CAPTURE_FILTER); 135 | if (tlv) { 136 | memset(filter, 0, sizeof(filter)); 137 | memcpy(filter, tlv->value, tlv->len); 138 | 139 | } else { 140 | indigo_logger(LOG_LEVEL_ERROR, "TLV CAPTURE_FILTER is missing"); 141 | goto done; 142 | } 143 | 144 | tlv = find_wrapper_tlv_by_id(req, TLV_CAPTURE_INFILE); 145 | if (tlv) { 146 | memset(infile_name, 0, sizeof(infile_name)); 147 | memcpy(infile_name, tlv->value, tlv->len); 148 | } else { 149 | indigo_logger(LOG_LEVEL_ERROR, "TLV CAPTURE_INFILE is missing"); 150 | goto done; 151 | } 152 | 153 | tlv = find_wrapper_tlv_by_id(req, TLV_CAPTURE_OUTFILE); 154 | if (tlv) { 155 | memset(outfile_name, 0, sizeof(outfile_name)); 156 | memcpy(outfile_name, tlv->value, tlv->len); 157 | 158 | snprintf(buffer, sizeof(buffer), "tshark -r %s -Y '%s' -w %s", infile_name, filter, outfile_name); 159 | indigo_logger(LOG_LEVEL_INFO, "Run: %s", buffer); 160 | system(buffer); 161 | 162 | if (!file_exists(outfile_name)) { 163 | indigo_logger(LOG_LEVEL_ERROR, "CAPTURE_OUTFILE file %s does not exist", outfile_name); 164 | goto done; 165 | } 166 | 167 | } else { 168 | indigo_logger(LOG_LEVEL_ERROR, "TLV CAPTURE_OUTFILE is missing"); 169 | goto done; 170 | } 171 | 172 | status = TLV_VALUE_STATUS_OK; 173 | message = TLV_VALUE_OK; 174 | 175 | done: 176 | fill_wrapper_message_hdr(resp, API_CMD_RESPONSE, req->hdr.seq); 177 | fill_wrapper_tlv_byte(resp, TLV_STATUS, status); 178 | fill_wrapper_tlv_bytes(resp, TLV_MESSAGE, strlen(message), message); 179 | 180 | return 0; 181 | } 182 | 183 | static int sniffer_upload_file_handler(struct packet_wrapper *req, struct packet_wrapper *resp) { 184 | int status = TLV_VALUE_STATUS_NOT_OK; 185 | char *message = TLV_VALUE_NOT_OK; 186 | char buffer[BUFFER_LEN]; 187 | char file_name[TLV_VALUE_SIZE]; 188 | struct tlv_hdr *tlv = NULL; 189 | 190 | memset(file_name, 0, sizeof(file_name)); 191 | tlv = find_wrapper_tlv_by_id(req, TLV_CAPTURE_FILE); 192 | if (tlv) { 193 | memcpy(file_name, tlv->value, tlv->len); 194 | 195 | if (!file_exists(file_name)) { 196 | indigo_logger(LOG_LEVEL_ERROR, "file %s does not exist", file_name); 197 | goto done; 198 | } 199 | 200 | if (tool_addr != NULL) { 201 | snprintf(buffer, sizeof(buffer), "curl -v -F TestArtifacts=@%s http://%s:%d%s", file_name, inet_ntoa(tool_addr->sin_addr), TOOL_POST_PORT, ARTIFACTS_UPLOAD_API); 202 | indigo_logger(LOG_LEVEL_INFO, "Run: %s", buffer); 203 | system(buffer); 204 | } 205 | 206 | } else { 207 | indigo_logger(LOG_LEVEL_ERROR, "TLV CAPTURE_FILE is missing"); 208 | goto done; 209 | } 210 | 211 | status = TLV_VALUE_STATUS_OK; 212 | message = TLV_VALUE_OK; 213 | 214 | done: 215 | fill_wrapper_message_hdr(resp, API_CMD_RESPONSE, req->hdr.seq); 216 | fill_wrapper_tlv_byte(resp, TLV_STATUS, status); 217 | fill_wrapper_tlv_bytes(resp, TLV_MESSAGE, strlen(message), message); 218 | 219 | return 0; 220 | } -------------------------------------------------------------------------------- /indigo_packet.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2020 Wi-Fi Alliance */ 2 | 3 | /* Permission to use, copy, modify, and/or distribute this software for any */ 4 | /* purpose with or without fee is hereby granted, provided that the above */ 5 | /* copyright notice and this permission notice appear in all copies. */ 6 | 7 | /* THE SOFTWARE IS PROVIDED 'AS IS' AND THE AUTHOR DISCLAIMS ALL */ 8 | /* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED */ 9 | /* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL */ 10 | /* THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR */ 11 | /* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING */ 12 | /* FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF */ 13 | /* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT */ 14 | /* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS */ 15 | /* SOFTWARE. */ 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | #include "vendor_specific.h" 22 | #include "indigo_api.h" 23 | #include "utils.h" 24 | 25 | int capture_packet = 0, capture_count = 0; /* debug. Write the received packets to files */ 26 | int debug_packet = 0; /* used by the packet hexstring print */ 27 | 28 | /* Parse the QuickTrack message from the packet to the wrapper */ 29 | int parse_packet(struct packet_wrapper *req, char *packet, int packet_len) { 30 | int i = 0, parser = 0, ret = 0; 31 | struct indigo_api *api = NULL; 32 | struct indigo_tlv *tlv = NULL; 33 | 34 | /* Print the debug message */ 35 | if (debug_packet) 36 | print_hex(packet, packet_len); 37 | 38 | /* Parse the message header */ 39 | ret = parse_message_hdr(&req->hdr, packet, packet_len); 40 | if (ret > 0) { 41 | if (debug_packet) { 42 | print_message_hdr(&req->hdr); 43 | } 44 | parser += ret; 45 | } else { 46 | return -1; 47 | } 48 | 49 | /* Parse the TLVs */ 50 | while (packet_len - parser > 0) { 51 | req->tlv[req->tlv_num] = (struct tlv_hdr *)malloc(sizeof(struct tlv_hdr)); 52 | memset(req->tlv[req->tlv_num], 0, sizeof(struct tlv_hdr)); 53 | 54 | ret = parse_tlv(req->tlv[req->tlv_num], packet + parser, packet_len - parser); 55 | if (ret > 0) { 56 | if (debug_packet) { 57 | print_tlv(req->tlv[req->tlv_num]); 58 | } 59 | 60 | req->tlv_num++; 61 | parser += ret; 62 | } else { 63 | break; 64 | } 65 | } 66 | 67 | api = get_api_by_id(req->hdr.type); 68 | if (api) { 69 | if (!debug_packet) 70 | indigo_logger(LOG_LEVEL_INFO, "API: 0x%04x (%s)", api->type, api->name); 71 | } else { 72 | indigo_logger(LOG_LEVEL_WARNING, "API: 0x%04x Unknown", req->hdr.type); 73 | return -1; 74 | } 75 | 76 | for (i = 0; i < req->tlv_num; i++) { 77 | tlv = get_tlv_by_id(req->tlv[i]->id); 78 | if (tlv) { 79 | if (!debug_packet) 80 | indigo_logger(LOG_LEVEL_INFO, " TLV: 0x%04x (%s)", tlv->id, tlv->name); 81 | } else { 82 | indigo_logger(LOG_LEVEL_WARNING, " TLV: 0x%04x Unknown", req->tlv[i]->id); 83 | return -1; 84 | } 85 | } 86 | 87 | /* Only for the debug purpose. Write the received packet to files */ 88 | if (capture_packet) { 89 | char fn[S_BUFFER_LEN], value[8]; 90 | char *buffer; 91 | int buffer_len = packet_len*6; 92 | api = get_api_by_id(req->hdr.type); 93 | if (api) { 94 | sprintf(fn, "%02d_%s", capture_count++, api->name); 95 | } 96 | buffer = (char*)malloc(sizeof(char)*buffer_len); 97 | if (!buffer) { 98 | return 0; 99 | } 100 | memset(buffer, 0, buffer_len); 101 | for (i = 0; i < packet_len; i++) { 102 | memset(value, 0, sizeof(value)); 103 | sprintf(value, "0x%02x%s", (unsigned char)(packet[i]&0x00ff), (itlv[i]) { 119 | if (wrapper->tlv[i]->id == id) { 120 | return wrapper->tlv[i]; 121 | } 122 | } 123 | } 124 | 125 | return NULL; 126 | } 127 | 128 | /* Free the wrapper malloc's memory */ 129 | int free_packet_wrapper(struct packet_wrapper *wrapper) { 130 | int i = 0; 131 | 132 | for (i = 0; i < TLV_NUM; i++) { 133 | if (wrapper->tlv[i]) { 134 | if (wrapper->tlv[i]->value) { 135 | free(wrapper->tlv[i]->value); 136 | } 137 | free(wrapper->tlv[i]); 138 | } 139 | } 140 | memset(wrapper, 0, sizeof(struct packet_wrapper)); 141 | 142 | return 0; 143 | } 144 | 145 | /* Parse the message header */ 146 | int parse_message_hdr(struct message_hdr *hdr, char *message, int message_len) { 147 | if (message_len < sizeof(struct message_hdr)) { 148 | return -1; 149 | } 150 | 151 | hdr->version = message[0]; 152 | hdr->type = ((message[1] & 0x00ff) << 8) | (message[2] & 0x00ff); 153 | hdr->seq = ((message[3] & 0x00ff) << 8) | (message[4] & 0x00ff); 154 | hdr->reserved = message[5]; 155 | hdr->reserved2 = message[6]; 156 | 157 | return sizeof(struct message_hdr); 158 | } 159 | 160 | /* Convert the packet message header from the structure */ 161 | int gen_message_hdr(char *message, int message_len, struct message_hdr *hdr) { 162 | int len = 0; 163 | 164 | if (message_len < sizeof(struct message_hdr)) { 165 | return -1; 166 | } 167 | 168 | message[len++] = hdr->version; 169 | message[len++] = (char) (hdr->type >> 8); 170 | message[len++] = (char) (hdr->type & 0x00ff); 171 | message[len++] = (char) (hdr->seq >> 8); 172 | message[len++] = (char) (hdr->seq & 0x00ff); 173 | message[len++] = hdr->reserved; 174 | message[len++] = hdr->reserved2; 175 | 176 | return sizeof(struct message_hdr); 177 | } 178 | 179 | /* Print the header */ 180 | void print_message_hdr(struct message_hdr *hdr) { 181 | indigo_logger(LOG_LEVEL_INFO, "Version: %d", hdr->version); 182 | indigo_logger(LOG_LEVEL_INFO, "Type: 0x%04x (%s)", hdr->type, get_api_type_by_id(hdr->type)); 183 | indigo_logger(LOG_LEVEL_INFO, "Sequence: 0x%04x", hdr->seq); 184 | indigo_logger(LOG_LEVEL_INFO, "Reserved: 0x%02x", hdr->reserved); 185 | indigo_logger(LOG_LEVEL_INFO, "Reserved2: 0x%02x", hdr->reserved2); 186 | } 187 | 188 | /* Print the hexstring of the specific range */ 189 | int print_hex(char *message, int message_len) { 190 | int i; 191 | for(i = 0; i < message_len; i++) { 192 | printf("0x%02x ", (unsigned char)message[i]); 193 | } 194 | printf("\n\n"); 195 | return 0; 196 | } 197 | 198 | /* Add the TLV to the wrapper */ 199 | int add_wrapper_tlv(struct packet_wrapper *wrapper, int id, int len, char *value) { 200 | if (add_tlv(wrapper->tlv[wrapper->tlv_num], id, len, value) == 0) { 201 | wrapper->tlv_num++; 202 | return 0; 203 | } 204 | return 1; 205 | } 206 | 207 | /* Fill the TLV with the ID, length and value */ 208 | int add_tlv(struct tlv_hdr *tlv, int id, int len, char *value) { 209 | if (!tlv) 210 | return 1; 211 | tlv->id = id; 212 | tlv->len = len; 213 | tlv->value = (char*)malloc(sizeof(char)*len); 214 | memcpy(tlv->value, value, len); 215 | return 0; 216 | } 217 | 218 | /* Parse the TLV from the packet to the structure */ 219 | int parse_tlv(struct tlv_hdr *tlv, char *packet, int packet_len) { 220 | if (packet_len < 3) { 221 | return -1; 222 | } 223 | 224 | tlv->id = ((packet[0] & 0x00ff) << 8) | (packet[1] & 0x00ff); 225 | tlv->len = packet[2]; 226 | tlv->value = (char*)malloc(sizeof(char) * tlv->len); 227 | memcpy(tlv->value, &packet[3], tlv->len); 228 | 229 | return tlv->len+3; 230 | } 231 | 232 | /* Convert the TLV structure to the packet */ 233 | int gen_tlv(char *packet, int packet_size, struct tlv_hdr *t) { 234 | int len = 0; 235 | 236 | if (packet_size < t->len + 3) { 237 | return -1; 238 | } 239 | 240 | packet[len++] = (char) (t->id >> 8); 241 | packet[len++] = (char) (t->id & 0x00ff); 242 | packet[len++] = t->len; 243 | memcpy(&packet[len], t->value, t->len); 244 | len += t->len; 245 | 246 | return len; 247 | } 248 | 249 | /* Print the TLV */ 250 | void print_tlv(struct tlv_hdr *t) { 251 | int i = 0; 252 | char buffer[S_BUFFER_LEN], value[S_BUFFER_LEN]; 253 | struct indigo_tlv *tlv = get_tlv_by_id(t->id); 254 | 255 | memset(buffer, 0, sizeof(buffer)); 256 | memset(value, 0, sizeof(value)); 257 | 258 | indigo_logger(LOG_LEVEL_INFO, " ID: 0x%04x (%s)", t->id, tlv == NULL ? "Unknown" : tlv->name); 259 | indigo_logger(LOG_LEVEL_INFO, " Length: %d", t->len); 260 | 261 | if (t->len > 0) { 262 | sprintf(buffer, " Value: "); 263 | } 264 | for (i = 0; i < t->len; i++) { 265 | sprintf(value, "%02x ", t->value[i]); 266 | strcat(buffer, value); 267 | } 268 | indigo_logger(LOG_LEVEL_INFO, buffer); 269 | } 270 | 271 | /* Convert the wrapper to the packet includes the message header and all TLVs. Used by the ACK and resposne */ 272 | int assemble_packet(char *packet, int packet_size, struct packet_wrapper *wrapper) { 273 | int i = 0, ret = 0, packet_len = 0; 274 | 275 | ret = gen_message_hdr(packet, packet_size, &wrapper->hdr); 276 | packet_len += ret; 277 | 278 | for (i = 0; i < wrapper->tlv_num; i++) { 279 | ret = gen_tlv(packet + packet_len, packet_size - packet_len, wrapper->tlv[i]); 280 | if (ret) { 281 | packet_len += ret; 282 | } else { 283 | break; 284 | } 285 | } 286 | 287 | if (debug_packet) 288 | print_hex(packet, packet_len); 289 | 290 | return packet_len; 291 | } 292 | -------------------------------------------------------------------------------- /indigo_packet.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2020 Wi-Fi Alliance */ 2 | 3 | /* Permission to use, copy, modify, and/or distribute this software for any */ 4 | /* purpose with or without fee is hereby granted, provided that the above */ 5 | /* copyright notice and this permission notice appear in all copies. */ 6 | 7 | /* THE SOFTWARE IS PROVIDED 'AS IS' AND THE AUTHOR DISCLAIMS ALL */ 8 | /* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED */ 9 | /* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL */ 10 | /* THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR */ 11 | /* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING */ 12 | /* FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF */ 13 | /* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT */ 14 | /* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS */ 15 | /* SOFTWARE. */ 16 | 17 | #ifndef _INDIGO_PACKET_ 18 | #define _INDIGO_PACKET_ 19 | 20 | #define TLV_NUM 128 21 | #define TLV_VALUE_SIZE 256 22 | 23 | /* Packet structure */ 24 | struct __attribute__((__packed__)) message_hdr { 25 | unsigned char version; 26 | unsigned short type; 27 | unsigned short seq; 28 | unsigned char reserved; 29 | unsigned char reserved2; 30 | }; 31 | 32 | struct __attribute__((__packed__)) tlv_hdr { 33 | unsigned short id; 34 | unsigned char len; 35 | unsigned char *value; 36 | }; 37 | 38 | struct packet_wrapper { 39 | struct message_hdr hdr; 40 | struct tlv_hdr *tlv[TLV_NUM]; 41 | int tlv_num; 42 | }; 43 | 44 | /* API */ 45 | int assemble_packet(char *packet, int packet_size, struct packet_wrapper *wrapper); 46 | int parse_packet(struct packet_wrapper *req, char *packet, int packet_len); 47 | int free_packet_wrapper(struct packet_wrapper *wrapper); 48 | 49 | /* Debug */ 50 | int print_hex(char *message, int message_len); 51 | 52 | /* Message header */ 53 | int parse_message_hdr(struct message_hdr *hdr, char *message, int message_len); 54 | int add_message_hdr(char *message, int message_len, struct message_hdr *hdr); 55 | void print_message_hdr(struct message_hdr *hdr); 56 | 57 | /* TLV header */ 58 | int parse_tlv(struct tlv_hdr *tlv, char *message, int message_len); 59 | int gen_tlv(char *message, int message_len, struct tlv_hdr *t); 60 | void print_tlv(struct tlv_hdr *t); 61 | struct tlv_hdr *find_wrapper_tlv_by_id(struct packet_wrapper *wrapper, int id); 62 | int add_wrapper_tlv(struct packet_wrapper *wrapper, int id, int len, char *value); 63 | 64 | int add_tlv(struct tlv_hdr *tlv, int id, int len, char *value); 65 | #endif /* _INDIGO_PACKET_ */ 66 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2020 Wi-Fi Alliance */ 2 | 3 | /* Permission to use, copy, modify, and/or distribute this software for any */ 4 | /* purpose with or without fee is hereby granted, provided that the above */ 5 | /* copyright notice and this permission notice appear in all copies. */ 6 | 7 | /* THE SOFTWARE IS PROVIDED 'AS IS' AND THE AUTHOR DISCLAIMS ALL */ 8 | /* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED */ 9 | /* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL */ 10 | /* THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR */ 11 | /* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING */ 12 | /* FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF */ 13 | /* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT */ 14 | /* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS */ 15 | /* SOFTWARE. */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #include "vendor_specific.h" 33 | #include "eloop.h" 34 | #include "indigo_api.h" 35 | #include "utils.h" 36 | 37 | 38 | /* Internal functions */ 39 | static void control_receive_message(int sock, void *eloop_ctx, void *sock_ctx); 40 | static int parse_parameters(int argc, char *argv[]); 41 | static void usage(); 42 | 43 | /* External variables */ 44 | extern int capture_packet; /* debug. Write the received packets to files */ 45 | extern int debug_packet; /* used by the packet hexstring print */ 46 | 47 | /* Initiate the service port. */ 48 | static int control_socket_init(int port) { 49 | int s = -1; 50 | char cmd[S_BUFFER_LEN]; 51 | struct sockaddr_in addr; 52 | 53 | /* Open UDP socket */ 54 | s = socket(PF_INET, SOCK_DGRAM, 0); 55 | if (s < 0) { 56 | indigo_logger(LOG_LEVEL_ERROR, "Failed to open server socket: %s", strerror(errno)); 57 | return -1; 58 | } 59 | 60 | /* Bind specific port */ 61 | memset(&addr, 0, sizeof(addr)); 62 | addr.sin_family = AF_INET; 63 | addr.sin_port = htons(port); 64 | if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 65 | indigo_logger(LOG_LEVEL_ERROR, "Failed to bind server socket: %s", strerror(errno)); 66 | if (errno == EADDRINUSE) { 67 | sprintf(cmd, "netstat -lunatp | grep %d", port); 68 | system(cmd); 69 | } 70 | close(s); 71 | return -1; 72 | } 73 | 74 | /* Register to eloop and ready for the socket event */ 75 | if (eloop_register_read_sock(s, control_receive_message, NULL, NULL)) { 76 | indigo_logger(LOG_LEVEL_ERROR, "Failed to initiate ControlAppC"); 77 | close(s); 78 | return -1; 79 | } 80 | return s; 81 | } 82 | 83 | struct sockaddr_in *tool_addr; // For HTTP Post 84 | /* Callback function of the QuickTrack API. */ 85 | static void control_receive_message(int sock, void *eloop_ctx, void *sock_ctx) { 86 | int ret; // return code 87 | int fromlen, len; // structure size and received length 88 | struct sockaddr_storage from; // source address of the message 89 | unsigned char buffer[BUFFER_LEN]; // buffer to receive the message 90 | struct packet_wrapper req, resp; // packet wrapper for the received message and response 91 | struct indigo_api *api = NULL; // used for API search, validation and handler call 92 | 93 | /* Receive request */ 94 | fromlen = sizeof(from); 95 | len = recvfrom(sock, buffer, BUFFER_LEN, 0, (struct sockaddr *) &from, (socklen_t*)&fromlen); 96 | if (len < 0) { 97 | indigo_logger(LOG_LEVEL_ERROR, "Server: Failed to receive the packet"); 98 | return ; 99 | } else { 100 | indigo_logger(LOG_LEVEL_DEBUG, "Server: Receive the packet"); 101 | } 102 | tool_addr = (struct sockaddr_in *)&from; 103 | 104 | /* Parse request to HDR and TLV. Response NACK if parser fails. Otherwises, ACK. */ 105 | memset(&req, 0, sizeof(struct packet_wrapper)); 106 | memset(&resp, 0, sizeof(struct packet_wrapper)); 107 | ret = parse_packet(&req, buffer, len); 108 | if (ret == 0) { 109 | indigo_logger(LOG_LEVEL_DEBUG, "Server: Parsed packet successfully"); 110 | } else { 111 | indigo_logger(LOG_LEVEL_ERROR, "Server: Failed to parse the packet"); 112 | fill_wrapper_ack(&resp, req.hdr.seq, 0x31, "Unable to parse the packet"); 113 | len = assemble_packet(buffer, BUFFER_LEN, &resp); 114 | 115 | sendto(sock, (const char *)buffer, len, MSG_CONFIRM, (const struct sockaddr *) &from, fromlen); 116 | goto done; 117 | } 118 | 119 | /* Find API by ID. If API is not supported, assemble NACK. */ 120 | api = get_api_by_id(req.hdr.type); 121 | if (api) { 122 | indigo_logger(LOG_LEVEL_DEBUG, "API %s: Found handler", api->name); 123 | } else { 124 | indigo_logger(LOG_LEVEL_ERROR, "API Unknown (0x%04x): No registered handler", req.hdr.type); 125 | fill_wrapper_ack(&resp, req.hdr.seq, 0x31, "Unable to find the API handler"); 126 | len = assemble_packet(buffer, BUFFER_LEN, &resp); 127 | sendto(sock, (const char *)buffer, len, MSG_CONFIRM, (const struct sockaddr *) &from, fromlen); 128 | goto done; 129 | } 130 | 131 | /* Verify. Optional. If validation is failed, then return NACK. */ 132 | if (api->verify == NULL || (api->verify && api->verify(&req, &resp) == 0)) { 133 | indigo_logger(LOG_LEVEL_INFO, "API %s: Return ACK", api->name); 134 | fill_wrapper_ack(&resp, req.hdr.seq, 0x30, "ACK: Command received"); 135 | len = assemble_packet(buffer, BUFFER_LEN, &resp); 136 | sendto(sock, (const char *)buffer, len, MSG_CONFIRM, (const struct sockaddr *) &from, fromlen); 137 | free_packet_wrapper(&resp); 138 | } else { 139 | indigo_logger(LOG_LEVEL_ERROR, "API %s: Failed to verify and return NACK", api->name); 140 | fill_wrapper_ack(&resp, req.hdr.seq, 1, "Unable to find the API handler"); 141 | len = assemble_packet(buffer, BUFFER_LEN, &resp); 142 | sendto(sock, (const char *)buffer, len, MSG_CONFIRM, (const struct sockaddr *) &from, fromlen); 143 | goto done; 144 | } 145 | 146 | /* Optional, use timer to handle the execution */ 147 | /* Handle & Response. Call API handle(), assemble packet by response wrapper and send back to source address. */ 148 | if (api->handle && api->handle(&req, &resp) == 0) { 149 | indigo_logger(LOG_LEVEL_INFO, "API %s: Return execution result", api->name); 150 | len = assemble_packet(buffer, BUFFER_LEN, &resp); 151 | sendto(sock, (const char *)buffer, len, MSG_CONFIRM, (const struct sockaddr *) &from, fromlen); 152 | } else { 153 | indigo_logger(LOG_LEVEL_DEBUG, "API %s (0x%04x): No handle function", api ? api->name : "Unknown", req.hdr.type); 154 | } 155 | 156 | done: 157 | /* Clean up resource */ 158 | free_packet_wrapper(&req); 159 | free_packet_wrapper(&resp); 160 | indigo_logger(LOG_LEVEL_DEBUG, "API %s: Complete", api ? api->name : "Unknown"); 161 | } 162 | 163 | /* Show the usage */ 164 | static void usage() { 165 | printf("usage:\n"); 166 | printf("app [-h] [-p] [-i|-i:[,:]] [-a] [-s]\n\n"); 167 | printf("usage:\n"); 168 | printf(" -a = specify hostapd path\n"); 169 | printf(" -b = specify bridge name for wireless interfaces\n"); 170 | printf(" -d = debug received and sent message\n"); 171 | printf(" -i = specify the interface. E.g., -i wlan0. Or, :.\n band can be 2 for 2.4GHz, 5 for 5GHz and 6 for 6GHz. E.g., -i 2:wlan0,2:wlan1,5:wlan32,5:wlan33\n"); 172 | printf(" -p = port number of the application\n"); 173 | printf(" -s = specify wpa_supplicant path\n\n"); 174 | } 175 | 176 | /* Show the welcome message with role and version */ 177 | static void print_welcome() { 178 | #ifdef _DUT_ 179 | printf("Welcome to use QuickTrack Control App DUT version"); 180 | #elif defined(_TEST_SNIFFER_) 181 | printf("Welcome to use QuickTrack Control App Sniffer version"); 182 | #else 183 | printf("Welcome to use Quicktrack Control App Platform version"); 184 | #endif 185 | 186 | #ifdef _VERSION_ 187 | printf(" %s.\n", _VERSION_); 188 | #else 189 | printf(".\n"); 190 | #endif 191 | } 192 | 193 | /* Parse the commandline parameters */ 194 | static int parse_parameters(int argc, char *argv[]) { 195 | int c, ifs_configured = 0, bridge_configured = 0; 196 | char buf[256]; 197 | 198 | #ifdef _VERSION_ 199 | while ((c = getopt(argc, argv, "a:b:s:i:hp:dcv")) != -1) { 200 | #else 201 | while ((c = getopt(argc, argv, "a:b:s:i:hp:dc")) != -1) { 202 | #endif 203 | switch (c) { 204 | case 'a': 205 | set_hapd_full_exec_path(optarg); 206 | break; 207 | case 'b': 208 | set_wlans_bridge(optarg); 209 | bridge_configured = 1; 210 | break; 211 | case 'c': 212 | capture_packet = 1; 213 | break; 214 | case 'd': 215 | debug_packet = 1; 216 | break; 217 | case 'h': 218 | usage(); 219 | return 1; 220 | case 'i': 221 | if (set_wireless_interface(optarg) == 0) { 222 | ifs_configured = 1; 223 | } 224 | break; 225 | case 'p': 226 | set_service_port(atoi(optarg)); 227 | break; 228 | case 's': 229 | set_wpas_full_exec_path(optarg); 230 | break; 231 | #ifdef _VERSION_ 232 | case 'v': 233 | return 1; 234 | #endif 235 | } 236 | } 237 | 238 | if (optind < argc) { 239 | printf("\nInvalid option %s\n", argv[optind]); 240 | usage(); 241 | return 1; 242 | } 243 | 244 | if (ifs_configured == 0) { 245 | #ifdef DEFAULT_APP_INTERFACES_PARAMS 246 | #ifdef _OPENWRT_ 247 | if (detect_number_radio() != 2) 248 | snprintf(buf, sizeof(buf), "%s", DEFAULT_APP_6E_INTERFACES_PARAMS); 249 | else 250 | #endif 251 | snprintf(buf, sizeof(buf), "%s", DEFAULT_APP_INTERFACES_PARAMS); 252 | printf("\nUse default interface parameters %s.\n", buf); 253 | set_wireless_interface(buf); 254 | #else 255 | usage(); 256 | printf("\nWe need to specify the interfaces with -i.\n"); 257 | return 1; 258 | #endif 259 | } 260 | 261 | if (bridge_configured == 0) { 262 | set_wlans_bridge(BRIDGE_WLANS); 263 | } 264 | 265 | return 0; 266 | } 267 | 268 | static void handle_term(int sig, void *eloop_ctx, void *signal_ctx) { 269 | indigo_logger(LOG_LEVEL_INFO, "Signal %d received - terminating\n", sig); 270 | eloop_terminate(); 271 | } 272 | 273 | static void handle_sighup(int sig, void *eloop_ctx, void *signal_ctx) { 274 | indigo_logger(LOG_LEVEL_INFO, "Signal %d received - hangup\n", sig); 275 | eloop_terminate(); 276 | vendor_deinit(); 277 | } 278 | 279 | int main(int argc, char* argv[]) { 280 | int service_socket = -1; 281 | 282 | /* Welcome message */ 283 | print_welcome(); 284 | 285 | /* Initiate the application */ 286 | set_wireless_interface(WIRELESS_INTERFACE_DEFAULT); // Set default wireless interface information 287 | set_hapd_full_exec_path(HAPD_EXEC_FILE_DEFAULT); // Set default hostapd execution file path 288 | set_hapd_ctrl_path(HAPD_CTRL_PATH_DEFAULT); // Set default hostapd control interface path 289 | set_hapd_global_ctrl_path(HAPD_GLOBAL_CTRL_PATH_DEFAULT); // Set default hostapd global control interface path 290 | set_hapd_conf_file(HAPD_CONF_FILE_DEFAULT); // Set default hostapd configuration file path 291 | set_wpas_full_exec_path(WPAS_EXEC_FILE_DEFAULT); // Set default wap_supplicant execution file path 292 | set_wpas_ctrl_path(WPAS_CTRL_PATH_DEFAULT); // Set default wap_supplicant control interface path 293 | set_wpas_global_ctrl_path(WPAS_GLOBAL_CTRL_PATH_DEFAULT); // Set default wap_supplicant global control interface path 294 | set_wpas_conf_file(WPAS_CONF_FILE_DEFAULT); // Set default wap_supplicant configuration file path 295 | 296 | /* Parse the application arguments */ 297 | if (parse_parameters(argc, argv)) { 298 | return 0; 299 | } 300 | 301 | #ifndef _OPENWRT_ 302 | system("mkdir -p /etc/hostapd/"); 303 | #endif 304 | 305 | /* Print the run-time information */ 306 | indigo_logger(LOG_LEVEL_INFO, "QuickTrack control app running at: %d", get_service_port()); 307 | indigo_logger(LOG_LEVEL_INFO, "Wireless Interface:" ); 308 | show_wireless_interface_info(); 309 | indigo_logger(LOG_LEVEL_INFO, "hostapd Path: %s (%s)", get_hapd_full_exec_path(), get_hapd_exec_file()); 310 | indigo_logger(LOG_LEVEL_INFO, "wpa_supplicant Path: %s (%s)", get_wpas_full_exec_path(), get_wpas_exec_file()); 311 | 312 | /* 313 | * The following information may not help anymore since 314 | * - we support multiple vaps 315 | * - remote udp port is known only when receive the control interface TLV 316 | indigo_logger(LOG_LEVEL_INFO, "Hostapd Global Control Interface: %s", get_hapd_global_ctrl_path()); 317 | indigo_logger(LOG_LEVEL_INFO, "Hostapd Control Interface: %s", get_hapd_ctrl_path()); 318 | indigo_logger(LOG_LEVEL_INFO, "WPA Supplicant Control Interface: %s", get_wpas_ctrl_path()); 319 | */ 320 | 321 | /* Register the callback */ 322 | register_apis(); 323 | 324 | /* Intiate the vendor's specific startup commands */ 325 | vendor_init(); 326 | 327 | /* Start eloop */ 328 | eloop_init(NULL); 329 | 330 | /* Register SIGTERM */ 331 | eloop_register_signal(SIGINT, handle_term, NULL); 332 | eloop_register_signal(SIGTERM, handle_term, NULL); 333 | eloop_register_signal(SIGHUP, handle_sighup, NULL); 334 | 335 | /* Bind the service port and register to eloop */ 336 | service_socket = control_socket_init(get_service_port()); 337 | if (service_socket >= 0) { 338 | eloop_run(); 339 | } else { 340 | indigo_logger(LOG_LEVEL_INFO, "Failed to initiate the UDP socket"); 341 | } 342 | 343 | /* Stop eloop */ 344 | eloop_destroy(); 345 | indigo_logger(LOG_LEVEL_INFO, "ControlAppC stops"); 346 | if (service_socket >= 0) { 347 | indigo_logger(LOG_LEVEL_INFO, "Close service port: %d", get_service_port()); 348 | close(service_socket); 349 | } 350 | 351 | vendor_deinit(); 352 | 353 | return 0; 354 | } 355 | -------------------------------------------------------------------------------- /openwrt-controlappc-dut-makefile: -------------------------------------------------------------------------------- 1 | # Type is laptop or openwrt 2 | TYPE = openwrt 3 | # Role is dut or platform 4 | ROLE = dut 5 | 6 | OBJS = main.o eloop.o indigo_api.o indigo_packet.o utils.o wpa_ctrl.o 7 | CFLAGS += -g 8 | CFLAGS += -D_OPENWRT_ 9 | # CFLAGS += -D_WTS_OPENWRT_ 10 | CFLAGS += -DHOSTAPD_SUPPORT_MBSSID_WAR 11 | 12 | VERSION = "1.0.8" 13 | # Define the package version 14 | ifneq ($(VERSION),) 15 | CFLAGS += -D_VERSION_='$(VERSION)' 16 | endif 17 | 18 | ifeq ($(ROLE),dut) 19 | OBJS += indigo_api_callback_dut.o vendor_specific_dut.o 20 | CFLAGS += -D_DUT_ 21 | else 22 | OBJS += indigo_api_callback_tp.o vendor_specific_tp.o 23 | CFLAGS += -DCONFIG_CTRL_IFACE_UDP 24 | CFLAGS += -D_TEST_PLATFORM_ 25 | endif 26 | 27 | all: app 28 | 29 | %.o: %.c 30 | $(CC) $(CFLAGS) -c -o $@ $< 31 | 32 | app: $(OBJS) 33 | $(CC) $(CFLAGS) -o $@ $^ 34 | 35 | clean: 36 | rm -rf app *.o 37 | -------------------------------------------------------------------------------- /openwrt-controlappc-tp-makefile: -------------------------------------------------------------------------------- 1 | # Type is laptop or openwrt 2 | TYPE = openwrt 3 | # Role is dut or platform 4 | ROLE = tp 5 | 6 | OBJS = main.o eloop.o indigo_api.o indigo_packet.o utils.o wpa_ctrl.o 7 | CFLAGS += -g 8 | CFLAGS += -D_OPENWRT_ 9 | # CFLAGS += -D_WTS_OPENWRT_ 10 | 11 | VERSION = "1.0.8" 12 | # Define the package version 13 | ifneq ($(VERSION),) 14 | CFLAGS += -D_VERSION_='$(VERSION)' 15 | endif 16 | 17 | ifeq ($(ROLE),dut) 18 | OBJS += indigo_api_callback_dut.o vendor_specific_dut.o 19 | CFLAGS += -D_DUT_ 20 | else 21 | OBJS += indigo_api_callback_tp.o vendor_specific_tp.o 22 | CFLAGS += -DCONFIG_CTRL_IFACE_UDP 23 | CFLAGS += -D_TEST_PLATFORM_ 24 | endif 25 | 26 | all: app 27 | 28 | %.o: %.c 29 | $(CC) $(CFLAGS) -c -o $@ $< 30 | 31 | app: $(OBJS) 32 | $(CC) $(CFLAGS) -o $@ $^ 33 | 34 | clean: 35 | rm -rf app *.o 36 | -------------------------------------------------------------------------------- /package.controlappc-dut.Makefile: -------------------------------------------------------------------------------- 1 | include $(TOPDIR)/rules.mk 2 | 3 | PKG_NAME:=controlappc-dut 4 | PKG_RELEASE:=1.0.6 5 | 6 | PKG_MAINTAINER:=WFA 7 | PKG_LICENSE:=WFA 8 | 9 | PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_RELEASE) 10 | PKG_BUILD_PARALLEL:=1 11 | 12 | TARGET_LDFLAGS_C:=$(TARGET_LDFLAGS) 13 | 14 | STAMP_CONFIGURED:=$(STAMP_CONFIGURED)_$(CONFIG_WPA_MSG_MIN_PRIORITY) 15 | 16 | DRIVER_MAKEOPTS= 17 | 18 | # Full 19 | include $(INCLUDE_DIR)/package.mk 20 | 21 | define Package/controlappc-dut/default 22 | SECTION:=net 23 | CATEGORY:=Network 24 | TITLE:=ControlAppC from Wi-Fi Alliance QuickTrack Project 25 | URL:=http://wi-fi.org/ 26 | endef 27 | 28 | define Package/controlappc-dut 29 | $(call Package/controlappc-dut/default) 30 | TITLE+= (WFA) 31 | endef 32 | 33 | #define Build/Compile/hostapd-wfa 34 | define Build/Compile 35 | $(info ************ Build/Compile/controlappc-dut **********) 36 | $(call Build/RunMake, \ 37 | ) 38 | endef 39 | 40 | define Build/Prepare 41 | $(info ************ Build/Prepare **********) 42 | $(INSTALL_DIR) $(PKG_BUILD_DIR) 43 | cp -rf ./src/* $(PKG_BUILD_DIR)/ 44 | endef 45 | 46 | define Build/RunMake 47 | $(info ************ Build/RunMake $(TARGET_CC) **********) 48 | CC=$(TARGET_CC) LD=$(TARGET_LD) $(MAKE) $(PKG_JOBS) -C $(PKG_BUILD_DIR)/$(1) 49 | $(2) 50 | endef 51 | 52 | define Package/controlappc-dut/install 53 | $(info ************ Package/controlappc-dut/install $(PKG_BUILD_DIR) **********) 54 | $(INSTALL_DIR) $(1)/usr/local/bin 55 | $(INSTALL_BIN) $(PKG_BUILD_DIR)/app $(1)/usr/local/bin/controlappc-dut 56 | endef 57 | 58 | #Package/hostapd-wfa/install = $(Package/hostapd-wfa/install) 59 | $(eval $(call BuildPackage,controlappc-dut,)) 60 | -------------------------------------------------------------------------------- /package.controlappc-tp.Makefile: -------------------------------------------------------------------------------- 1 | include $(TOPDIR)/rules.mk 2 | 3 | PKG_NAME:=controlappc-tp 4 | PKG_RELEASE:=1.0.6 5 | 6 | PKG_MAINTAINER:=WFA 7 | PKG_LICENSE:=WFA 8 | 9 | PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_RELEASE) 10 | PKG_BUILD_PARALLEL:=1 11 | 12 | TARGET_LDFLAGS_C:=$(TARGET_LDFLAGS) 13 | 14 | STAMP_CONFIGURED:=$(STAMP_CONFIGURED)_$(CONFIG_WPA_MSG_MIN_PRIORITY) 15 | 16 | DRIVER_MAKEOPTS= 17 | 18 | # Full 19 | include $(INCLUDE_DIR)/package.mk 20 | 21 | define Package/controlappc-tp/default 22 | SECTION:=net 23 | CATEGORY:=Network 24 | TITLE:=ControlAppC from Wi-Fi Alliance QuickTrack Project 25 | URL:=http://wi-fi.org/ 26 | endef 27 | 28 | define Package/controlappc-tp 29 | $(call Package/controlappc-tp/default) 30 | TITLE+= (WFA) 31 | endef 32 | 33 | #define Build/Compile/hostapd-wfa 34 | define Build/Compile 35 | $(info ************ Build/Compile/controlappc-tp **********) 36 | $(call Build/RunMake, \ 37 | ) 38 | endef 39 | 40 | define Build/Prepare 41 | $(info ************ Build/Prepare **********) 42 | $(INSTALL_DIR) $(PKG_BUILD_DIR) 43 | cp -rf ./src/* $(PKG_BUILD_DIR)/ 44 | endef 45 | 46 | define Build/RunMake 47 | $(info ************ Build/RunMake $(TARGET_CC) **********) 48 | CC=$(TARGET_CC) LD=$(TARGET_LD) $(MAKE) $(PKG_JOBS) -C $(PKG_BUILD_DIR)/$(1) 49 | $(2) 50 | endef 51 | 52 | define Package/controlappc-tp/install 53 | $(info ************ Package/controlappc-tp/install $(PKG_BUILD_DIR) **********) 54 | $(INSTALL_DIR) $(1)/usr/local/bin 55 | $(INSTALL_BIN) $(PKG_BUILD_DIR)/app $(1)/usr/local/bin/controlappc-tp 56 | endef 57 | 58 | #Package/hostapd-wfa/install = $(Package/hostapd-wfa/install) 59 | $(eval $(call BuildPackage,controlappc-tp,)) 60 | -------------------------------------------------------------------------------- /patch_nwmgr.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Local variable 4 | file="/etc/NetworkManager/NetworkManager.conf" 5 | bkup_file="/etc/NetworkManager/NetworkManager.conf.bkup" 6 | debug=0 7 | i=0 8 | array=() 9 | main_section=0 10 | keyfile_section=0 11 | 12 | # Error return 13 | error_exit() { 14 | echo "$1Please manually add the unmanaged-interface:wl* to ${file} and restart NetworkManager if Network Manager is enabled." 15 | exit 0 16 | } 17 | 18 | # Backup file 19 | backup() { 20 | if [ -f "$file" ]; then 21 | cp -rf "$file" "$bkup_file" 22 | fi 23 | } 24 | 25 | # Restore file from backup 26 | restore() { 27 | if [ -f "$bkup_file" ]; then 28 | cp -rf "$bkup_file" "$file" 29 | fi 30 | } 31 | 32 | # Read lines from configuration 33 | read_config() { 34 | # Return error if NetworkManager.conf doesn't exist 35 | if [ ! -f "${file}" ]; then 36 | error_exit "The patch script cannot find ${file}. " 37 | fi 38 | # Read to array 39 | # echo "Read lines from ${file}." 40 | while IFS= read -r line; 41 | do array+=("$line"); 42 | done < "$file" 43 | # echo "Read lines completes. Total line number is ${#array[@]}." 44 | } 45 | 46 | # Save lines to configuration 47 | save_config() { 48 | printf "%s\n" "${array[@]}" >${file} 49 | } 50 | 51 | # Parse and update main section 52 | patch_main() { 53 | # Update [main] to include plugin=*,keyfile* 54 | echo "Patching main section." 55 | for (( i=0; i< ${#array[@]}; i++ )); 56 | do 57 | line="${array[$i]}" 58 | # Skip comment 59 | if [[ "$line" =~ \#.* ]]; then 60 | # echo "skip $line" 61 | continue 62 | fi 63 | # Start to check plugin after main section 64 | if [[ "$line" == "[main]" ]]; then 65 | main_section=1 66 | continue 67 | fi 68 | if [[ "$main_section" = "0" ]]; then 69 | continue 70 | fi 71 | 72 | # Find plugins 73 | if [[ "$line" =~ plugins=.*keyfile.* ]]; then 74 | echo "$line Found keyfile from plugins. Don't require to patch main section." 75 | break 76 | elif [[ "$line" =~ plugins=.* ]]; then 77 | echo "$line Found plugins but no keyfile. Append keyfile to plugin." 78 | array[$i]="$line,keyfile" 79 | break 80 | fi 81 | # Append plugins 82 | if [[ "$line" =~ \[.* ]]; then 83 | echo "End of main section. Unable to find plugins in main ${i}, append \"plugins=keyfile\"." 84 | array=( "${array[@]:0:$i}" "plugins=keyfile" "${array[@]:$i}") 85 | break 86 | fi 87 | done 88 | 89 | # Debug 90 | if [[ "${debug}" = 1 ]]; then 91 | echo "Debug main section..." 92 | for line in "${array[@]}"; do 93 | echo "(DEBUG) $line" 94 | done 95 | echo "" 96 | fi 97 | 98 | if [[ "$main_section" = 0 ]]; then 99 | error_exit "Unable to find the main section. " 100 | fi 101 | } 102 | 103 | # Parse and update keyfile section 104 | patch_keyfile() { 105 | # Update [keyfile] to include unmanaged-devices=interface-name:wl* 106 | echo "Patching keyfile section." 107 | for (( i=0; i< ${#array[@]}; i++ )); 108 | do 109 | line="${array[$i]}" 110 | # Skip comment 111 | if [[ "$line" =~ \#.* ]]; then 112 | # echo "skip $line" 113 | continue 114 | fi 115 | # Start to check unmanaged-devices after keyfile section 116 | if [[ "$line" == "[keyfile]" ]]; then 117 | keyfile_section=1 118 | continue 119 | fi 120 | if [[ "$keyfile_section" = "0" ]]; then 121 | continue 122 | fi 123 | # Find unmanaged-devices 124 | if [[ "$line" =~ unmanaged-devices=.*wl.* ]]; then 125 | echo "$line Found unmanaged-devices --> $line" 126 | break 127 | elif [[ "$line" =~ unmanaged-devices=.* ]]; then 128 | echo "$line Found unmanaged-devices but no wl*. Replace the configuration." 129 | array[$i]="unmanaged-devices=interface-name:wl*" 130 | break 131 | fi 132 | # Append unmanaged-devices to keyfile section if not existed 133 | if [[ "$line" =~ \[.* ]]; then 134 | echo "End of keyfile section. Unable to find unmanaged-devices in keyfile ${i}. Append \"unmanaged-devices=interface-name:wl*\"" 135 | array=( "${array[@]:0:$i}" "unmanaged-devices=interface-name:wl*" "${array[@]:$i}") 136 | break 137 | fi 138 | done 139 | # Append keyfile and unmanaged-devices if not existed 140 | if [[ "$keyfile_section" = "0" ]]; then 141 | echo "Unable to find keyfile section. Append the section." 142 | array+=( "" "[keyfile]" "unmanaged-devices=interface-name:wl*") 143 | fi 144 | 145 | # Debug 146 | if [[ "${debug}" = 1 ]]; then 147 | echo "Debug keyfile section..." 148 | for line in "${array[@]}"; do 149 | echo "(DEBUG) $line" 150 | done 151 | echo "" 152 | fi 153 | } 154 | 155 | if [[ "$1" = "restore" ]]; then 156 | echo "Restore ${file} from ${bkup_file}" 157 | restore 158 | systemctl restart NetworkManager 159 | else 160 | echo "Start to patch ${file}" 161 | backup 162 | read_config 163 | patch_main 164 | patch_keyfile 165 | save_config 166 | echo "The original configuration is backup to ${bkup_file}. You can restore it if any problem." 167 | echo "sudo cp -rf ${bkup_file} ${file}" 168 | echo "sudo systemctl restart NetworkManager" 169 | systemctl stop wpa_supplicant 170 | systemctl restart NetworkManager 171 | echo "Patch complete" 172 | fi 173 | exit 0 174 | -------------------------------------------------------------------------------- /sta_reset_config.conf: -------------------------------------------------------------------------------- 1 | ctrl_interface=/var/run/wpa_supplicant 2 | ap_scan=1 3 | network={ 4 | ssid="QuickTrack" 5 | key_mgmt=WPA-PSK 6 | proto=RSN 7 | pairwise=CCMP 8 | psk="12345678" 9 | } 10 | -------------------------------------------------------------------------------- /test.py: -------------------------------------------------------------------------------- 1 | import random, socket, string, sys, time 2 | 3 | class Tlv(): 4 | def __init__(self, id, val): 5 | self.id = id 6 | self.val = val 7 | def to_bytes(self): 8 | raw = bytearray() 9 | raw.append(self.id >> 8) 10 | raw.append(self.id & 0x00ff) 11 | raw.append(len(self.val)) 12 | raw += bytearray(self.val) 13 | return raw 14 | 15 | class Msg(): 16 | version = 0x01 17 | reserved = 0xff 18 | def __init__(self, id): 19 | self.id = id 20 | self.seq = random.randint(0x0000, 0xffff) 21 | self.tlvs = [] 22 | def append_tlv(self, tlv): 23 | self.tlvs.append(tlv) 24 | def to_bytes(self): 25 | raw = bytearray() 26 | raw.append(self.version) 27 | raw.append(self.id >> 8) 28 | raw.append(self.id & 0x00ff) 29 | raw.append(self.seq >> 8) 30 | raw.append(self.seq & 0x00ff) 31 | raw.append(self.reserved) 32 | raw.append(self.reserved) 33 | for t in self.tlvs: 34 | output = t.to_bytes() 35 | raw += output 36 | 37 | return raw 38 | 39 | def get_hexstring(input): 40 | hexstring = "" 41 | for b in bytearray(input): 42 | hexstring += "0x%02x " % b 43 | return hexstring.rstrip() 44 | 45 | def send_indigo_api(ip, port): 46 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 47 | server_address = (ip, port) 48 | 49 | for output in outputs: 50 | try: 51 | # Send Requset 52 | print('sending request') 53 | sent = sock.sendto(output, server_address) 54 | 55 | # Receive ACK 56 | print('waiting to receive ack') 57 | data, server = sock.recvfrom(4096) 58 | print('received "%s"' % get_hexstring(data)) 59 | 60 | # Receive Response 61 | print('waiting to receive response') 62 | data, server = sock.recvfrom(4096) 63 | print('received "%s"' % get_hexstring(data)) 64 | print('(ascii) "%s"' % (data)) 65 | time.sleep(command_interval) 66 | except Exception as e: 67 | print(e) 68 | print("An exception occurred and closing socket") 69 | sock.close() 70 | break 71 | 72 | print("closing socket") 73 | sock.close() 74 | 75 | def send_indigo_api_raw(ip, port, raw): 76 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 77 | server_address = (ip, port) 78 | 79 | try: 80 | # Send Requset 81 | print('sending request') 82 | sent = sock.sendto(raw, server_address) 83 | 84 | # Receive ACK 85 | print('waiting to receive ack') 86 | data, server = sock.recvfrom(4096) 87 | print('received "%s"' % get_hexstring(data)) 88 | 89 | # Receive Response 90 | print('waiting to receive response') 91 | data, server = sock.recvfrom(4096) 92 | print('received "%s"' % get_hexstring(data)) 93 | print('(ascii) "%s"' % (data)) 94 | time.sleep(command_interval) 95 | except Exception as e: 96 | print(e) 97 | print("An exception occurred and closing socket") 98 | sock.close() 99 | 100 | print("closing socket") 101 | sock.close() 102 | 103 | def test_get_control_app(): 104 | m = Msg(0x5002) 105 | return m 106 | 107 | def test_loopback_start(lb_port=55501): 108 | m = Msg(0x5003) 109 | m.append_tlv(Tlv(0x0054, bytes(b'%d' % lb_port))) 110 | return m 111 | 112 | def test_loopback_stop(): 113 | m = Msg(0x5004) 114 | return m 115 | 116 | def test_loopback_send_data(): 117 | m = Msg(0x5008) 118 | m.append_tlv(Tlv(0x0058, bytes(b'10.252.10.32'))) 119 | m.append_tlv(Tlv(0x0054, bytes(b'20480'))) 120 | m.append_tlv(Tlv(0x0067, bytes(b'12'))) 121 | m.append_tlv(Tlv(0x0069, bytes(b'1'))) 122 | m.append_tlv(Tlv(0x00c0, bytes(b'1200'))) 123 | return m 124 | 125 | def start_loopback_client(target_host, target_port=20480, count=10, size=1000): 126 | recv_count = 0 127 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 128 | server_address = (target_host, target_port) 129 | 130 | letters = string.ascii_lowercase 131 | 132 | for i in range(count): 133 | loopback_data = ''.join(random.choice(letters) for i in range(size)) 134 | try: 135 | # Send Requset 136 | print('[count=%d] sending loopback data len=%d %s...' % (i, len(loopback_data), loopback_data[0:50])) 137 | sent = sock.sendto(loopback_data, server_address) 138 | 139 | # Receive Response 140 | data, server = sock.recvfrom(4096) 141 | print('[count=%d] received loopback data len=%d %s...' % (i, len(data), data[0:50])) 142 | recv_count = recv_count + 1 143 | except: 144 | print("[count=%d] failed to send socket") 145 | 146 | sock.close() 147 | print("Percentage: %d%%" % int((float(recv_count)/float(count))*100) ) 148 | 149 | 150 | def test_ap_send_disassociate(): 151 | m = Msg(0x1004) 152 | m.append_tlv(Tlv(0x0028, bytes(b'b8:5d:0a:62:b3:ee'))) 153 | return m 154 | 155 | def test_sta_start_up(): 156 | m = Msg(0x2008) 157 | m.append_tlv(Tlv(0x0097, bytes(b'udp:10240'))) 158 | return m 159 | 160 | def test_sta_configure(): 161 | m = Msg(0x2001) 162 | m.append_tlv(Tlv(0x0035, bytes(b'Indigo_1600155580'))) # SSID 163 | m.append_tlv(Tlv(0x003a, bytes(b'12345678'))) # PSK 164 | m.append_tlv(Tlv(0x003b, bytes(b'RSN'))) # PROTO 165 | m.append_tlv(Tlv(0x003d, bytes(b'CCMP'))) # PAIRWISE 166 | m.append_tlv(Tlv(0x003c, bytes(b'1'))) # STA_IEEE80211_W 167 | m.append_tlv(Tlv(0x0036, bytes(b'WPA-PSK'))) # KEY_MGMT 168 | return m 169 | 170 | def test_sta_associate(): 171 | m = Msg(0x2000) 172 | return m 173 | 174 | def test_sta_disconnect(): 175 | m = Msg(0x2002) 176 | return m 177 | 178 | def test_ap_start(): 179 | m = Msg(0x1000) 180 | return m 181 | 182 | def test_ap_stop(): 183 | m = Msg(0x1001) 184 | return m 185 | 186 | def test_get_mac_addr(): 187 | m = Msg(0x5001) 188 | return m 189 | 190 | def test_ap_configure(): 191 | # Bytes to DUT : 01 10 02 01 51 ff ff 00 01 11 49 6e 64 69 67 6f 5f 31 36 30 32 38 33 39 35 39 34 192 | # 00 07 01 31 193 | # 00 02 02 31 31 194 | # 00 1e 01 67 195 | # 00 0e 20 30 31 32 33 34 35 36 37 38 39 61 62 63 64 65 66 30 31 32 33 34 35 36 37 38 39 61 62 63 64 65 66 196 | # 00 0b 01 32 197 | # 00 0c 03 53 41 45 198 | # 00 0d 04 43 43 4d 50 199 | m = Msg(0x1002) 200 | m.append_tlv(Tlv(0x0001, bytes(b'Indigo_1602839594'))) 201 | m.append_tlv(Tlv(0x0007, bytes(b'1'))) 202 | m.append_tlv(Tlv(0x0002, bytes(b'11'))) 203 | m.append_tlv(Tlv(0x001e, bytes(b'g'))) 204 | m.append_tlv(Tlv(0x000e, bytes(b'0123456789abcdef0123456789abcdef'))) 205 | m.append_tlv(Tlv(0x000b, bytes(b'2'))) 206 | m.append_tlv(Tlv(0x000c, bytes(b'SAE'))) 207 | m.append_tlv(Tlv(0x000d, bytes(b'CCMP'))) 208 | # m.append_tlv(Tlv(0x000d, [0x43, 0x43, 0x4d, 0x50] )) 209 | return m 210 | 211 | def test_assign_static_ip(): 212 | # Bytes to DUT : 01 50 06 00 cc ff ff 00 55 0b 31 39 32 2e 31 36 38 2e 31 2e 31 213 | m = Msg(0x5006) 214 | m.append_tlv(Tlv(0x0055, bytes(b'192.168.1.1'))) 215 | return m 216 | 217 | def test_device_reset(): 218 | # REQ: 01 50 07 01 4f ff ff 00 5c 01 32 00 57 01 30 219 | # RSP: 01 00 01 01 4f ff ff a0 01 01 30 a0 00 15 41 43 4b 3a 20 43 6f 6d 6d 61 6e 64 20 72 65 63 65 69 76 65 64 220 | m = Msg(0x5007) 221 | m.append_tlv(Tlv(0x005c, bytes(0x32))) 222 | m.append_tlv(Tlv(0x0057, bytes(0x30))) 223 | return m 224 | 225 | def test_hex_file(ip, port, fn): 226 | raw = bytearray() 227 | f = open(fn, "r") 228 | txt = f.read() 229 | data = txt.split(", ") 230 | for d in data: 231 | hex_int = int(d, 16) 232 | raw.append(hex_int & 0x00ff) 233 | send_indigo_api_raw(ip, port, raw) 234 | 235 | command_interval = 1 236 | outputs = [] 237 | 238 | # ContrlAppC ip and port 239 | peer_ip = '10.252.10.139' 240 | peer_port = 9004 241 | 242 | if len(sys.argv) == 1: 243 | m = test_get_control_app() 244 | outputs.append(m.to_bytes()) 245 | elif len(sys.argv) >= 2: 246 | if sys.argv[1] == "get_control_app": 247 | m = test_get_control_app() 248 | outputs.append(m.to_bytes()) 249 | elif sys.argv[1] == "loopback_start": 250 | if len(sys.argv) == 3: 251 | m = test_loopback_start(int(sys.argv[2])) 252 | else: 253 | m = test_loopback_start() 254 | outputs.append(m.to_bytes()) 255 | elif sys.argv[1] == "loopback_test": 256 | start_loopback_client(peer_ip, 20480, 10, 1000) 257 | m = test_get_control_app() 258 | outputs.append(m.to_bytes()) 259 | elif sys.argv[1] == "loopback_send_data": 260 | m = test_loopback_send_data() 261 | outputs.append(m.to_bytes()) 262 | elif sys.argv[1] == "loopback_stop": 263 | m = test_loopback_stop() 264 | outputs.append(m.to_bytes()) 265 | elif sys.argv[1] == "device_reset": 266 | m = test_device_reset() 267 | outputs.append(m.to_bytes()) 268 | elif sys.argv[1] == "ap_start": 269 | m = test_ap_start() 270 | outputs.append(m.to_bytes()) 271 | elif sys.argv[1] == "ap_stop": 272 | m = test_ap_stop() 273 | outputs.append(m.to_bytes()) 274 | elif sys.argv[1] == "ap_configure": 275 | m = test_ap_configure() 276 | outputs.append(m.to_bytes()) 277 | elif sys.argv[1] == "sta_start_up": 278 | m = test_sta_start_up() 279 | outputs.append(m.to_bytes()) 280 | elif sys.argv[1] == "sta_disconnect": 281 | m = test_sta_disconnect() 282 | outputs.append(m.to_bytes()) 283 | elif sys.argv[1] == "assign_static_ip": 284 | m = test_assign_static_ip() 285 | elif sys.argv[1] == "get_mac_addr": 286 | m = test_get_mac_addr() 287 | outputs.append(m.to_bytes()) 288 | elif sys.argv[1] == "file": 289 | test_hex_file(peer_ip, peer_port, sys.argv[2]) 290 | sys.exit() 291 | else: 292 | m = test_get_control_app() 293 | outputs.append(m.to_bytes()) 294 | 295 | send_indigo_api(peer_ip, peer_port) 296 | -------------------------------------------------------------------------------- /utils.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2020 Wi-Fi Alliance */ 2 | 3 | /* Permission to use, copy, modify, and/or distribute this software for any */ 4 | /* purpose with or without fee is hereby granted, provided that the above */ 5 | /* copyright notice and this permission notice appear in all copies. */ 6 | 7 | /* THE SOFTWARE IS PROVIDED 'AS IS' AND THE AUTHOR DISCLAIMS ALL */ 8 | /* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED */ 9 | /* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL */ 10 | /* THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR */ 11 | /* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING */ 12 | /* FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF */ 13 | /* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT */ 14 | /* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS */ 15 | /* SOFTWARE. */ 16 | 17 | #ifndef _INDIGO_UTILS_ 18 | #define _INDIGO_UTILS_ 1 19 | 20 | #include 21 | 22 | #define S_BUFFER_LEN 512 23 | #define BUFFER_LEN 1536 24 | #define L_BUFFER_LEN 8192 25 | 26 | #define TOOL_POST_PORT 8080 27 | #define HAPD_UPLOAD_API "/upload-platform-hapd-log" 28 | #define WPAS_UPLOAD_API "/upload-platform-wpas-log" 29 | #define ARTIFACTS_UPLOAD_API "/upload-test-artifacts" 30 | #ifdef _DUT_ 31 | #define APP_LOG_FILE "controlappc_DUT.log" 32 | #else 33 | #define APP_LOG_FILE "controlappc_tool_platform.log" 34 | #endif 35 | #define UPLOAD_TC_APP_LOG 1 36 | 37 | /* Log */ 38 | enum { 39 | LOG_LEVEL_DEBUG_VERBOSE = 0, 40 | LOG_LEVEL_DEBUG = 1, 41 | LOG_LEVEL_INFO = 2, 42 | LOG_LEVEL_NOTICE = 3, 43 | LOG_LEVEL_WARNING = 4, 44 | LOG_LEVEL_ERROR = 5 45 | }; 46 | 47 | enum { 48 | BAND_24GHZ = 0, 49 | BAND_5GHZ = 1, 50 | BAND_6GHZ = 2 51 | }; 52 | 53 | enum { 54 | PHYMODE_AUTO = 0, 55 | PHYMODE_11B = 1, 56 | PHYMODE_11BG = 2, 57 | PHYMODE_11BGN = 3, 58 | PHYMODE_11A = 4, 59 | PHYMODE_11NA = 5, 60 | PHYMODE_11AC = 6, 61 | PHYMODE_11AXG = 7, 62 | PHYMODE_11AXA = 8, 63 | PHYMODE_11AX = 9, 64 | PHYMODE_11BE = 10, 65 | }; 66 | 67 | enum { 68 | CHWIDTH_AUTO = 0, 69 | CHWIDTH_20 = 1, 70 | CHWIDTH_40 = 2, 71 | CHWIDTH_80 = 3, 72 | CHWIDTH_80PLUS80 = 4, 73 | CHWIDTH_160 = 5 74 | }; 75 | 76 | enum { 77 | DATA_TYPE_UDP = 0, 78 | DATA_TYPE_ICMP = 1 79 | }; 80 | 81 | enum { 82 | OP_CLASS_6G_20 = 131, 83 | OP_CLASS_6G_40 = 132, 84 | OP_CLASS_6G_80 = 133, 85 | OP_CLASS_6G_160 = 134 86 | }; 87 | 88 | enum wlan_fc_stype_mgmt { 89 | ASSOC_REQ = 0, 90 | ASSOC_RESP = 1, 91 | REASSOC_REQ = 2, 92 | REASSOC_RESP = 3, 93 | PROBE_REQ = 4, 94 | PROBE_RESP = 5, 95 | BEACON = 8, 96 | ATIM = 9, 97 | DISASSOC = 10, 98 | AUTH = 11, 99 | DEAUTH = 12, 100 | ACTION = 13 101 | }; 102 | 103 | struct sta_platform_config { 104 | int phymode; 105 | int chwidth; 106 | bool phymode_isset; 107 | bool chwidth_isset; 108 | }; 109 | 110 | struct channel_info { 111 | int channel; 112 | int freq; 113 | }; 114 | 115 | #define UNUSED_IDENTIFIER -1 116 | struct interface_info { 117 | int identifier; // valid only for multiple VAPs case 118 | int band; 119 | int bssid; 120 | char ifname[16]; 121 | char ssid[64]; 122 | int mbssid_enable; 123 | int transmitter; 124 | int hapd_bss_id; 125 | char hapd_conf_file[64]; 126 | char link_conf_file[64]; 127 | int link_id; 128 | int link_band; 129 | }; 130 | 131 | struct bss_identifier_info { 132 | int identifier; 133 | int band; 134 | int mbssid_enable; 135 | int transmitter; 136 | int mld_link; 137 | }; 138 | 139 | struct loopback_info { 140 | int sock; 141 | double rate; 142 | int pkt_sent; 143 | int pkt_rcv; 144 | int pkt_type; 145 | int pkt_size; 146 | char target_ip[64]; 147 | char message[1600]; 148 | }; 149 | 150 | /* log and file API */ 151 | void indigo_logger(int level, const char *fmt, ...); 152 | int pipe_command(char *buffer, int buffer_size, char *cmd, char *parameter[]); 153 | char* read_file(char *fn); 154 | int write_file(char *fn, char *buffer, int len); 155 | int append_file(char *fn, char *buffer, int len); 156 | void open_tc_app_log(); 157 | void close_tc_app_log(); 158 | 159 | /* network interface and loopback API */ 160 | int get_mac_address(char *buffer, int size, char *interface); 161 | int set_mac_address(char *ifname, char *mac); 162 | int find_interface_ip(char *ipaddr, int ipaddr_len, char *name); 163 | int loopback_server_start(char *local_ip, char *local_port, int timeout); 164 | int loopback_server_stop(); 165 | int loopback_server_status(); 166 | int send_udp_data(char *target_ip, int target_port, int packet_count, int packet_size, double rate); 167 | int stop_loopback_data(int *pkt_sent); 168 | int send_broadcast_arp(char *target_ip, int *send_count, int rate); 169 | int send_icmp_data(char *target_ip, int packet_count, int packet_size, double rate); 170 | char* get_wlans_bridge(); 171 | int set_wlans_bridge(char* br); 172 | int is_bridge_created(); 173 | int create_bridge(char *br); 174 | int add_interface_to_bridge(char *br, char *interface); 175 | int reset_bridge(char *br); 176 | int control_interface(char *ifname, char *op); 177 | int set_interface_ip(char *ifname, char *ip); 178 | int reset_interface_ip(char *ifname); 179 | int add_wireless_interface(char *ifname); 180 | int delete_wireless_interface(char *ifname); 181 | void bridge_init(char *br); 182 | void detect_del_arp_entry(char *ip); 183 | int add_arp_entry(char *ip, char *mac, char *ifname); 184 | 185 | #define DEBUG_LEVEL_DISABLE 0 186 | #define DEBUG_LEVEL_BASIC 1 187 | #define DEBUG_LEVEL_ADVANCED 2 188 | int get_debug_level(int value); 189 | 190 | /* hostapd API */ 191 | char* get_hapd_exec_file(); 192 | int set_hapd_exec_file(char* path); 193 | char* get_hapd_full_exec_path(); 194 | int set_hapd_full_exec_path(char* path); 195 | char* get_hapd_ctrl_path_by_id(struct interface_info* wlan); 196 | char* get_hapd_ctrl_path(); 197 | int set_hapd_ctrl_path(char* path); 198 | char* get_hapd_global_ctrl_path(); 199 | int set_hapd_global_ctrl_path(char* path); 200 | char* get_hapd_conf_file(); 201 | int set_hapd_conf_file(char* path); 202 | void set_hostapd_debug_level(int level); 203 | char* get_hostapd_debug_arguments(); 204 | 205 | /* wpa_supplicant API */ 206 | char* get_wpas_exec_file(); 207 | int set_wpas_exec_file(char* path); 208 | char* get_wpas_full_exec_path(); 209 | int set_wpas_full_exec_path(char* path); 210 | char* get_wpas_ctrl_path(); 211 | char* get_wpas_if_ctrl_path(char* if_name); 212 | int set_wpas_ctrl_path(char* path); 213 | char* get_wpas_global_ctrl_path(); 214 | int set_wpas_global_ctrl_path(char* path); 215 | char* get_wpas_conf_file(); 216 | int set_wpas_conf_file(char* path); 217 | void set_wpas_debug_level(int level); 218 | char* get_wpas_debug_arguments(); 219 | 220 | /* service and environment API */ 221 | char* get_wireless_interface(); 222 | int set_wireless_interface(char *name); 223 | int get_service_port(); 224 | int set_service_port(int port); 225 | char* get_default_wireless_interface_info(); 226 | int clear_interfaces_resource(); 227 | char* get_all_hapd_conf_files(int *swap_hostapd); 228 | 229 | void parse_bss_identifier(int bss_identifier, struct bss_identifier_info* bss); 230 | struct interface_info* assign_wireless_interface_info(struct bss_identifier_info *bss); 231 | struct interface_info* get_wireless_interface_info(int band, int identifier); 232 | struct interface_info* get_first_configured_wireless_interface_info(); 233 | int add_all_wireless_interface_to_bridge(char *br); 234 | void set_default_wireless_interface_info(int channel); 235 | int show_wireless_interface_info(); 236 | void iterate_all_wlan_interfaces(void (*callback_fn)(void *)); 237 | void get_server_cert_hash(char *pem_file, char *buffer); 238 | int insert_wpa_network_config(char *config); 239 | void remove_pac_file(char *path); 240 | int is_band_enabled(int band); 241 | 242 | /* misc */ 243 | size_t strlcpy(char *dest, const char *src, size_t siz); 244 | int get_key_value(char *value, char *buffer, char *token); 245 | int verify_band_from_freq(int freq, int band); 246 | int get_center_freq_index(int channel, int width); 247 | int get_6g_center_freq_index(int channel, int width); 248 | int is_ht40plus_chan(int chan); 249 | int is_ht40minus_chan(int chan); 250 | int http_file_post(char *host, int port, char *path, char *file_name); 251 | int file_exists(const char *fname); 252 | #endif 253 | -------------------------------------------------------------------------------- /vendor_specific.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2020 Wi-Fi Alliance */ 2 | 3 | /* Permission to use, copy, modify, and/or distribute this software for any */ 4 | /* purpose with or without fee is hereby granted, provided that the above */ 5 | /* copyright notice and this permission notice appear in all copies. */ 6 | 7 | /* THE SOFTWARE IS PROVIDED 'AS IS' AND THE AUTHOR DISCLAIMS ALL */ 8 | /* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED */ 9 | /* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL */ 10 | /* THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR */ 11 | /* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING */ 12 | /* FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF */ 13 | /* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT */ 14 | /* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS */ 15 | /* SOFTWARE. */ 16 | 17 | #ifndef _VENDOR_SPECIFIC_ 18 | #define _VENDOR_SPECIFIC_ 1 19 | 20 | /* hostapd definitions */ 21 | #ifdef _DUT_ 22 | #ifdef _OPENWRT_ /* DUT & OpenWRT */ 23 | #define HAPD_EXEC_FILE_DEFAULT "/usr/sbin/hostapd" 24 | #else /* DUT & Laptop */ 25 | #define HAPD_EXEC_FILE_DEFAULT "/usr/local/bin/WFA-Hostapd-Supplicant/hostapd" 26 | #endif /* _OPENWRT_ */ 27 | 28 | #else /* Platform */ 29 | #ifdef _OPENWRT_ /* Platform & OpenWRT */ 30 | /* Only OpenWRT + Test Platform, the hostapd path is /usr/sbin/hostapd_udp. */ 31 | #define HAPD_EXEC_FILE_DEFAULT "/usr/sbin/hostapd_udp" 32 | #else /* Platform & Laptop */ 33 | #define HAPD_EXEC_FILE_DEFAULT "/usr/local/bin/WFA-Hostapd-Supplicant/hostapd_udp" 34 | #endif /* _OPENWRT_ */ 35 | #endif /* _DUT_ */ 36 | #define HAPD_CTRL_PATH_DEFAULT "/var/run/hostapd" 37 | #define HAPD_GLOBAL_CTRL_PATH_DEFAULT "/var/run/hostapd-global" 38 | #define HAPD_LOG_FILE "/var/log/hostapd.log" 39 | 40 | #ifdef _OPENWRT_ 41 | #define HAPD_CONF_FILE_DEFAULT "/tmp/hostapd.conf" 42 | #define HAPD_CONF_FILE_DEFAULT_PATH "/tmp" 43 | #define WPAS_CONF_FILE_DEFAULT "/tmp/wpa_supplicant.conf" 44 | // 2(2.4G): first interface ath1, second interface ath11 45 | // 5(5G): first interface ath0, second interface ath01 46 | #define DEFAULT_APP_INTERFACES_PARAMS "2:ath1,2:ath11,2:ath12,2:ath13,5:ath0,5:ath01,5:ath02,5:ath03" 47 | #define DEFAULT_APP_6E_INTERFACES_PARAMS "6:ath0,6:ath01,6:ath02,6:ath03,5:ath1,5:ath11,5:ath12,5:ath13,2:ath2,2:ath21,2:ath22,2:ath23" 48 | #define WIFI7_PHY_INTERFACE "phy00" 49 | 50 | #else 51 | #define HAPD_CONF_FILE_DEFAULT "/etc/hostapd/hostapd.conf" 52 | #define HAPD_CONF_FILE_DEFAULT_PATH "/etc/hostapd" 53 | #define WPAS_CONF_FILE_DEFAULT "/etc/wpa_supplicant/wpa_supplicant.conf" 54 | // d(2.4G or 5G):Single band can work on 2G or 5G: first interface wlan0, second interface wlan1 55 | #define DEFAULT_APP_INTERFACES_PARAMS "2:wlan0,2:wlan1,5:wlan0,5:wlan1" 56 | 57 | #endif /* _OPENWRT_ */ 58 | 59 | /* wpa_supplicant definitions */ 60 | #ifdef _DUT_ 61 | #define WPAS_EXEC_FILE_DEFAULT "/usr/local/bin/WFA-Hostapd-Supplicant/wpa_supplicant" 62 | #else /* Platform */ 63 | #define WPAS_EXEC_FILE_DEFAULT "/usr/local/bin/WFA-Hostapd-Supplicant/wpa_supplicant_udp" 64 | #define WLANTEST_EXEC_FILE_DEFAULT "/usr/local/bin/WFA-Hostapd-Supplicant/wlantest" 65 | #define WLANTEST_CLI_EXEC_FILE_DEFAULT "/usr/local/bin/WFA-Hostapd-Supplicant/wlantest_cli" 66 | #define WLANTEST_LOG_FILE "/tmp/wlantest.log" 67 | #endif /* _DUT_ */ 68 | #define WPAS_CTRL_PATH_DEFAULT "/var/run/wpa_supplicant" 69 | #define WPAS_GLOBAL_CTRL_PATH_DEFAULT "/var/run/wpa_supplicant/global" // not use wpas global before 70 | #define WPAS_LOG_FILE "/var/log/supplicant.log" 71 | 72 | #define HS20_OSU_CLIENT "/usr/local/bin/WFA-Hostapd-Supplicant/hs20-osu-client" 73 | 74 | #define WIRELESS_INTERFACE_DEFAULT "wlan0" 75 | #define MONITOR_INTERFACE_DEFAULT "mon0" 76 | #define SERVICE_PORT_DEFAULT 9004 77 | 78 | /* Default bridge for wireless interfaces */ 79 | #define BRIDGE_WLANS "br-wlans" 80 | 81 | #ifdef _WTS_OPENWRT_ 82 | #define HOSTAPD_SUPPORT_MBSSID 0 83 | #else 84 | /* hostapd support MBSSID with single hostapd conf 85 | * hostapd support "multiple_bssid" configuration 86 | */ 87 | #define HOSTAPD_SUPPORT_MBSSID 1 88 | 89 | #endif 90 | 91 | /* Default Tool STA maximum number of cached scan results*/ 92 | #define MAX_SCAN_ENTRY 1024 93 | 94 | /* Default DUT GO intent value */ 95 | #define P2P_GO_INTENT 7 96 | 97 | #define DHCP_SERVER_IP "192.168.65.1" 98 | void vendor_init(); 99 | void vendor_deinit(); 100 | void vendor_device_reset(); 101 | 102 | #define SAE_PK_FILE_PATH "/vendor/wfa/" 103 | 104 | /** 105 | * wps settings retrieved with vendor-specific operations. 106 | */ 107 | 108 | #define WPS_OOB_SSID "ssid" 109 | #define WPS_OOB_AUTH_TYPE "wpa_key_mgmt" 110 | #define WPS_OOB_ENC_TYPE "wpa_pairwise" 111 | #define WPS_OOB_PSK "wpa_passphrase" 112 | #define WPS_OOB_WPA_VER "wpa" 113 | #define WPS_OOB_AP_PIN "ap_pin" 114 | #define WPS_OOB_STATE "wps_state" 115 | #define WPS_CONFIG "config_methods" 116 | #define WPS_DEV_NAME "device_name" 117 | #define WPS_DEV_TYPE "device_type" 118 | #define WPS_MANUFACTURER "manufacturer" 119 | #define WPS_MODEL_NAME "model_name" 120 | #define WPS_MODEL_NUMBER "model_number" 121 | #define WPS_SERIAL_NUMBER "serial_number" 122 | 123 | #define WPS_OOB_NOT_CONFIGURED "1" 124 | #define WPS_OOB_CONFIGURED "2" 125 | 126 | #define SUPPORTED_CONF_METHOD_AP "label keypad push_button virtual_push_button display virtual_display" 127 | #define SUPPORTED_CONF_METHOD_STA "keypad push_button virtual_push_button display virtual_display" 128 | 129 | #define WPS_OOB_ONLY "1" 130 | #define WPS_COMMON "2" 131 | 132 | enum wps_device_role { 133 | WPS_AP, 134 | WPS_STA 135 | }; 136 | 137 | #define GROUP_NUM (3) 138 | #define AP_SETTING_NUM (14) 139 | #define STA_SETTING_NUM (6) 140 | 141 | typedef struct _wps_setting { 142 | /* key-value for each setting pair */ 143 | char wkey[64]; 144 | char value[512]; 145 | char attr[64]; 146 | } wps_setting; 147 | 148 | #ifdef _TEST_PLATFORM_ 149 | 150 | /** 151 | * struct sta_driver_ops - Driver interface API wrapper definition 152 | * 153 | * This structure defines the API that each driver interface needs to implement 154 | * for indigo c control application. 155 | */ 156 | struct sta_driver_ops { 157 | const char *name; 158 | int (*set_channel_width)(void); 159 | void (*set_phy_mode)(void); 160 | }; 161 | 162 | extern const struct sta_driver_ops sta_driver_platform1_ops; 163 | extern const struct sta_driver_ops sta_driver_platform2_ops; 164 | extern const struct sta_driver_ops sta_driver_platform3_ops; 165 | 166 | /* Generic platform dependent APIs */ 167 | int set_channel_width(); 168 | void set_phy_mode(); 169 | #endif 170 | 171 | #ifdef _OPENWRT_ 172 | void openwrt_apply_radio_config(void); 173 | int detect_number_radio(void); 174 | #endif 175 | 176 | void create_sta_interface(); 177 | void delete_sta_interface(); 178 | 179 | void configure_ap_enable_mbssid(); 180 | void configure_ap_radio_params(char *band, char *country, int channel, int chwidth); 181 | void start_ap_set_wlan_params(void *if_info); 182 | 183 | int get_p2p_mac_addr(char *mac_addr, size_t size); 184 | int get_p2p_group_if(char *if_name, size_t size); 185 | int get_p2p_dev_if(char *if_name, size_t size); 186 | 187 | void get_monitor_if(char *if_name, size_t size); 188 | 189 | void start_dhcp_server(char *if_name, char *ip_addr); 190 | void stop_dhcp_server(); 191 | void start_dhcp_client(char *if_name); 192 | void stop_dhcp_client(); 193 | wps_setting* get_vendor_wps_settings(enum wps_device_role); 194 | 195 | void get_mld_link_mac(char *mac_addr, size_t size, char *band); 196 | #endif 197 | -------------------------------------------------------------------------------- /vendor_specific_dut.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2020 Wi-Fi Alliance */ 2 | 3 | /* Permission to use, copy, modify, and/or distribute this software for any */ 4 | /* purpose with or without fee is hereby granted, provided that the above */ 5 | /* copyright notice and this permission notice appear in all copies. */ 6 | 7 | /* THE SOFTWARE IS PROVIDED 'AS IS' AND THE AUTHOR DISCLAIMS ALL */ 8 | /* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED */ 9 | /* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL */ 10 | /* THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR */ 11 | /* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING */ 12 | /* FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF */ 13 | /* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT */ 14 | /* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS */ 15 | /* SOFTWARE. */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include "vendor_specific.h" 24 | #include "utils.h" 25 | 26 | #ifdef HOSTAPD_SUPPORT_MBSSID_WAR 27 | extern int use_openwrt_wpad; 28 | #endif 29 | 30 | #if defined(_OPENWRT_) 31 | int detect_number_radio() { 32 | FILE *fp; 33 | char buffer[BUFFER_LEN]; 34 | int number_radio = 0; 35 | 36 | fp = popen("iw dev", "r"); 37 | if (fp) { 38 | while (fgets(buffer, sizeof(buffer), fp) != NULL) { 39 | if (strstr(buffer, "phy#0") || strstr(buffer, "phy#1") || strstr(buffer, "phy#2")) 40 | number_radio += 1; 41 | } 42 | pclose(fp); 43 | } 44 | 45 | return number_radio; 46 | } 47 | #endif 48 | 49 | void interfaces_init() { 50 | #if defined(_OPENWRT_) && !defined(_WTS_OPENWRT_) 51 | char buffer[BUFFER_LEN]; 52 | char mac_addr[S_BUFFER_LEN]; 53 | int number_radio = 0; 54 | char phy_name[16]; 55 | 56 | number_radio = detect_number_radio(); 57 | 58 | memset(buffer, 0, sizeof(buffer)); 59 | if (number_radio == 1) 60 | sprintf(phy_name, WIFI7_PHY_INTERFACE); 61 | else 62 | sprintf(phy_name, "phy1"); 63 | sprintf(buffer, "iw phy %s interface add ath1 type managed >/dev/null 2>/dev/null", phy_name); 64 | system(buffer); 65 | sprintf(buffer, "iw phy %s interface add ath11 type managed >/dev/null 2>/dev/null", phy_name); 66 | system(buffer); 67 | if (number_radio != 1) 68 | sprintf(phy_name, "phy0"); 69 | sprintf(buffer, "iw phy %s interface add ath0 type managed >/dev/null 2>/dev/null", phy_name); 70 | system(buffer); 71 | sprintf(buffer, "iw phy %s interface add ath01 type managed >/dev/null 2>/dev/null", phy_name); 72 | system(buffer); 73 | if (number_radio == 1 || number_radio == 3) { 74 | if (number_radio != 1) 75 | sprintf(phy_name, "phy2"); 76 | sprintf(buffer, "iw phy %s interface add ath2 type managed >/dev/null 2>/dev/null", phy_name); 77 | system(buffer); 78 | sprintf(buffer, "iw phy %s interface add ath21 type managed >/dev/null 2>/dev/null", phy_name); 79 | system(buffer); 80 | } 81 | 82 | memset(mac_addr, 0, sizeof(mac_addr)); 83 | get_mac_address(mac_addr, sizeof(mac_addr), "ath1"); 84 | control_interface("ath1", "down"); 85 | mac_addr[16] = (char)'0'; 86 | set_mac_address("ath1", mac_addr); 87 | 88 | control_interface("ath11", "down"); 89 | mac_addr[16] = (char)'1'; 90 | set_mac_address("ath11", mac_addr); 91 | 92 | memset(mac_addr, 0, sizeof(mac_addr)); 93 | get_mac_address(mac_addr, sizeof(mac_addr), "ath0"); 94 | control_interface("ath0", "down"); 95 | if (number_radio == 1) 96 | mac_addr[16] = (char)'4'; 97 | else 98 | mac_addr[16] = (char)'0'; 99 | set_mac_address("ath0", mac_addr); 100 | 101 | control_interface("ath01", "down"); 102 | if (number_radio == 1) 103 | mac_addr[16] = (char)'5'; 104 | else 105 | mac_addr[16] = (char)'1'; 106 | set_mac_address("ath01", mac_addr); 107 | 108 | if (number_radio == 1 || number_radio == 3) { 109 | memset(mac_addr, 0, sizeof(mac_addr)); 110 | get_mac_address(mac_addr, sizeof(mac_addr), "ath2"); 111 | control_interface("ath2", "down"); 112 | mac_addr[16] = (char)'8'; 113 | set_mac_address("ath2", mac_addr); 114 | 115 | control_interface("ath21", "down"); 116 | mac_addr[16] = (char)'9'; 117 | set_mac_address("ath21", mac_addr); 118 | } 119 | sleep(1); 120 | #endif 121 | } 122 | /* Be invoked when start controlApp */ 123 | void vendor_init() { 124 | #if defined(_OPENWRT_) && !defined(_WTS_OPENWRT_) 125 | char buffer[BUFFER_LEN]; 126 | char mac_addr[S_BUFFER_LEN]; 127 | 128 | /* Vendor: add codes to let ControlApp have full control of hostapd */ 129 | /* Avoid hostapd being invoked by procd */ 130 | memset(buffer, 0, sizeof(buffer)); 131 | sprintf(buffer, "/etc/init.d/wpad stop >/dev/null 2>/dev/null"); 132 | system(buffer); 133 | 134 | interfaces_init(); 135 | #if HOSTAPD_SUPPORT_MBSSID 136 | #ifdef HOSTAPD_SUPPORT_MBSSID_WAR 137 | system("cp /overlay/hostapd /usr/sbin/hostapd"); 138 | use_openwrt_wpad = 0; 139 | #endif 140 | #endif 141 | #endif 142 | } 143 | 144 | /* Be invoked when terminate controlApp */ 145 | void vendor_deinit() { 146 | char buffer[S_BUFFER_LEN]; 147 | memset(buffer, 0, sizeof(buffer)); 148 | sprintf(buffer, "killall %s 1>/dev/null 2>/dev/null", get_hapd_exec_file()); 149 | system(buffer); 150 | sprintf(buffer, "killall %s 1>/dev/null 2>/dev/null", get_wpas_exec_file()); 151 | system(buffer); 152 | } 153 | 154 | /* Called by reset_device_hander() */ 155 | void vendor_device_reset() { 156 | #ifdef _WTS_OPENWRT_ 157 | char buffer[S_BUFFER_LEN]; 158 | 159 | /* Reset the country code */ 160 | snprintf(buffer, sizeof(buffer), "uci -q delete wireless.wifi0.country"); 161 | system(buffer); 162 | 163 | snprintf(buffer, sizeof(buffer), "uci -q delete wireless.wifi1.country"); 164 | system(buffer); 165 | #endif 166 | #if HOSTAPD_SUPPORT_MBSSID 167 | /* interfaces may be destroyed by hostapd after done the MBSSID testing */ 168 | interfaces_init(); 169 | #ifdef HOSTAPD_SUPPORT_MBSSID_WAR 170 | if (use_openwrt_wpad > 0) { 171 | system("cp /overlay/hostapd /usr/sbin/hostapd"); 172 | use_openwrt_wpad = 0; 173 | } 174 | #endif 175 | #endif 176 | } 177 | 178 | #ifdef _OPENWRT_ 179 | void openwrt_apply_radio_config(void) { 180 | char buffer[S_BUFFER_LEN]; 181 | 182 | #ifdef _WTS_OPENWRT_ 183 | // Apply radio configurations 184 | memset(buffer, 0, sizeof(buffer)); 185 | sprintf(buffer, "%s -g /var/run/hostapd/global -B -P /var/run/hostapd-global.pid", 186 | get_hapd_full_exec_path()); 187 | system(buffer); 188 | sleep(1); 189 | system("wifi down >/dev/null 2>/dev/null"); 190 | sleep(2); 191 | system("wifi up >/dev/null 2>/dev/null"); 192 | sleep(3); 193 | 194 | memset(buffer, 0, sizeof(buffer)); 195 | sprintf(buffer, "killall %s 1>/dev/null 2>/dev/null", get_hapd_exec_file()); 196 | system(buffer); 197 | sleep(2); 198 | #endif 199 | } 200 | #endif 201 | 202 | /* Called by configure_ap_handler() */ 203 | void configure_ap_enable_mbssid() { 204 | #ifdef _WTS_OPENWRT_ 205 | /* 206 | * the following uci commands need to reboot openwrt 207 | * so it can not be configured by controlApp 208 | * 209 | * Manually enable MBSSID on OpenWRT when need to test MBSSID 210 | * 211 | system("uci set wireless.qcawifi=qcawifi"); 212 | system("uci set wireless.qcawifi.mbss_ie_enable=1"); 213 | system("uci commit"); 214 | */ 215 | #elif defined(_OPENWRT_) 216 | #ifdef HOSTAPD_SUPPORT_MBSSID_WAR 217 | system("cp /rom/usr/sbin/wpad /usr/sbin/hostapd"); 218 | use_openwrt_wpad = 1; 219 | #endif 220 | #endif 221 | } 222 | 223 | void configure_ap_radio_params(char *band, char *country, int channel, int chwidth) { 224 | #ifdef _WTS_OPENWRT 225 | char buffer[S_BUFFER_LEN], wifi_name[16]; 226 | 227 | if (!strncmp(band, "a", 1)) { 228 | snprintf(wifi_name, sizeof(wifi_name), "wifi0"); 229 | } else { 230 | snprintf(wifi_name, sizeof(wifi_name), "wifi1"); 231 | } 232 | 233 | if (strlen(country) > 0) { 234 | snprintf(buffer, sizeof(buffer), "uci set wireless.%s.country=\'%s\'", wifi_name, country); 235 | system(buffer); 236 | } 237 | 238 | snprintf(buffer, sizeof(buffer), "uci set wireless.%s.channel=\'%d\'", wifi_name, channel); 239 | system(buffer); 240 | 241 | if (!strncmp(band, "a", 1)) { 242 | if (channel == 165) { // Force 20M for CH 165 243 | snprintf(buffer, sizeof(buffer), "uci set wireless.wifi0.htmode=\'HT20\'"); 244 | } else if (chwidth == 2) { // 160M test cases only 245 | snprintf(buffer, sizeof(buffer), "uci set wireless.wifi0.htmode=\'HT160\'"); 246 | } else if (chwidth == 0) { // 11N only 247 | snprintf(buffer, sizeof(buffer), "uci set wireless.wifi0.htmode=\'HT40\'"); 248 | } else { // 11AC or 11AX 249 | snprintf(buffer, sizeof(buffer), "uci set wireless.wifi0.htmode=\'HT80\'"); 250 | } 251 | system(buffer); 252 | } 253 | 254 | system("uci commit"); 255 | #endif 256 | } 257 | 258 | /* void (*callback_fn)(void *), callback of active wlans iterator 259 | * 260 | * Called by start_ap_handler() after invoking hostapd 261 | */ 262 | void start_ap_set_wlan_params(void *if_info) { 263 | char buffer[S_BUFFER_LEN]; 264 | struct interface_info *wlan = (struct interface_info *) if_info; 265 | 266 | memset(buffer, 0, sizeof(buffer)); 267 | #ifdef _WTS_OPENWRT_ 268 | /* Workaround: openwrt has IOT issue with intel AX210 AX mode */ 269 | sprintf(buffer, "cfg80211tool %s he_ul_ofdma 0", wlan->ifname); 270 | system(buffer); 271 | /* Avoid target assert during channel switch */ 272 | sprintf(buffer, "cfg80211tool %s he_ul_mimo 0", wlan->ifname); 273 | system(buffer); 274 | sprintf(buffer, "cfg80211tool %s twt_responder 0", wlan->ifname); 275 | system(buffer); 276 | #endif 277 | printf("set_wlan_params: %s\n", buffer); 278 | } 279 | 280 | /* Return addr of P2P-device if there is no GO or client interface */ 281 | int get_p2p_mac_addr(char *mac_addr, size_t size) { 282 | FILE *fp; 283 | char buffer[S_BUFFER_LEN], *ptr, addr[32]; 284 | int error = 1, match = 0; 285 | 286 | fp = popen("iw dev", "r"); 287 | if (fp) { 288 | while (fgets(buffer, sizeof(buffer), fp) != NULL) { 289 | ptr = strstr(buffer, "addr"); 290 | if (ptr != NULL) { 291 | sscanf(ptr, "%*s %s", addr); 292 | while (fgets(buffer, sizeof(buffer), fp) != NULL) { 293 | ptr = strstr(buffer, "type"); 294 | if (ptr != NULL) { 295 | ptr += 5; 296 | if (!strncmp(ptr, "P2P-GO", 6) || !strncmp(ptr, "P2P-client", 10)) { 297 | snprintf(mac_addr, size, "%s", addr); 298 | error = 0; 299 | match = 1; 300 | } else if (!strncmp(ptr, "P2P-device", 10)) { 301 | snprintf(mac_addr, size, "%s", addr); 302 | error = 0; 303 | } 304 | break; 305 | } 306 | } 307 | if (match) 308 | break; 309 | } 310 | } 311 | pclose(fp); 312 | } 313 | 314 | return error; 315 | } 316 | 317 | /* Get the name of P2P Group(GO or Client) interface */ 318 | int get_p2p_group_if(char *if_name, size_t size) { 319 | FILE *fp; 320 | char buffer[S_BUFFER_LEN], *ptr, name[32]; 321 | int error = 1; 322 | 323 | fp = popen("iw dev", "r"); 324 | if (fp) { 325 | while (fgets(buffer, sizeof(buffer), fp) != NULL) { 326 | ptr = strstr(buffer, "Interface"); 327 | if (ptr != NULL) { 328 | sscanf(ptr, "%*s %s", name); 329 | while (fgets(buffer, sizeof(buffer), fp) != NULL) { 330 | ptr = strstr(buffer, "type"); 331 | if (ptr != NULL) { 332 | ptr += 5; 333 | if (!strncmp(ptr, "P2P-GO", 6) || !strncmp(ptr, "P2P-client", 10)) { 334 | snprintf(if_name, size, "%s", name); 335 | error = 0; 336 | } 337 | break; 338 | } 339 | } 340 | if (!error) 341 | break; 342 | } 343 | } 344 | pclose(fp); 345 | } 346 | 347 | return error; 348 | } 349 | 350 | /* "iw dev" doesn't show the name of P2P device. The naming rule is based on wpa_supplicant */ 351 | int get_p2p_dev_if(char *if_name, size_t size) { 352 | snprintf(if_name, size, "p2p-dev-%s", get_wireless_interface()); 353 | 354 | return 0; 355 | } 356 | 357 | /* Append IP range config and start dhcpd */ 358 | void start_dhcp_server(char *if_name, char *ip_addr) 359 | { 360 | char buffer[S_BUFFER_LEN]; 361 | char ip_sub[32], *ptr; 362 | FILE *fp; 363 | 364 | /* Avoid using system dhcp server service 365 | snprintf(buffer, sizeof(buffer), "sed -i -e 's/INTERFACESv4=\".*\"/INTERFACESv4=\"%s\"/g' /etc/default/isc-dhcp-server", if_name); 366 | system(buffer); 367 | snprintf(buffer, sizeof(buffer), "systemctl restart isc-dhcp-server.service"); 368 | system(buffer); 369 | */ 370 | /* Sample command from isc-dhcp-server: dhcpd -user dhcpd -group dhcpd -f -4 -pf /run/dhcp-server/dhcpd.pid -cf /etc/dhcp/dhcpd.conf p2p-wlp2s0-0 */ 371 | 372 | /* Avoid apparmor check because we manually start dhcpd */ 373 | memset(ip_sub, 0, sizeof(ip_sub)); 374 | ptr = strrchr(ip_addr, '.'); 375 | memcpy(ip_sub, ip_addr, ptr - ip_addr); 376 | system("cp QT_dhcpd.conf /etc/dhcp/QT_dhcpd.conf"); 377 | fp = fopen("/etc/dhcp/QT_dhcpd.conf", "a"); 378 | if (fp) { 379 | snprintf(buffer, sizeof(buffer), "\nsubnet %s.0 netmask 255.255.255.0 {\n", ip_sub); 380 | fputs(buffer, fp); 381 | snprintf(buffer, sizeof(buffer), " range %s.50 %s.200;\n", ip_sub, ip_sub); 382 | fputs(buffer, fp); 383 | fputs("}\n", fp); 384 | fclose(fp); 385 | } 386 | system("touch /var/lib/dhcp/dhcpd.leases_QT"); 387 | snprintf(buffer, sizeof(buffer), "dhcpd -4 -cf /etc/dhcp/QT_dhcpd.conf -lf /var/lib/dhcp/dhcpd.leases_QT %s", if_name); 388 | system(buffer); 389 | } 390 | 391 | void stop_dhcp_server() 392 | { 393 | /* system("systemctl stop isc-dhcp-server.service"); */ 394 | system("killall dhcpd 1>/dev/null 2>/dev/null"); 395 | } 396 | 397 | void start_dhcp_client(char *if_name) 398 | { 399 | char buffer[S_BUFFER_LEN]; 400 | 401 | snprintf(buffer, sizeof(buffer), "dhclient -4 %s &", if_name); 402 | system(buffer); 403 | } 404 | 405 | void stop_dhcp_client() 406 | { 407 | system("killall dhclient 1>/dev/null 2>/dev/null"); 408 | } 409 | 410 | wps_setting *p_wps_setting = NULL; 411 | wps_setting customized_wps_settings_ap[AP_SETTING_NUM]; 412 | wps_setting customized_wps_settings_sta[STA_SETTING_NUM]; 413 | 414 | void save_wsc_setting(wps_setting *s, char *entry, int len) 415 | { 416 | char *p = NULL; 417 | 418 | p = strchr(entry, '\n'); 419 | if (p) 420 | p++; 421 | else 422 | p = entry; 423 | 424 | sscanf(p, "%[^:]:%[^:]:%s", s->wkey, s->value, s->attr); 425 | } 426 | 427 | wps_setting* __get_wps_setting(int len, char *buffer, enum wps_device_role role) 428 | { 429 | char *token = strtok(buffer , ","); 430 | wps_setting *s = NULL; 431 | int i = 0; 432 | 433 | if (role == WPS_AP) { 434 | memset(customized_wps_settings_ap, 0, sizeof(customized_wps_settings_ap)); 435 | p_wps_setting = customized_wps_settings_ap; 436 | while (token != NULL) { 437 | s = &p_wps_setting[i++]; 438 | save_wsc_setting(s, token, strlen(token)); 439 | token = strtok(NULL, ","); 440 | } 441 | } else { 442 | memset(customized_wps_settings_sta, 0, sizeof(customized_wps_settings_sta)); 443 | p_wps_setting = customized_wps_settings_sta; 444 | while (token != NULL) { 445 | s = &p_wps_setting[i++]; 446 | save_wsc_setting(s, token, strlen(token)); 447 | token = strtok(NULL, ","); 448 | } 449 | } 450 | return p_wps_setting; 451 | } 452 | 453 | wps_setting* get_vendor_wps_settings(enum wps_device_role role) 454 | { 455 | /* 456 | * Please implement the vendor proprietary function to get WPS OOB and required settings. 457 | * */ 458 | #define WSC_SETTINGS_FILE_AP "/tmp/wsc_settings_APUT" 459 | #define WSC_SETTINGS_FILE_STA "/tmp/wsc_settings_STAUT" 460 | int len = 0, is_valid = 0; 461 | char pipebuf[S_BUFFER_LEN]; 462 | char *parameter_ap[] = {"cat", WSC_SETTINGS_FILE_AP, NULL, NULL}; 463 | char *parameter_sta[] = {"cat", WSC_SETTINGS_FILE_STA, NULL, NULL}; 464 | 465 | memset(pipebuf, 0, sizeof(pipebuf)); 466 | if (role == WPS_AP) { 467 | if (0 == access(WSC_SETTINGS_FILE_AP, F_OK)) { 468 | // use customized ap wsc settings 469 | #ifdef _OPENWRT_ 470 | len = pipe_command(pipebuf, sizeof(pipebuf), "/bin/cat", parameter_ap); 471 | #else 472 | len = pipe_command(pipebuf, sizeof(pipebuf), "/usr/bin/cat", parameter_ap); 473 | #endif 474 | if (len) { 475 | indigo_logger(LOG_LEVEL_INFO, "wsc settings APUT:\n %s", pipebuf); 476 | return __get_wps_setting(len, pipebuf, WPS_AP); 477 | } else { 478 | indigo_logger(LOG_LEVEL_INFO, "wsc settings APUT: no data"); 479 | } 480 | } else { 481 | indigo_logger(LOG_LEVEL_ERROR, "APUT: WPS Erorr. Failed to get settings."); 482 | return NULL; 483 | } 484 | } else { 485 | if (0 == access(WSC_SETTINGS_FILE_STA, F_OK)) { 486 | // use customized sta wsc settings 487 | len = pipe_command(pipebuf, sizeof(pipebuf), "/usr/bin/cat", parameter_sta); 488 | if (len) { 489 | indigo_logger(LOG_LEVEL_INFO, "wsc settings STAUT:\n %s", pipebuf); 490 | return __get_wps_setting(len, pipebuf, WPS_STA); 491 | } else { 492 | indigo_logger(LOG_LEVEL_INFO, "wsc settings STAUT: no data"); 493 | } 494 | } else { 495 | indigo_logger(LOG_LEVEL_ERROR, "STAUT: WPS Erorr. Failed to get settings."); 496 | return NULL; 497 | } 498 | } 499 | } 500 | 501 | void get_mld_link_mac(char *mac_addr, size_t size, char *band) { 502 | FILE *fp; 503 | char buffer[S_BUFFER_LEN], *ptr, name[32], addr[32]; 504 | char *if_name; 505 | int band_id, freq; 506 | 507 | memset(mac_addr, 0, size); 508 | if (strcmp(band, "2.4GHz") == 0) 509 | band_id = BAND_24GHZ; 510 | else if (strcmp(band, "5GHz") == 0) 511 | band_id = BAND_5GHZ; 512 | else if (strcmp(band, "6GHz") == 0) 513 | band_id = BAND_6GHZ; 514 | if_name = get_wireless_interface(); 515 | 516 | fp = popen("iw dev", "r"); 517 | if (fp) { 518 | while (fgets(buffer, sizeof(buffer), fp) != NULL) { 519 | ptr = strstr(buffer, "Interface"); 520 | if (ptr != NULL) { 521 | sscanf(ptr, "%*s %s", name); 522 | if (!strncmp(name, if_name, strlen(if_name))) { 523 | /* link 0: 524 | addr 00:03:7f:12:66:60 525 | channel 36 (5180 MHz), width: 80 MHz, center1: 5210 MHz 526 | txpower 28.00 dBm 527 | */ 528 | while (fgets(buffer, sizeof(buffer), fp) != NULL) { 529 | ptr = strstr(buffer, "link"); 530 | if (ptr != NULL) { 531 | fgets(buffer, sizeof(buffer), fp); 532 | sscanf(buffer, "%*s %s", addr); 533 | fgets(buffer, sizeof(buffer), fp); 534 | ptr = strchr(buffer, '('); 535 | sscanf(ptr+1, "%d", &freq); 536 | if (verify_band_from_freq(freq, band_id) == 0) { 537 | snprintf(mac_addr, size, "%s", addr); 538 | break; 539 | } 540 | } 541 | } 542 | if (mac_addr[0]) 543 | break; 544 | } 545 | } 546 | } 547 | pclose(fp); 548 | } 549 | 550 | return; 551 | } 552 | -------------------------------------------------------------------------------- /vendor_specific_sniffer.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2020 Wi-Fi Alliance */ 2 | 3 | /* Permission to use, copy, modify, and/or distribute this software for any */ 4 | /* purpose with or without fee is hereby granted, provided that the above */ 5 | /* copyright notice and this permission notice appear in all copies. */ 6 | 7 | /* THE SOFTWARE IS PROVIDED 'AS IS' AND THE AUTHOR DISCLAIMS ALL */ 8 | /* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED */ 9 | /* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL */ 10 | /* THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR */ 11 | /* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING */ 12 | /* FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF */ 13 | /* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT */ 14 | /* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS */ 15 | /* SOFTWARE. */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include "vendor_specific.h" 24 | #include "utils.h" 25 | 26 | #ifdef _TEST_SNIFFER_ 27 | /** 28 | * Generic platform dependent API implementation 29 | */ 30 | 31 | void interfaces_init() { 32 | char buffer[BUFFER_LEN]; 33 | 34 | memset(buffer, 0, sizeof(buffer)); 35 | sprintf(buffer, "iw phy phy0 interface add mon0 type monitor >/dev/null 2>/dev/null"); 36 | system(buffer); 37 | 38 | sleep(1); 39 | } 40 | 41 | /* Be invoked when start controlApp */ 42 | void vendor_init() { 43 | interfaces_init(); 44 | } 45 | 46 | /* Be invoked when terminate controlApp */ 47 | void vendor_deinit() { 48 | char buffer[S_BUFFER_LEN]; 49 | memset(buffer, 0, sizeof(buffer)); 50 | system("iw dev mon0 del >/dev/null 2>/dev/null"); 51 | } 52 | 53 | #endif /* _TEST_SNIFFER_ */ 54 | -------------------------------------------------------------------------------- /wpa_ctrl.c: -------------------------------------------------------------------------------- 1 | /* 2 | * wpa_supplicant/hostapd control interface library 3 | * Copyright (c) 2004-2005, Jouni Malinen 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License version 2 as 7 | * published by the Free Software Foundation. 8 | * 9 | * Alternatively, this software may be distributed under the terms of BSD 10 | * license. 11 | * 12 | * See README and COPYING for more details. 13 | */ 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #ifndef CONFIG_NATIVE_WINDOWS 23 | #include 24 | #include 25 | #include 26 | #endif /* CONFIG_NATIVE_WINDOWS */ 27 | 28 | #include "vendor_specific.h" 29 | #include "wpa_ctrl.h" 30 | #include "utils.h" 31 | #ifdef CONFIG_NATIVE_WINDOWS 32 | #include "common.h" 33 | #endif /* CONFIG_NATIVE_WINDOWS */ 34 | 35 | 36 | /** 37 | * struct wpa_ctrl - Internal structure for control interface library 38 | * 39 | * This structure is used by the wpa_supplicant/hostapd control interface 40 | * library to store internal data. Programs using the library should not touch 41 | * this data directly. They can only use the pointer to the data structure as 42 | * an identifier for the control interface connection and use this as one of 43 | * the arguments for most of the control interface library functions. 44 | */ 45 | struct wpa_ctrl { 46 | int s; 47 | #ifdef CONFIG_CTRL_IFACE_UDP 48 | struct sockaddr_in local; 49 | struct sockaddr_in dest; 50 | char *cookie; 51 | #else /* CONFIG_CTRL_IFACE_UDP */ 52 | struct sockaddr_un local; 53 | struct sockaddr_un dest; 54 | #endif /* CONFIG_CTRL_IFACE_UDP */ 55 | }; 56 | 57 | 58 | struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path) 59 | { 60 | struct wpa_ctrl *ctrl; 61 | #ifndef CONFIG_CTRL_IFACE_UDP 62 | static int counter = 0; 63 | #else 64 | unsigned short port = 0; 65 | char buf[128]; 66 | size_t len; 67 | #endif /* CONFIG_CTRL_IFACE_UDP */ 68 | 69 | ctrl = malloc(sizeof(*ctrl)); 70 | if (ctrl == NULL) 71 | return NULL; 72 | memset(ctrl, 0, sizeof(*ctrl)); 73 | 74 | #ifdef CONFIG_CTRL_IFACE_UDP 75 | ctrl->s = socket(PF_INET, SOCK_DGRAM, 0); 76 | if (ctrl->s < 0) { 77 | perror("socket"); 78 | free(ctrl); 79 | return NULL; 80 | } 81 | 82 | ctrl->local.sin_family = AF_INET; 83 | #ifdef CONFIG_CTRL_IFACE_UDP 84 | ctrl->local.sin_addr.s_addr = INADDR_ANY; 85 | #else /* CONFIG_CTRL_IFACE_UDP_REMOTE */ 86 | ctrl->local.sin_addr.s_addr = htonl((127 << 24) | 1); 87 | #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */ 88 | if (bind(ctrl->s, (struct sockaddr *) &ctrl->local, 89 | sizeof(ctrl->local)) < 0) { 90 | close(ctrl->s); 91 | free(ctrl); 92 | return NULL; 93 | } 94 | 95 | sscanf(ctrl_path, "udp:%hu", &port); 96 | 97 | ctrl->dest.sin_family = AF_INET; 98 | ctrl->dest.sin_addr.s_addr = htonl((127 << 24) | 1); 99 | ctrl->dest.sin_port = htons(port); 100 | if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest, 101 | sizeof(ctrl->dest)) < 0) { 102 | perror("connect"); 103 | close(ctrl->s); 104 | free(ctrl); 105 | return NULL; 106 | } 107 | 108 | len = sizeof(buf) - 1; 109 | if (wpa_ctrl_request(ctrl, "GET_COOKIE", 10, buf, &len, NULL) == 0) { 110 | buf[len] = '\0'; 111 | ctrl->cookie = strdup(buf); 112 | printf("%s\n\n", ctrl->cookie); 113 | } 114 | #else /* CONFIG_CTRL_IFACE_UDP */ 115 | ctrl->s = socket(PF_UNIX, SOCK_DGRAM, 0); 116 | if (ctrl->s < 0) { 117 | free(ctrl); 118 | return NULL; 119 | } 120 | 121 | ctrl->local.sun_family = AF_UNIX; 122 | snprintf(ctrl->local.sun_path, sizeof(ctrl->local.sun_path), 123 | "/tmp/wpa_ctrl_%d-%d", getpid(), counter++); 124 | if (bind(ctrl->s, (struct sockaddr *) &ctrl->local, 125 | sizeof(ctrl->local)) < 0) { 126 | close(ctrl->s); 127 | free(ctrl); 128 | return NULL; 129 | } 130 | 131 | ctrl->dest.sun_family = AF_UNIX; 132 | snprintf(ctrl->dest.sun_path, sizeof(ctrl->dest.sun_path), "%s", 133 | ctrl_path); 134 | if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest, 135 | sizeof(ctrl->dest)) < 0) { 136 | close(ctrl->s); 137 | unlink(ctrl->local.sun_path); 138 | free(ctrl); 139 | return NULL; 140 | } 141 | #endif /* CONFIG_CTRL_IFACE_UDP */ 142 | 143 | return ctrl; 144 | } 145 | 146 | 147 | void wpa_ctrl_close(struct wpa_ctrl *ctrl) 148 | { 149 | #ifndef CONFIG_CTRL_IFACE_UDP 150 | unlink(ctrl->local.sun_path); 151 | #else 152 | if (ctrl->cookie) 153 | free(ctrl->cookie); 154 | #endif /* CONFIG_CTRL_IFACE_UDP */ 155 | close(ctrl->s); 156 | free(ctrl); 157 | } 158 | 159 | 160 | int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len, 161 | char *reply, size_t *reply_len, 162 | void (*msg_cb)(char *msg, size_t len)) 163 | { 164 | struct timeval tv; 165 | int res; 166 | fd_set rfds; 167 | const char *_cmd; 168 | char *cmd_buf = NULL; 169 | size_t _cmd_len; 170 | 171 | #ifdef CONFIG_CTRL_IFACE_UDP 172 | if (ctrl->cookie) { 173 | char *pos; 174 | _cmd_len = strlen(ctrl->cookie) + 1 + cmd_len; 175 | cmd_buf = malloc(_cmd_len); 176 | if (cmd_buf == NULL) 177 | return -1; 178 | _cmd = cmd_buf; 179 | pos = cmd_buf; 180 | strlcpy(pos, ctrl->cookie, _cmd_len); 181 | pos += strlen(ctrl->cookie); 182 | *pos++ = ' '; 183 | memcpy(pos, cmd, cmd_len); 184 | } else 185 | #endif /* CONFIG_CTRL_IFACE_UDP */ 186 | { 187 | _cmd = cmd; 188 | _cmd_len = cmd_len; 189 | } 190 | 191 | if (send(ctrl->s, _cmd, _cmd_len, 0) < 0) { 192 | return -1; 193 | } 194 | 195 | for (;;) { 196 | tv.tv_sec = 2; 197 | tv.tv_usec = 0; 198 | FD_ZERO(&rfds); 199 | FD_SET(ctrl->s, &rfds); 200 | res = select(ctrl->s + 1, &rfds, NULL, NULL, &tv); 201 | if (FD_ISSET(ctrl->s, &rfds)) { 202 | res = recv(ctrl->s, reply, *reply_len, 0); 203 | if (res < 0 && errno == EINTR) { 204 | continue; 205 | } 206 | if (res < 0) { 207 | return res; 208 | } 209 | if (res > 0 && reply[0] == '<') { 210 | /* This is an unsolicited message from 211 | * wpa_supplicant, not the reply to the 212 | * request. Use msg_cb to report this to the 213 | * caller. */ 214 | if (msg_cb) { 215 | /* Make sure the message is nul 216 | * terminated. */ 217 | if ((size_t) res == *reply_len) 218 | res = (*reply_len) - 1; 219 | reply[res] = '\0'; 220 | msg_cb(reply, res); 221 | } 222 | continue; 223 | } 224 | *reply_len = res; 225 | break; 226 | } else { 227 | return -2; 228 | } 229 | } 230 | return 0; 231 | } 232 | 233 | 234 | static int wpa_ctrl_attach_helper(struct wpa_ctrl *ctrl, int attach) 235 | { 236 | char buf[10]; 237 | int ret; 238 | size_t len = 10; 239 | 240 | ret = wpa_ctrl_request(ctrl, attach ? "ATTACH" : "DETACH", 6, 241 | buf, &len, NULL); 242 | if (ret < 0) 243 | return ret; 244 | if (len == 3 && memcmp(buf, "OK\n", 3) == 0) 245 | return 0; 246 | return -1; 247 | } 248 | 249 | 250 | int wpa_ctrl_attach(struct wpa_ctrl *ctrl) 251 | { 252 | return wpa_ctrl_attach_helper(ctrl, 1); 253 | } 254 | 255 | 256 | int wpa_ctrl_detach(struct wpa_ctrl *ctrl) 257 | { 258 | return wpa_ctrl_attach_helper(ctrl, 0); 259 | } 260 | 261 | 262 | int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len) 263 | { 264 | int res; 265 | 266 | res = recv(ctrl->s, reply, *reply_len, 0); 267 | if (res < 0) 268 | return res; 269 | *reply_len = res; 270 | return 0; 271 | } 272 | 273 | 274 | int wpa_ctrl_pending(struct wpa_ctrl *ctrl) 275 | { 276 | struct timeval tv; 277 | int res; 278 | fd_set rfds; 279 | tv.tv_sec = 0; 280 | tv.tv_usec = 0; 281 | FD_ZERO(&rfds); 282 | FD_SET(ctrl->s, &rfds); 283 | res = select(ctrl->s + 1, &rfds, NULL, NULL, &tv); 284 | return FD_ISSET(ctrl->s, &rfds); 285 | } 286 | 287 | 288 | int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl) 289 | { 290 | return ctrl->s; 291 | } 292 | -------------------------------------------------------------------------------- /wpa_ctrl.h: -------------------------------------------------------------------------------- 1 | /* 2 | * wpa_supplicant/hostapd control interface library 3 | * Copyright (c) 2004-2005, Jouni Malinen 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License version 2 as 7 | * published by the Free Software Foundation. 8 | * 9 | * Alternatively, this software may be distributed under the terms of BSD 10 | * license. 11 | * 12 | * See README and COPYING for more details. 13 | */ 14 | 15 | #ifndef WPA_CTRL_H 16 | #define WPA_CTRL_H 17 | 18 | #ifdef __cplusplus 19 | extern "C" { 20 | #endif 21 | 22 | /* wpa_supplicant control interface - fixed message prefixes */ 23 | 24 | /** Interactive request for identity/password/pin */ 25 | #define WPA_CTRL_REQ "CTRL-REQ-" 26 | 27 | /** Response to identity/password/pin request */ 28 | #define WPA_CTRL_RSP "CTRL-RSP-" 29 | 30 | /* Event messages with fixed prefix */ 31 | /** Authentication completed successfully and data connection enabled */ 32 | #define WPA_EVENT_CONNECTED "CTRL-EVENT-CONNECTED " 33 | /** Disconnected, data connection is not available */ 34 | #define WPA_EVENT_DISCONNECTED "CTRL-EVENT-DISCONNECTED " 35 | /** wpa_supplicant is exiting */ 36 | #define WPA_EVENT_TERMINATING "CTRL-EVENT-TERMINATING " 37 | /** Password change was completed successfully */ 38 | #define WPA_EVENT_PASSWORD_CHANGED "CTRL-EVENT-PASSWORD-CHANGED " 39 | /** EAP-Request/Notification received */ 40 | #define WPA_EVENT_EAP_NOTIFICATION "CTRL-EVENT-EAP-NOTIFICATION " 41 | /** EAP authentication started (EAP-Request/Identity received) */ 42 | #define WPA_EVENT_EAP_STARTED "CTRL-EVENT-EAP-STARTED " 43 | /** EAP method selected */ 44 | #define WPA_EVENT_EAP_METHOD "CTRL-EVENT-EAP-METHOD " 45 | /** EAP authentication completed successfully */ 46 | #define WPA_EVENT_EAP_SUCCESS "CTRL-EVENT-EAP-SUCCESS " 47 | /** EAP authentication failed (EAP-Failure received) */ 48 | #define WPA_EVENT_EAP_FAILURE "CTRL-EVENT-EAP-FAILURE " 49 | 50 | 51 | /* wpa_supplicant/hostapd control interface access */ 52 | 53 | /** 54 | * wpa_ctrl_open - Open a control interface to wpa_supplicant/hostapd 55 | * @ctrl_path: Path for UNIX domain sockets; ignored if UDP sockets are used. 56 | * Returns: Pointer to abstract control interface data or %NULL on failure 57 | * 58 | * This function is used to open a control interface to wpa_supplicant/hostapd. 59 | * ctrl_path is usually /var/run/wpa_supplicant or /var/run/hostapd. This path 60 | * is configured in wpa_supplicant/hostapd and other programs using the control 61 | * interface need to use matching path configuration. 62 | */ 63 | struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path); 64 | 65 | 66 | /** 67 | * wpa_ctrl_close - Close a control interface to wpa_supplicant/hostapd 68 | * @ctrl: Control interface data from wpa_ctrl_open() 69 | * 70 | * This function is used to close a control interface. 71 | */ 72 | void wpa_ctrl_close(struct wpa_ctrl *ctrl); 73 | 74 | 75 | /** 76 | * wpa_ctrl_request - Send a command to wpa_supplicant/hostapd 77 | * @ctrl: Control interface data from wpa_ctrl_open() 78 | * @cmd: Command; usually, ASCII text, e.g., "PING" 79 | * @cmd_len: Length of the cmd in bytes 80 | * @reply: Buffer for the response 81 | * @reply_len: Reply buffer length 82 | * @msg_cb: Callback function for unsolicited messages or %NULL if not used 83 | * Returns: 0 on success, -1 on error (send or receive failed), -2 on timeout 84 | * 85 | * This function is used to send commands to wpa_supplicant/hostapd. Received 86 | * response will be written to reply and reply_len is set to the actual length 87 | * of the reply. This function will block for up to two seconds while waiting 88 | * for the reply. If unsolicited messages are received, the blocking time may 89 | * be longer. 90 | * 91 | * msg_cb can be used to register a callback function that will be called for 92 | * unsolicited messages received while waiting for the command response. These 93 | * messages may be received if wpa_ctrl_request() is called at the same time as 94 | * wpa_supplicant/hostapd is sending such a message. This can happen only if 95 | * the program has used wpa_ctrl_attach() to register itself as a monitor for 96 | * event messages. Alternatively to msg_cb, programs can register two control 97 | * interface connections and use one of them for commands and the other one for 98 | * receiving event messages, in other words, call wpa_ctrl_attach() only for 99 | * the control interface connection that will be used for event messages. 100 | */ 101 | int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len, 102 | char *reply, size_t *reply_len, 103 | void (*msg_cb)(char *msg, size_t len)); 104 | 105 | 106 | /** 107 | * wpa_ctrl_attach - Register as an event monitor for the control interface 108 | * @ctrl: Control interface data from wpa_ctrl_open() 109 | * Returns: 0 on success, -1 on failure, -2 on timeout 110 | * 111 | * This function registers the control interface connection as a monitor for 112 | * wpa_supplicant/hostapd events. After a success wpa_ctrl_attach() call, the 113 | * control interface connection starts receiving event messages that can be 114 | * read with wpa_ctrl_recv(). 115 | */ 116 | int wpa_ctrl_attach(struct wpa_ctrl *ctrl); 117 | 118 | 119 | /** 120 | * wpa_ctrl_detach - Unregister event monitor from the control interface 121 | * @ctrl: Control interface data from wpa_ctrl_open() 122 | * Returns: 0 on success, -1 on failure, -2 on timeout 123 | * 124 | * This function unregisters the control interface connection as a monitor for 125 | * wpa_supplicant/hostapd events, i.e., cancels the registration done with 126 | * wpa_ctrl_attach(). 127 | */ 128 | int wpa_ctrl_detach(struct wpa_ctrl *ctrl); 129 | 130 | 131 | /** 132 | * wpa_ctrl_recv - Receive a pending control interface message 133 | * @ctrl: Control interface data from wpa_ctrl_open() 134 | * @reply: Buffer for the message data 135 | * @reply_len: Length of the reply buffer 136 | * Returns: 0 on success, -1 on failure 137 | * 138 | * This function will receive a pending control interface message. This 139 | * function will block if no messages are available. The received response will 140 | * be written to reply and reply_len is set to the actual length of the reply. 141 | * wpa_ctrl_recv() is only used for event messages, i.e., wpa_ctrl_attach() 142 | * must have been used to register the control interface as an event monitor. 143 | */ 144 | int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len); 145 | 146 | 147 | /** 148 | * wpa_ctrl_pending - Check whether there are pending event messages 149 | * @ctrl: Control interface data from wpa_ctrl_open() 150 | * Returns: Non-zero if there are pending messages 151 | * 152 | * This function will check whether there are any pending control interface 153 | * message available to be received with wpa_ctrl_recv(). wpa_ctrl_pending() is 154 | * only used for event messages, i.e., wpa_ctrl_attach() must have been used to 155 | * register the control interface as an event monitor. 156 | */ 157 | int wpa_ctrl_pending(struct wpa_ctrl *ctrl); 158 | 159 | 160 | /** 161 | * wpa_ctrl_get_fd - Get file descriptor used by the control interface 162 | * @ctrl: Control interface data from wpa_ctrl_open() 163 | * Returns: File descriptor used for the connection 164 | * 165 | * This function can be used to get the file descriptor that is used for the 166 | * control interface connection. The returned value can be used, e.g., with 167 | * select() while waiting for multiple events. 168 | * 169 | * The returned file descriptor must not be used directly for sending or 170 | * receiving packets; instead, the library functions wpa_ctrl_request() and 171 | * wpa_ctrl_recv() must be used for this. 172 | */ 173 | int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl); 174 | 175 | #ifdef CONFIG_CTRL_IFACE_UDP 176 | #define WPA_CTRL_IFACE_PORT 9877 177 | #define WPA_GLOBAL_CTRL_IFACE_PORT 9878 178 | #endif /* CONFIG_CTRL_IFACE_UDP */ 179 | 180 | 181 | #ifdef __cplusplus 182 | } 183 | #endif 184 | 185 | #endif /* WPA_CTRL_H */ 186 | --------------------------------------------------------------------------------