/* * Sigma Control API DUT (NAN functionality) * Copyright (c) 2014-2015, Qualcomm Atheros, Inc. * All Rights Reserved. * Licensed under the Clear BSD license. See README for more details. */ #include "sigma_dut.h" #include #include "wpa_ctrl.h" #include "wpa_helpers.h" #include "wifi_hal.h" #include "nan.h" pthread_cond_t gCondition; pthread_mutex_t gMutex; wifi_handle global_handle; static int nan_state = 0; static int event_anyresponse = 0; static int is_fam = 0; uint16_t global_header_handle = 0; uint32_t global_match_handle = 0; #define MAC_ADDR_ARRAY(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] #define MAC_ADDR_STR "%02x:%02x:%02x:%02x:%02x:%02x" #ifndef ETH_ALEN #define ETH_ALEN 6 #endif struct sigma_dut *global_dut = NULL; static char global_nan_mac_addr[ETH_ALEN]; static char global_event_resp_buf[1024]; static int nan_further_availability_tx(struct sigma_dut *dut, struct sigma_conn *conn, struct sigma_cmd *cmd); static int nan_further_availability_rx(struct sigma_dut *dut, struct sigma_conn *conn, struct sigma_cmd *cmd); void nan_hex_dump(struct sigma_dut *dut, uint8_t *data, size_t len) { char buf[512]; uint16_t index; uint8_t *ptr; int pos; memset(buf, 0, sizeof(buf)); ptr = data; pos = 0; for (index = 0; index < len; index++) { pos += sprintf(&(buf[pos]), "%02x ", *ptr++); if (pos > 508) break; } sigma_dut_print(dut, DUT_MSG_INFO, "HEXDUMP len=[%d]", (int) len); sigma_dut_print(dut, DUT_MSG_INFO, "buf:%s", buf); } int nan_parse_hex(unsigned char c) { if (c >= '0' && c <= '9') return c - '0'; if (c >= 'a' && c <= 'f') return c - 'a' + 10; if (c >= 'A' && c <= 'F') return c - 'A' + 10; return 0; } int nan_parse_token(const char *tokenIn, u8 *tokenOut, int *filterLen) { int total_len = 0, len = 0; char *saveptr = NULL; tokenIn = strtok_r((char *) tokenIn, ":", &saveptr); while (tokenIn != NULL) { len = strlen(tokenIn); if (len == 1 && *tokenIn == '*') len = 0; tokenOut[total_len++] = (u8) len; if (len != 0) memcpy((u8 *) tokenOut + total_len, tokenIn, len); total_len += len; tokenIn = strtok_r(NULL, ":", &saveptr); } *filterLen = total_len; return 0; } int nan_parse_mac_address(struct sigma_dut *dut, const char *arg, u8 *addr) { if (strlen(arg) != 17) { sigma_dut_print(dut, DUT_MSG_ERROR, "Invalid mac address %s", arg); sigma_dut_print(dut, DUT_MSG_ERROR, "expected format xx:xx:xx:xx:xx:xx"); return -1; } addr[0] = nan_parse_hex(arg[0]) << 4 | nan_parse_hex(arg[1]); addr[1] = nan_parse_hex(arg[3]) << 4 | nan_parse_hex(arg[4]); addr[2] = nan_parse_hex(arg[6]) << 4 | nan_parse_hex(arg[7]); addr[3] = nan_parse_hex(arg[9]) << 4 | nan_parse_hex(arg[10]); addr[4] = nan_parse_hex(arg[12]) << 4 | nan_parse_hex(arg[13]); addr[5] = nan_parse_hex(arg[15]) << 4 | nan_parse_hex(arg[16]); return 0; } int nan_parse_mac_address_list(struct sigma_dut *dut, const char *input, u8 *output, u16 max_addr_allowed) { /* * Reads a list of mac address separated by space. Each MAC address * should have the format of aa:bb:cc:dd:ee:ff. */ char *saveptr; char *token; int i = 0; for (i = 0; i < max_addr_allowed; i++) { token = strtok_r((i == 0) ? (char *) input : NULL, " ", &saveptr); if (token) { nan_parse_mac_address(dut, token, output); output += NAN_MAC_ADDR_LEN; } else break; } sigma_dut_print(dut, DUT_MSG_INFO, "Num MacAddress:%d", i); return i; } int nan_parse_hex_string(struct sigma_dut *dut, const char *input, u8 *output, int *outputlen) { int i = 0; int j = 0; for (i = 0; i < (int) strlen(input) && j < *outputlen; i += 2) { output[j] = nan_parse_hex(input[i]); if (i + 1 < (int) strlen(input)) { output[j] = ((output[j] << 4) | nan_parse_hex(input[i + 1])); } j++; } *outputlen = j; sigma_dut_print(dut, DUT_MSG_INFO, "Input:%s inputlen:%d outputlen:%d", input, (int) strlen(input), (int) *outputlen); return 0; } int wait(struct timespec abstime) { struct timeval now; gettimeofday(&now, NULL); abstime.tv_sec += now.tv_sec; if (((abstime.tv_nsec + now.tv_usec * 1000) > 1000 * 1000 * 1000) || (abstime.tv_nsec + now.tv_usec * 1000 < 0)) { abstime.tv_sec += 1; abstime.tv_nsec += now.tv_usec * 1000; abstime.tv_nsec -= 1000 * 1000 * 1000; } else { abstime.tv_nsec += now.tv_usec * 1000; } return pthread_cond_timedwait(&gCondition, &gMutex, &abstime); } int nan_cmd_sta_preset_testparameters(struct sigma_dut *dut, struct sigma_conn *conn, struct sigma_cmd *cmd) { const char *oper_chan = get_param(cmd, "oper_chan"); int channel = 0; channel = atoi(oper_chan); dut->sta_channel = channel; return 0; } int sigma_nan_enable(struct sigma_dut *dut, struct sigma_conn *conn, struct sigma_cmd *cmd) { const char *master_pref = get_param(cmd, "MasterPref"); const char *rand_fac = get_param(cmd, "RandFactor"); const char *hop_count = get_param(cmd, "HopCount"); const char *high_tsf = get_param(cmd, "HighTSF"); const char *sdftx_band = get_param(cmd, "SDFTxBand"); const char *oper_chan = get_param(cmd, "oper_chn"); const char *further_avail_ind = get_param(cmd, "FurtherAvailInd"); const char *band = get_param(cmd, "Band"); const char *only_5g = get_param(cmd, "5GOnly"); struct timespec abstime; NanEnableRequest req; memset(&req, 0, sizeof(NanEnableRequest)); req.header.handle = 0xFFFF; req.header.transaction_id = 0; req.support_5g = 1; req.config_5g_beacons = 1; req.beacon_5g_val = 1; req.config_5g_discovery = 1; req.discovery_5g_val = 1; req.cluster_low = 0; req.cluster_high = 0xFFFF; req.sid_beacon = 1; req.rssi_close = 60; req.rssi_middle = 70; req.rssi_proximity = 70; req.hop_count_limit = 2; req.random_time = 120; req.master_pref = 30; req.periodic_scan_interval = 20; /* This is a debug hack to becon in channel 11 */ if (oper_chan) { req.config_2dot4g_support = 1; req.support_2dot4g_val = 111; } if (dut->device_type == STA_testbed) { sigma_dut_print(dut, DUT_MSG_INFO, "Device in Test Bed mode"); req.config_debug_flags = 1; req.debug_flags_val = 0x80000000; if (high_tsf) { if (strcasecmp(high_tsf, "On") == 0) req.debug_flags_val = 0xc0000000; } } if (master_pref) { int master_pref_val = strtoul(master_pref, NULL, 0); req.master_pref = master_pref_val; } if (rand_fac) { int rand_fac_val = strtoul(rand_fac, NULL, 0); req.config_random_factor_force = 1; req.random_factor_force_val = rand_fac_val; } if (hop_count) { int hop_count_val = strtoul(hop_count, NULL, 0); req.config_hop_count_force = 1; req.hop_count_force_val = hop_count_val; } if (sdftx_band) { if (strcasecmp(sdftx_band, "5G") == 0) { req.config_2dot4g_support = 1; req.support_2dot4g_val = 0; } } if (band) { if (strcasecmp(band, "24G") == 0) { sigma_dut_print(dut, DUT_MSG_INFO, "Band 2.4GHz selected"); /* Enable 2.4G support */ req.config_2dot4g_support = 1; req.support_2dot4g_val = 1; req.config_2dot4g_beacons = 1; req.beacon_2dot4g_val = 1; req.config_2dot4g_discovery = 1; req.discovery_2dot4g_val = 1; /* Disable 5G support */ req.support_5g = 0; req.config_5g_beacons = 1; req.beacon_5g_val = 0; req.config_5g_discovery = 1; req.discovery_5g_val = 0; } } if (further_avail_ind) { sigma_dut_print(dut, DUT_MSG_INFO, "FAM Test Enabled"); if (strcasecmp(further_avail_ind, "tx") == 0) { is_fam = 1; nan_further_availability_tx(dut, conn, cmd); return 0; } else if (strcasecmp(further_avail_ind, "rx") == 0) { nan_further_availability_rx(dut, conn, cmd); return 0; } } if (only_5g && atoi(only_5g)) { sigma_dut_print(dut, DUT_MSG_INFO, "5GHz only enabled"); req.config_2dot4g_support = 1; req.support_2dot4g_val = 1; req.config_2dot4g_beacons = 1; req.beacon_2dot4g_val = 0; req.config_2dot4g_discovery = 1; req.discovery_2dot4g_val = 1; } nan_enable_request(0, global_handle, &req); abstime.tv_sec = 4; abstime.tv_nsec = 0; return wait(abstime); } int sigma_nan_disable(struct sigma_dut *dut, struct sigma_conn *conn, struct sigma_cmd *cmd) { NanDisableRequest req; struct timespec abstime; memset(&req, 0, sizeof(NanDisableRequest)); req.header.handle = 0x0; req.header.transaction_id = 0; nan_disable_request(0, global_handle, &req); abstime.tv_sec = 4; abstime.tv_nsec = 0; return wait(abstime); } int sigma_nan_config_enable(struct sigma_dut *dut, struct sigma_conn *conn, struct sigma_cmd *cmd) { const char *master_pref = get_param(cmd, "MasterPref"); const char *rand_fac = get_param(cmd, "RandFactor"); const char *hop_count = get_param(cmd, "HopCount"); struct timespec abstime; NanConfigRequest req; memset(&req, 0, sizeof(NanConfigRequest)); req.header.handle = 0x0; req.header.transaction_id = 0; req.config_rssi_proximity = 1; req.rssi_proximity = 70; if (master_pref) { int master_pref_val = strtoul(master_pref, NULL, 0); req.config_master_pref = 1; req.master_pref = master_pref_val; } if (rand_fac) { int rand_fac_val = strtoul(rand_fac, NULL, 0); req.config_random_factor_force = 1; req.random_factor_force_val = rand_fac_val; } if (hop_count) { int hop_count_val = strtoul(hop_count, NULL, 0); req.config_hop_count_force = 1; req.hop_count_force_val = hop_count_val; } nan_config_request(0, global_handle, &req); abstime.tv_sec = 4; abstime.tv_nsec = 0; return wait(abstime); } static int sigma_nan_subscribe_request(struct sigma_dut *dut, struct sigma_conn *conn, struct sigma_cmd *cmd) { const char *subscribe_type = get_param(cmd, "SubscribeType"); const char *service_name = get_param(cmd, "ServiceName"); const char *disc_range = get_param(cmd, "DiscoveryRange"); const char *rx_match_filter = get_param(cmd, "rxMatchFilter"); const char *tx_match_filter = get_param(cmd, "txMatchFilter"); const char *sdftx_dw = get_param(cmd, "SDFTxDW"); const char *discrange_ltd = get_param(cmd, "DiscRangeLtd"); const char *include_bit = get_param(cmd, "IncludeBit"); const char *mac = get_param(cmd, "MAC"); const char *srf_type = get_param(cmd, "SRFType"); NanSubscribeRequest req; int filter_len_rx = 0, filter_len_tx = 0; u8 input_rx[NAN_MAX_MATCH_FILTER_LEN]; u8 input_tx[NAN_MAX_MATCH_FILTER_LEN]; memset(&req, 0, sizeof(NanSubscribeRequest)); req.header.handle = 0xFFFF; req.header.transaction_id = 0; req.ttl = 0; req.period = 1000; req.subscribe_type = 1; req.serviceResponseFilter = 1; /* MAC */ req.serviceResponseInclude = 0; req.ssiRequiredForMatchIndication = 0; req.subscribe_match = NAN_MATCH_ALG_MATCH_CONTINUOUS; req.subscribe_count = 0; if (subscribe_type) { if (strcasecmp(subscribe_type, "Active") == 0) { req.subscribe_type = 1; } else if (strcasecmp(subscribe_type, "Passive") == 0) { req.subscribe_type = 0; } else if (strcasecmp(subscribe_type, "Cancel") == 0) { NanSubscribeCancelRequest req; memset(&req, 0, sizeof(NanSubscribeCancelRequest)); req.header.handle = 128; req.header.transaction_id = 0; nan_subscribe_cancel_request(0, global_handle, &req); return 0; } } if (disc_range) req.rssi_threshold_flag = atoi(disc_range); if (sdftx_dw) req.subscribe_count = atoi(sdftx_dw); /* Check this once again if config can be called here (TBD) */ if (discrange_ltd) req.rssi_threshold_flag = atoi(discrange_ltd); if (include_bit) { int include_bit_val = atoi(include_bit); req.serviceResponseInclude = include_bit_val; sigma_dut_print(dut, DUT_MSG_INFO, "Includebit set %d", req.serviceResponseInclude); } if (srf_type) { int srf_type_val = atoi(srf_type); if (srf_type_val == 1) req.serviceResponseFilter = 0; /* Bloom */ else req.serviceResponseFilter = 1; /* MAC */ req.useServiceResponseFilter = 1; sigma_dut_print(dut, DUT_MSG_INFO, "srfFilter %d", req.serviceResponseFilter); } if (mac) { sigma_dut_print(dut, DUT_MSG_INFO, "MAC_ADDR List %s", mac); req.num_intf_addr_present = nan_parse_mac_address_list( dut, mac, &req.intf_addr[0][0], NAN_MAX_SUBSCRIBE_MAX_ADDRESS); } memset(input_rx, 0, sizeof(input_rx)); memset(input_tx, 0, sizeof(input_tx)); if (rx_match_filter) { nan_parse_token(rx_match_filter, input_rx, &filter_len_rx); sigma_dut_print(dut, DUT_MSG_INFO, "RxFilterLen %d", filter_len_rx); } if (tx_match_filter) { nan_parse_token(tx_match_filter, input_tx, &filter_len_tx); sigma_dut_print(dut, DUT_MSG_INFO, "TxFilterLen %d", filter_len_tx); } if (tx_match_filter) { req.tx_match_filter_len = filter_len_tx; memcpy(req.tx_match_filter, input_tx, filter_len_tx); nan_hex_dump(dut, req.tx_match_filter, filter_len_tx); } if (rx_match_filter) { req.rx_match_filter_len = filter_len_rx; memcpy(req.rx_match_filter, input_rx, filter_len_rx); nan_hex_dump(dut, req.rx_match_filter, filter_len_rx); } strlcpy((char *) req.service_name, service_name, strlen(service_name) + 1); req.service_name_len = strlen(service_name); nan_subscribe_request(0, global_handle, &req); return 0; } int config_post_disc_attr(void) { NanConfigRequest configReq; memset(&configReq, 0, sizeof(NanConfigRequest)); configReq.header.handle = 0x0; configReq.header.transaction_id = 0; /* Configure Post disc attr */ /* Make these defines and use correct enum */ configReq.config_discovery_attr = 1; configReq.discovery_attr_val.type = 4; /* Further Nan discovery */ configReq.discovery_attr_val.role = 0; configReq.discovery_attr_val.transmit_freq = 1; configReq.discovery_attr_val.duration = 0; configReq.discovery_attr_val.avail_interval_bitmap = 0x00000008; nan_config_request(0, global_handle, &configReq); return 0; } int sigma_nan_publish_request(struct sigma_dut *dut, struct sigma_conn *conn, struct sigma_cmd *cmd) { const char *publish_type = get_param(cmd, "PublishType"); const char *service_name = get_param(cmd, "ServiceName"); const char *disc_range = get_param(cmd, "DiscoveryRange"); const char *rx_match_filter = get_param(cmd, "rxMatchFilter"); const char *tx_match_filter = get_param(cmd, "txMatchFilter"); const char *sdftx_dw = get_param(cmd, "SDFTxDW"); const char *discrange_ltd = get_param(cmd, "DiscRangeLtd"); NanPublishRequest req; int filter_len_rx = 0, filter_len_tx = 0; u8 input_rx[NAN_MAX_MATCH_FILTER_LEN]; u8 input_tx[NAN_MAX_MATCH_FILTER_LEN]; memset(&req, 0, sizeof(NanPublishRequest)); req.header.handle = 0xFFFF; req.header.transaction_id = 0; req.ttl = 0; req.period = 500; req.replied_event_flag = 1; req.publish_type = NAN_PUBLISH_TYPE_UNSOLICITED; req.tx_type = NAN_TX_TYPE_BROADCAST; req.publish_count = 0; strlcpy((char *) req.service_name, service_name, strlen(service_name) + 1); req.service_name_len = strlen(service_name); if (publish_type) { if (strcasecmp(publish_type, "Solicited") == 0) { req.publish_type = NAN_PUBLISH_TYPE_SOLICITED; } else if (strcasecmp(publish_type, "Cancel") == 0) { NanPublishCancelRequest req; memset(&req, 0, sizeof(NanPublishCancelRequest)); req.header.handle = 1; req.header.transaction_id = 0; nan_publish_cancel_request(0, global_handle, &req); return 0; } } if (disc_range) req.rssi_threshold_flag = atoi(disc_range); if (sdftx_dw) req.publish_count = atoi(sdftx_dw); if (discrange_ltd) req.rssi_threshold_flag = atoi(discrange_ltd); memset(input_rx, 0, sizeof(input_rx)); memset(input_tx, 0, sizeof(input_tx)); if (rx_match_filter) { nan_parse_token(rx_match_filter, input_rx, &filter_len_rx); sigma_dut_print(dut, DUT_MSG_INFO, "RxFilterLen %d", filter_len_rx); } if (tx_match_filter) { nan_parse_token(tx_match_filter, input_tx, &filter_len_tx); sigma_dut_print(dut, DUT_MSG_INFO, "TxFilterLen %d", filter_len_tx); } if (is_fam == 1) { config_post_disc_attr(); /* TODO: Add comments regarding this step */ req.connmap = 0x10; } if (tx_match_filter) { req.tx_match_filter_len = filter_len_tx; memcpy(req.tx_match_filter, input_tx, filter_len_tx); nan_hex_dump(dut, req.tx_match_filter, filter_len_tx); } if (rx_match_filter) { req.rx_match_filter_len = filter_len_rx; memcpy(req.rx_match_filter, input_rx, filter_len_rx); nan_hex_dump(dut, req.rx_match_filter, filter_len_rx); } strlcpy((char *) req.service_name, service_name, strlen(service_name) + 1); req.service_name_len = strlen(service_name); nan_publish_request(0, global_handle, &req); return 0; } static int nan_further_availability_rx(struct sigma_dut *dut, struct sigma_conn *conn, struct sigma_cmd *cmd) { const char *master_pref = get_param(cmd, "MasterPref"); const char *rand_fac = get_param(cmd, "RandFactor"); const char *hop_count = get_param(cmd, "HopCount"); struct timespec abstime; NanEnableRequest req; memset(&req, 0, sizeof(NanEnableRequest)); req.header.handle = 0xFFFF; req.header.transaction_id = 0; req.support_5g = 1; req.config_5g_beacons = 1; req.beacon_5g_val = 1; req.config_5g_discovery = 1; req.discovery_5g_val = 1; req.cluster_low = 0; req.cluster_high = 0xFFFF; req.sid_beacon = 1; req.rssi_close = 60; req.rssi_middle = 70; req.rssi_proximity = 70; req.hop_count_limit = 2; req.random_time = 120; req.master_pref = 30; req.periodic_scan_interval = 20; if (dut->device_type == STA_testbed) { sigma_dut_print(dut, DUT_MSG_INFO, "Device in Test Bed mode"); req.config_debug_flags = 1; /* TODO: Make a comment here.. */ req.debug_flags_val = 0xA0000000; } if (master_pref) req.master_pref = strtoul(master_pref, NULL, 0); if (rand_fac) { int rand_fac_val = strtoul(rand_fac, NULL, 0); req.config_random_factor_force = 1; req.random_factor_force_val = rand_fac_val; } if (hop_count) { int hop_count_val = strtoul(hop_count, NULL, 0); req.config_hop_count_force = 1; req.hop_count_force_val = hop_count_val; } nan_enable_request(0, global_handle, &req); abstime.tv_sec = 4; abstime.tv_nsec = 0; wait(abstime); return 0; } static int nan_further_availability_tx(struct sigma_dut *dut, struct sigma_conn *conn, struct sigma_cmd *cmd) { const char *master_pref = get_param(cmd, "MasterPref"); const char *rand_fac = get_param(cmd, "RandFactor"); const char *hop_count = get_param(cmd, "HopCount"); NanEnableRequest req; NanConfigRequest configReq; memset(&req, 0, sizeof(NanEnableRequest)); req.header.handle = 0xFFFF; req.header.transaction_id = 0; req.support_5g = 1; req.config_5g_beacons = 1; req.beacon_5g_val = 1; req.config_5g_discovery = 1; req.discovery_5g_val = 1; req.cluster_low = 0; req.cluster_high = 0xFFFF; req.sid_beacon = 1; req.rssi_close = 60; req.rssi_middle = 70; req.rssi_proximity = 70; req.hop_count_limit = 2; req.random_time = 120; req.master_pref = 30; req.periodic_scan_interval = 20; if (dut->device_type == STA_testbed) { sigma_dut_print(dut, DUT_MSG_INFO, "Device in Test Bed mode"); req.config_debug_flags = 1; req.debug_flags_val = 0x00000000; } if (master_pref) req.master_pref = strtoul(master_pref, NULL, 0); if (rand_fac) { int rand_fac_val = strtoul(rand_fac, NULL, 0); req.config_random_factor_force = 1; req.random_factor_force_val = rand_fac_val; } if (hop_count) { int hop_count_val = strtoul(hop_count, NULL, 0); req.config_hop_count_force = 1; req.hop_count_force_val = hop_count_val; } nan_enable_request(0, global_handle, &req); /* Start the config of fam */ memset(&configReq, 0, sizeof(NanConfigRequest)); configReq.header.handle = 0x0; configReq.header.transaction_id = 0; configReq.config_fam = 1; configReq.fam_val.numchans = 1; configReq.fam_val.entry_control = 0; configReq.fam_val.class_val = 81; configReq.fam_val.channel = 6; configReq.fam_val.mapid = 0; configReq.fam_val.avail_interval_bitmap = 0x7ffffffe; configReq.fam_val.vendor_elements_len = 0; memset(&configReq.fam_val.vendor_elements[0], 0, sizeof(configReq.fam_val.vendor_elements)); nan_config_request(0, global_handle, &configReq); return 0; } int sigma_nan_transmit_followup(struct sigma_dut *dut, struct sigma_conn *conn, struct sigma_cmd *cmd) { const char *mac = get_param(cmd, "mac"); const char *requestor_id = get_param(cmd, "RemoteInstanceId"); const char *local_id = get_param(cmd, "LocalInstanceId"); const char *service_name = get_param(cmd, "servicename"); NanTransmitFollowupRequest req; memset(&req, 0, sizeof(NanTransmitFollowupRequest)); req.header.handle = (uint16_t)global_header_handle; req.header.transaction_id = 0; req.match_handle = global_match_handle; req.addr[0] = 0xFF; req.addr[1] = 0xFF; req.addr[2] = 0xFF; req.addr[3] = 0xFF; req.addr[4] = 0xFF; req.addr[5] = 0xFF; req.priority = NAN_TX_PRIORITY_NORMAL; req.dw_or_faw = 0; req.service_specific_info_len = strlen(service_name); if (requestor_id) { /* int requestor_id_val = atoi(requestor_id); */ req.match_handle = global_match_handle; } if (local_id) { /* int local_id_val = atoi(local_id); */ req.header.handle = global_header_handle; } if (mac == NULL) { sigma_dut_print(dut, DUT_MSG_ERROR, "Invalid MAC Address"); return -1; } nan_parse_mac_address(dut, mac, req.addr); #if 0 if (requestor_id) req.match_handle = strtoul(requestor_id, NULL, 0); #endif nan_transmit_followup_request(0, global_handle, &req); return 0; } /* NotifyResponse invoked to notify the status of the Request */ void nan_notify_response(NanResponseMsg *rsp_data) { sigma_dut_print(global_dut, DUT_MSG_INFO, "%s: handle %d status %d value %d response_type %d", __func__, rsp_data->header.handle, rsp_data->status, rsp_data->value, rsp_data->response_type); global_header_handle = rsp_data->header.handle; if (rsp_data->response_type == NAN_RESPONSE_STATS) { sigma_dut_print(global_dut, DUT_MSG_INFO, "%s: stats_id %d", __func__, rsp_data->body.stats_response.stats_id); } #if 0 if (rsp_data->response_type == NAN_RESPONSE_CONFIG && rsp_data->status == 0) pthread_cond_signal(&gCondition); #endif } /* Events Callback */ void nan_event_publish_replied(NanPublishRepliedInd *event) { sigma_dut_print(global_dut, DUT_MSG_INFO, "%s: handle %d " MAC_ADDR_STR " rssi:%d", __func__, event->header.handle, MAC_ADDR_ARRAY(event->addr), event->rssi_value); event_anyresponse = 1; snprintf(global_event_resp_buf, sizeof(global_event_resp_buf), "EventName,Replied,RemoteInstanceId %d,mac," MAC_ADDR_STR, event->header.handle, MAC_ADDR_ARRAY(event->addr)); } /* Events Callback */ void nan_event_publish_terminated(NanPublishTerminatedInd *event) { sigma_dut_print(global_dut, DUT_MSG_INFO, "%s: handle %d reason %d", __func__, event->header.handle, event->reason); } /* Events Callback */ void nan_event_match(NanMatchInd *event) { sigma_dut_print(global_dut, DUT_MSG_INFO, "%s: handle %d match_handle %08x " MAC_ADDR_STR " rssi:%d", __func__, event->header.handle, event->match_handle, MAC_ADDR_ARRAY(event->addr), event->rssi_value); event_anyresponse = 1; global_header_handle = event->header.handle; global_match_handle = event->match_handle; /* memset(event_resp_buf, 0, sizeof(event_resp_buf)); */ /* global_pub_sub_handle = event->header.handle; */ /* Print the SSI */ sigma_dut_print(global_dut, DUT_MSG_INFO, "Printing SSI:"); #if 0 nanhexdump(event->service_specific_info, event->service_specific_info_len); #endif snprintf(global_event_resp_buf, sizeof(global_event_resp_buf), "EventName,DiscoveryResult,RemoteInstanceID,%d,LocalInstanceID,%d,mac," MAC_ADDR_STR " ", (event->match_handle >> 24), event->header.handle, MAC_ADDR_ARRAY(event->addr)); /* Print the match filter */ sigma_dut_print(global_dut, DUT_MSG_INFO, "Printing sdf match filter:"); /* nanhexdump(event->sdf_match_filter, event->sdf_match_filter_len); */ /* Print the conn_capability */ sigma_dut_print(global_dut, DUT_MSG_INFO, "Printing PostConnectivity Capability"); if (event->is_conn_capability_valid) { sigma_dut_print(global_dut, DUT_MSG_INFO, "Wfd supported:%s", event->conn_capability.is_wfd_supported ? "yes" : "no"); sigma_dut_print(global_dut, DUT_MSG_INFO, "Wfds supported:%s", (event->conn_capability.is_wfds_supported ? "yes" : "no")); sigma_dut_print(global_dut, DUT_MSG_INFO, "TDLS supported:%s", (event->conn_capability.is_tdls_supported ? "yes" : "no")); sigma_dut_print(global_dut, DUT_MSG_INFO, "IBSS supported:%s", (event->conn_capability.is_ibss_supported ? "yes" : "no")); sigma_dut_print(global_dut, DUT_MSG_INFO, "Mesh supported:%s", (event->conn_capability.is_mesh_supported ? "yes" : "no")); sigma_dut_print(global_dut, DUT_MSG_INFO, "Infra Field:%d", event->conn_capability.wlan_infra_field); } else { sigma_dut_print(global_dut, DUT_MSG_INFO, "PostConnectivity Capability not present"); } /* Print the discovery_attr */ sigma_dut_print(global_dut, DUT_MSG_INFO, "Printing PostDiscovery Attribute"); if (event->is_discovery_attr_valid) { sigma_dut_print(global_dut, DUT_MSG_INFO, "Conn Type:%d Device Role:%d" MAC_ADDR_STR, event->discovery_attr.type, event->discovery_attr.role, MAC_ADDR_ARRAY(event->discovery_attr.addr)); /* nanPrintFurtherAvailabilityMap(&event->discovery_attr.fam); */ sigma_dut_print(global_dut, DUT_MSG_INFO, "Printing Mesh Id:"); #if 0 nanhexdump(event->discovery_attr.mesh_id, sizeof(event->discovery_attr.mesh_id)); #endif } else { sigma_dut_print(global_dut, DUT_MSG_INFO, "PostDiscovery attribute not present"); } /* Print the fam */ if (event->is_fam_valid) { /* nanPrintFurtherAvailabilityMap(&event->fam); */ } } /* Events Callback */ void nan_event_unmatch(NanUnmatchInd *event) { sigma_dut_print(global_dut, DUT_MSG_INFO, "%s: handle %d match_handle %08x", __func__, event->header.handle, event->match_handle); } /* Events Callback */ void nan_event_subscribe_terminated(NanSubscribeTerminatedInd *event) { sigma_dut_print(global_dut, DUT_MSG_INFO, "%s: handle %d reason %d", __func__, event->header.handle, event->reason); } /* Events Callback */ void nan_event_followup(NanFollowupInd *event) { sigma_dut_print(global_dut, DUT_MSG_INFO, "%s: handle %d match_handle 0x%08x dw_or_faw %d " MAC_ADDR_STR, __func__, event->header.handle, event->match_handle, event->dw_or_faw, MAC_ADDR_ARRAY(event->addr)); global_match_handle = event->match_handle; global_header_handle = event->header.handle; #if 0 nanhexdump(event->service_specific_info, event->service_specific_info_len); #endif event_anyresponse = 1; snprintf(global_event_resp_buf, sizeof(global_event_resp_buf), "EventName,FollowUp,RemoteInstanceID,%d,LocalInstanceID,%d,mac," MAC_ADDR_STR " ", event->match_handle >> 24, event->header.handle, MAC_ADDR_ARRAY(event->addr)); } /* Events Callback */ void nan_event_disceng_event(NanDiscEngEventInd *event) { sigma_dut_print(global_dut, DUT_MSG_INFO, "%s: handle %d event_id %d", __func__, event->header.handle, event->event_id); if (event->event_id == NAN_EVENT_ID_JOINED_CLUSTER) { sigma_dut_print(global_dut, DUT_MSG_INFO, "%s: Joined cluster " MAC_ADDR_STR, __func__, MAC_ADDR_ARRAY(event->data.cluster.addr)); } if (event->event_id == NAN_EVENT_ID_STARTED_CLUSTER) { sigma_dut_print(global_dut, DUT_MSG_INFO, "%s: Started cluster " MAC_ADDR_STR, __func__, MAC_ADDR_ARRAY(event->data.cluster.addr)); } if (event->event_id == NAN_EVENT_ID_STA_MAC_ADDR) { sigma_dut_print(global_dut, DUT_MSG_INFO, "%s: Self STA " MAC_ADDR_STR, __func__, MAC_ADDR_ARRAY(event->data.mac_addr.addr)); memcpy(global_nan_mac_addr, event->data.mac_addr.addr, sizeof(global_nan_mac_addr)); } pthread_cond_signal(&gCondition); } /* Events Callback */ void nan_event_disabled(NanDisabledInd *event) { sigma_dut_print(global_dut, DUT_MSG_INFO, "%s: handle %d reason %d", __func__, event->header.handle, event->reason); /* pthread_cond_signal(&gCondition); */ } void * my_thread_function(void *ptr) { wifi_event_loop(global_handle); pthread_exit(0); return (void *) NULL; } static NanCallbackHandler callbackHandler = { .NotifyResponse = nan_notify_response, .EventPublishReplied = nan_event_publish_replied, .EventPublishTerminated = nan_event_publish_terminated, .EventMatch = nan_event_match, .EventUnMatch = nan_event_unmatch, .EventSubscribeTerminated = nan_event_subscribe_terminated, .EventFollowup = nan_event_followup, .EventDiscEngEvent = nan_event_disceng_event, .EventDisabled = nan_event_disabled, }; void nan_init(struct sigma_dut *dut) { pthread_t thread1; /* thread variables */ wifi_error err = wifi_initialize(&global_handle); if (err) { printf("wifi hal initialize failed\n"); return; } /* create threads 1 */ pthread_create(&thread1, NULL, &my_thread_function, NULL); pthread_mutex_init(&gMutex, NULL); pthread_cond_init(&gCondition, NULL); nan_register_handler(global_handle, callbackHandler); } void nan_cmd_sta_reset_default(struct sigma_dut *dut, struct sigma_conn *conn, struct sigma_cmd *cmd) { sigma_dut_print(dut, DUT_MSG_INFO, "NAN sta_reset_default"); if (nan_state == 0) { nan_init(dut); nan_state = 1; } is_fam = 0; event_anyresponse = 0; global_dut = dut; memset(global_event_resp_buf, 0, sizeof(global_event_resp_buf)); sigma_nan_disable(dut, conn, cmd); } int nan_cmd_sta_exec_action(struct sigma_dut *dut, struct sigma_conn *conn, struct sigma_cmd *cmd) { const char *program = get_param(cmd, "Prog"); const char *nan_op = get_param(cmd, "NANOp"); const char *method_type = get_param(cmd, "MethodType"); char resp_buf[100]; if (program == NULL) return -1; if (strcasecmp(program, "NAN") != 0) { send_resp(dut, conn, SIGMA_ERROR, "ErrorCode,Unsupported program"); return 0; } if (nan_op) { /* * NANOp has been specified. * We will build a nan_enable or nan_disable command. */ if (strcasecmp(nan_op, "On") == 0) { if (sigma_nan_enable(dut, conn, cmd) == 0) { snprintf(resp_buf, sizeof(resp_buf), "mac," MAC_ADDR_STR, MAC_ADDR_ARRAY(global_nan_mac_addr)); send_resp(dut, conn, SIGMA_COMPLETE, resp_buf); } else { send_resp(dut, conn, SIGMA_ERROR, "NAN_ENABLE_FAILED"); return -1; } } else if (strcasecmp(nan_op, "Off") == 0) { sigma_nan_disable(dut, conn, cmd); send_resp(dut, conn, SIGMA_COMPLETE, "NULL"); } } if (nan_state && nan_op == NULL) { if (method_type) { if (strcasecmp(method_type, "Publish") == 0) { sigma_nan_publish_request(dut, conn, cmd); send_resp(dut, conn, SIGMA_COMPLETE, "NULL"); } if (strcasecmp(method_type, "Subscribe") == 0) { sigma_nan_subscribe_request(dut, conn, cmd); send_resp(dut, conn, SIGMA_COMPLETE, "NULL"); } if (strcasecmp(method_type, "Followup") == 0) { sigma_nan_transmit_followup(dut, conn, cmd); send_resp(dut, conn, SIGMA_COMPLETE, "NULL"); } } else { sigma_nan_config_enable(dut, conn, cmd); snprintf(resp_buf, sizeof(resp_buf), "mac," MAC_ADDR_STR, MAC_ADDR_ARRAY(global_nan_mac_addr)); send_resp(dut, conn, SIGMA_COMPLETE, resp_buf); } } return 0; } int nan_cmd_sta_get_parameter(struct sigma_dut *dut, struct sigma_conn *conn, struct sigma_cmd *cmd) { const char *program = get_param(cmd, "Program"); const char *parameter = get_param(cmd, "Parameter"); char resp_buf[100]; NanStaParameter rsp; if (program == NULL) { sigma_dut_print(dut, DUT_MSG_ERROR, "Invalid Program Name"); return -1; } if (strcasecmp(program, "NAN") != 0) { send_resp(dut, conn, SIGMA_ERROR, "ErrorCode,Unsupported program"); return 0; } if (parameter == NULL) { sigma_dut_print(dut, DUT_MSG_ERROR, "Invalid Parameter"); return -1; } memset(&rsp, 0, sizeof(NanStaParameter)); nan_get_sta_parameter(0, global_handle, &rsp); sigma_dut_print(dut, DUT_MSG_INFO, "%s: NanStaparameter Master_pref:%02x, Random_factor:%02x, hop_count:%02x beacon_transmit_time:%d", __func__, rsp.master_pref, rsp.random_factor, rsp.hop_count, rsp.beacon_transmit_time); if (strcasecmp(parameter, "MasterPref") == 0) { snprintf(resp_buf, sizeof(resp_buf), "MasterPref,0x%x", rsp.master_pref); } else if (strcasecmp(parameter, "MasterRank") == 0) { snprintf(resp_buf, sizeof(resp_buf), "MasterRank,0x%lx", rsp.master_rank); } else if (strcasecmp(parameter, "RandFactor") == 0) { snprintf(resp_buf, sizeof(resp_buf), "RandFactor,0x%x", rsp.random_factor); } else if (strcasecmp(parameter, "HopCount") == 0) { snprintf(resp_buf, sizeof(resp_buf), "HopCount,0x%x", rsp.hop_count); } else if (strcasecmp(parameter, "BeaconTransTime") == 0) { snprintf(resp_buf, sizeof(resp_buf), "BeaconTransTime 0x%x", rsp.beacon_transmit_time); } else if (strcasecmp(parameter, "NANStatus") == 0) { if (nan_state == 1) snprintf(resp_buf, sizeof(resp_buf), "On"); else snprintf(resp_buf, sizeof(resp_buf), "Off"); } else { send_resp(dut, conn, SIGMA_ERROR, "Invalid Parameter"); return 0; } send_resp(dut, conn, SIGMA_COMPLETE, resp_buf); return 0; } int nan_cmd_sta_get_events(struct sigma_dut *dut, struct sigma_conn *conn, struct sigma_cmd *cmd) { const char *action = get_param(cmd, "Action"); /* Check action for start, stop and get events. */ if (strcasecmp(action, "Start") == 0) { memset(global_event_resp_buf, 0, sizeof(global_event_resp_buf)); send_resp(dut, conn, SIGMA_COMPLETE, NULL); } else if (strcasecmp(action, "Stop") == 0) { event_anyresponse = 0; memset(global_event_resp_buf, 0, sizeof(global_event_resp_buf)); send_resp(dut, conn, SIGMA_COMPLETE, NULL); } else if (strcasecmp(action, "Get") == 0) { if (event_anyresponse == 1) { send_resp(dut, conn, SIGMA_COMPLETE, global_event_resp_buf); } else { send_resp(dut, conn, SIGMA_COMPLETE, "EventList,NONE"); } } return 0; }