/** @file wifi_display.c * * * Copyright (C) 2008-2019, Marvell International Ltd. * * This software file (the "File") is distributed by Marvell International * Ltd. under the terms of the GNU General Public License Version 2, June 1991 * (the "License"). You may use, redistribute and/or modify this File in * accordance with the terms and conditions of the License, a copy of which * is available along with the File in the gpl.txt file or by writing to * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt. * * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE * ARE EXPRESSLY DISCLAIMED. The License provides additional details about * this warranty disclaimer. * */ /**************************************************************************** Change log: 22/09/11: Initial creation ****************************************************************************/ /**************************************************************************** Header files ****************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "wifi_display.h" #include "wifidirectutl.h" /* * @brief Show usage information for the wifidisplay_config command * * $return N/A */ static void print_wifidisplay_config_usage(void) { printf("\nUsage : wifidisplay_config [CONFIG_FILE]\n"); printf("\nIf CONFIG_FILE is provided, a 'set' is performed, else a 'get' is performed.\n"); printf("CONFIG_FILE contains all WiFiDisplay parameters.\n"); return; } /* ss and send ie config command * @param ie_index A pointer to the IE buffer index * @param data_len_wifidisplay Length of Wifidisplay data * @param buf Pointer to buffer to set. * @return SUCCESS--success, FAILURE--fail */ static int wifiDisplay_ie_config(t_s16 *ie_index, t_u16 data_len_wifidisplay, t_u8 *buf) { struct iwreq iwr; t_s32 sockfd; int i, ret = SUCCESS; tlvbuf_custom_ie *tlv = NULL; custom_ie *ie_ptr = NULL; tlv = (tlvbuf_custom_ie *)buf; tlv->tag = MRVL_MGMT_IE_LIST_TLV_ID; /* Locate headers */ ie_ptr = (custom_ie *)(tlv->ie_data); /* Set TLV fields : WFD IE parameters */ if (data_len_wifidisplay) { /* Set IE */ #define DISPLAY_MASK 0xFFFF ie_ptr->mgmt_subtype_mask = DISPLAY_MASK; tlv->length = sizeof(custom_ie) + data_len_wifidisplay; ie_ptr->ie_length = data_len_wifidisplay; ie_ptr->ie_index = *ie_index; } else { /* Get WPS IE */ tlv->length = 0; } /* Locate headers */ ie_ptr = (custom_ie *)((t_u8 *)(tlv->ie_data) + sizeof(custom_ie) + data_len_wifidisplay); memset(&iwr, 0, sizeof(iwr)); strncpy(iwr.ifr_name, (char *)dev_name, IFNAMSIZ); iwr.u.data.pointer = (void *)buf; iwr.u.data.length = ((2 * sizeof(custom_ie)) + sizeof(tlvbuf_custom_ie) + data_len_wifidisplay); iwr.u.data.flags = 0; /* * * create a socket * */ if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { printf("Cannot open socket.\n"); ret = FAILURE; goto _exit_; } if (ioctl(sockfd, CUSTOM_IE, &iwr)) { perror("ioctl[CUSTOM_IE]"); printf("Failed to set/get/clear the IE buffer\n"); ret = FAILURE; close(sockfd); goto _exit_; } close(sockfd); if (!data_len_wifidisplay) { /* Get the IE buffer index number for MGMT_IE_LIST_TLV */ tlv = (tlvbuf_custom_ie *)buf; *ie_index = -1; if (tlv->tag == MRVL_MGMT_IE_LIST_TLV_ID) { ie_ptr = (custom_ie *)(tlv->ie_data); for (i = 0; i < MAX_MGMT_IE_INDEX; i++) { // Index 0 and 1 are reserved for WFD in current implementation if ((ie_ptr->mgmt_subtype_mask == DISPLAY_MASK) && (ie_ptr->ie_length) && (i != 0) && (i != 1)) { *ie_index = ie_ptr->ie_index; break; } if (i < (MAX_MGMT_IE_INDEX - 1)) ie_ptr = (custom_ie *)((t_u8 *)ie_ptr + sizeof(custom_ie) + ie_ptr-> ie_length); } } if (*ie_index == -1) { printf("\nNo free IE buffer available\n"); ret = FAILURE; } } _exit_: return ret; } /** * @brief Creates a wifidisplay_config request and sends to the driver * * Usage: "Usage : wfd_config [CONFIG_FILE]" * * @param argc Number of arguments * @param argv Pointer to the arguments * @return None */ void wifidisplaycmd_config(int argc, char *argv[]) { t_u8 *buf = NULL; t_u16 ie_len_wifidisplay = 0, ie_len; t_s16 ie_index = -1; int opt, ret = SUCCESS; while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { switch (opt) { default: print_wifidisplay_config_usage(); return; } } argc -= optind; argv += optind; /* Check arguments */ if (argc < 2) { printf("ERR:wrong number of arguments.\n"); print_wifidisplay_config_usage(); return; } buf = (t_u8 *)malloc(MRVDRV_SIZE_OF_CMD_BUFFER); if (!buf) { printf("ERR:Cannot allocate memory!\n"); return; } memset(buf, 0, MRVDRV_SIZE_OF_CMD_BUFFER); if (argc >= 3) { /* Read parameters and send command to firmware */ wifidisplay_file_params_config(argv[2], argv[1], buf + sizeof(tlvbuf_custom_ie) + sizeof(custom_ie), &ie_len_wifidisplay); if (argc == 4) { ie_index = atoi(argv[3]); if (ie_index >= 4) { printf("ERR:wrong argument %s.\n", argv[3]); return; } } if (ie_len_wifidisplay > MAX_SIZE_IE_BUFFER) { printf("ERR:IE parameter size exceeds limit in %s.\n", argv[2]); free(buf); return; } ie_len = ie_len_wifidisplay + sizeof(tlvbuf_custom_ie) + sizeof(custom_ie); if (ie_len >= MRVDRV_SIZE_OF_CMD_BUFFER) { printf("ERR:Too much data in configuration file %s.\n", argv[2]); free(buf); return; } #ifdef DEBUG hexdump(buf, ie_len, ' '); #endif ret = wifiDisplay_ie_config(&ie_index, ie_len_wifidisplay, buf); if (ret != SUCCESS) { printf("ERR:Could not set wfd parameters\n"); } } } /* * @brief Read the wifidisplay parameters and sends to the driver * * @param file_name File to open for configuration parameters. * @param cmd_name Command Name for which parameters are read. * @param pbuf Pointer to output buffer * @param ie_len_wfd Length of wifidisplay parameters to return * @return SUCCESS or FAILURE */ #define DEVICE_DESCRIPTOR_LEN 24 static const t_u8 wifidisplay_oui[] = { 0x50, 0x6F, 0x9A, 0x0A }; void wifidisplay_file_params_config(char *file_name, char *cmd_name, t_u8 *pbuf, t_u16 *ie_len_wifidisplay) { FILE *config_file = NULL; char *line = NULL; t_u8 *extra = NULL, *len_ptr = NULL; t_u8 *buffer = pbuf; char **args = NULL; t_u16 cmd_len_wifidisplay = 0, tlv_len = 0; tlvbuf_wifidisplay_ie_format *display_ie_buf = NULL; int wifiDisplay_level = 0, ret = 0, coupled_sink_bitmap = 0; t_u16 display_device_info, session_mgmt_control_port, wfd_device_throuput; t_u8 assoc_bssid[] = { 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE }; t_u8 alternate_mac[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; t_u8 peer_mac[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; t_u8 default_mac[] = { 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE }; char wfd_mac[20]; int li = 0, arg_num = 0; char *pos = NULL; t_u8 cmd_found = 0; t_u16 temp; t_u16 wfd_session_len; t_u8 total_num_device_info __attribute__ ((__unused__)); /* For future use */ t_u8 curr_dev_info = 0; t_u8 dev_info_dev_add[ETH_ALEN], dev_info_assoc_bssid[ETH_ALEN], dev_info_coupled_add[ETH_ALEN]; t_u16 descriptor_display_device_info, descriptor_wfd_device_throuput; t_u8 descriptor_wfd_coupled_sink_status; t_u8 wfd_dev_descriptor_arr[120], device_info_desc_len, ind = DEVICE_DESCRIPTOR_LEN; /* Check if file exists */ config_file = fopen(file_name, "r"); if (config_file == NULL) { printf("\nERR:Config file can not open.\n"); return; } /* Memory allocations */ line = (char *)malloc(MAX_CONFIG_LINE); if (!line) { printf("ERR:Cannot allocate memory for line\n"); goto done; } memset(line, 0, MAX_CONFIG_LINE); extra = (t_u8 *)malloc(MAX_CONFIG_LINE); if (!extra) { printf("ERR:Cannot allocate memory for extra\n"); goto done; } memset(extra, 0, MAX_CONFIG_LINE); args = (char **)malloc(sizeof(char *) * MAX_ARGS_NUM); if (!args) { printf("ERR:Cannot allocate memory for args\n"); goto done; } memset(args, 0, (sizeof(char *) * MAX_ARGS_NUM)); display_ie_buf = (tlvbuf_wifidisplay_ie_format *)buffer; display_ie_buf->ElemId = VENDOR_SPECIFIC_IE_TAG; len_ptr = buffer + 1; memcpy(&display_ie_buf->Oui[0], wifidisplay_oui, sizeof(wifidisplay_oui)); cmd_len_wifidisplay += 2 + sizeof(wifidisplay_oui); while (config_get_line(line, MAX_CONFIG_LINE, config_file, &li, &pos)) { arg_num = parse_line(line, args); if (!cmd_found && (cmd_name != NULL) && strncmp(args[0], cmd_name, strlen(args[0]))) cmd_found = 1; if (strcmp(args[0], "display_dev_info") == 0) { wifiDisplay_level = DISPLAY_DEVICE_INFO; } else if (strcmp(args[0], "display_assoc_bssid") == 0) { wifiDisplay_level = DISPLAY_ASSOCIATED_BSSID; } else if (strcmp(args[0], "display_coupled_sink") == 0) { wifiDisplay_level = DISPLAY_COUPLED_SINK; } else if (strcmp(args[0], "display_session_info") == 0) { wifiDisplay_level = DISPLAY_SESSION_INFO; } else if (strcmp(args[0], "display_alternate_mac") == 0) { wifiDisplay_level = DISPLAY_ALTERNATE_MAC_ADDR; } else if (strcmp(args[0], "device_info") == 0) { if (is_wifidisplay_input_valid (WFD_DEVICE_INFO, arg_num - 1, args + 1) != SUCCESS) { goto done; } display_device_info = (t_u16)atoi(args[1]); } else if (strcmp(args[0], "mgmt_control_port") == 0) { if (is_wifidisplay_input_valid (WFD_SESSION_MGMT_CONTROL_PORT, arg_num - 1, args + 1) != SUCCESS) { goto done; } session_mgmt_control_port = (t_u16)atoi(args[1]); } else if (strcmp(args[0], "device_throuput") == 0) { if (is_wifidisplay_input_valid (WFD_DEVICE_THROUGHPUT, arg_num - 1, args + 1) != SUCCESS) { goto done; } wfd_device_throuput = (t_u16)atoi(args[1]); } else if (strcmp(args[0], "assoc_bssid") == 0) { strncpy(wfd_mac, args[1], 20); if ((ret = mac2raw(wfd_mac, assoc_bssid)) != SUCCESS) { printf("ERR: %s Address \n", ret == FAILURE ? "Invalid MAC" : ret == WIFIDIRECT_RET_MAC_BROADCAST ? "Broadcast" : "Multicast"); goto done; } } else if (strcmp(args[0], "alternate_mac") == 0) { strncpy(wfd_mac, args[1], 20); if ((ret = mac2raw(wfd_mac, alternate_mac)) != SUCCESS) { printf("ERR: %s Address \n", ret == FAILURE ? "Invalid MAC" : ret == WIFIDIRECT_RET_MAC_BROADCAST ? "Broadcast" : "Multicast"); goto done; } } else if (strcmp(args[0], "coupled_sink_bitmap") == 0) { if (is_wifidisplay_input_valid (WFD_COUPLED_SINK, arg_num - 1, args + 1) != SUCCESS) { goto done; } coupled_sink_bitmap = (t_u8)atoi(args[1]); } else if (strcmp(args[0], "session_info_len") == 0) { wfd_session_len = (t_u16)atoi(args[1]); total_num_device_info = (wfd_session_len / DEVICE_DESCRIPTOR_LEN); } else if (strncmp(args[0], "device_info_descriptor_len", 26) == 0) { device_info_desc_len = (t_u16)atoi(args[1]); } else if (strncmp(args[0], "device_info_dev_id", 18) == 0) { strncpy(wfd_mac, args[1], 20); if ((ret = mac2raw(wfd_mac, dev_info_dev_add)) != SUCCESS) { printf("ERR: %s Address \n", ret == FAILURE ? "Invalid MAC" : ret == WIFIDIRECT_RET_MAC_BROADCAST ? "Broadcast" : "Multicast"); goto done; } } else if (strncmp(args[0], "device_info_assoc_bssid", 18) == 0) { strncpy(wfd_mac, args[1], 20); if ((ret = mac2raw(wfd_mac, dev_info_assoc_bssid)) != SUCCESS) { printf("ERR: %s Address \n", ret == FAILURE ? "Invalid MAC" : ret == WIFIDIRECT_RET_MAC_BROADCAST ? "Broadcast" : "Multicast"); goto done; } } else if (strncmp(args[0], "descriptor_device_info", 22) == 0) { descriptor_display_device_info = (t_u16)atoi(args[1]); temp = htons(descriptor_display_device_info); memcpy(&descriptor_display_device_info, &temp, 2); } else if (strncmp(args[0], "descriptor_device_throuput", 24) == 0) { descriptor_wfd_device_throuput = (t_u16)atoi(args[1]); temp = htons(descriptor_wfd_device_throuput); memcpy(&descriptor_display_device_info, &temp, 2); } else if (strncmp(args[0], "descriptor_cs_bitmap", 20) == 0) { descriptor_wfd_coupled_sink_status = (t_u8)atoi(args[1]); } else if (strncmp(args[0], "device_info_coupled_address", 27) == 0) { strncpy(wfd_mac, args[1], 20); if ((ret = mac2raw(wfd_mac, dev_info_coupled_add)) != SUCCESS) { printf("ERR: %s Address \n", ret == FAILURE ? "Invalid MAC" : ret == WIFIDIRECT_RET_MAC_BROADCAST ? "Broadcast" : "Multicast"); goto done; } if (curr_dev_info > 5) { printf("ERR in device descriptor"); goto done; } memcpy(&wfd_dev_descriptor_arr[ind * curr_dev_info], &device_info_desc_len, sizeof(t_u8)); memcpy(&wfd_dev_descriptor_arr[ind * curr_dev_info + 1], &dev_info_dev_add, ETH_ALEN); memcpy(&wfd_dev_descriptor_arr[ind * curr_dev_info + 7], &dev_info_assoc_bssid, ETH_ALEN); memcpy(&wfd_dev_descriptor_arr [ind * curr_dev_info + 13], &descriptor_display_device_info, sizeof(t_u16)); memcpy(&wfd_dev_descriptor_arr [ind * curr_dev_info + 15], &descriptor_wfd_device_throuput, sizeof(t_u16)); memcpy(&wfd_dev_descriptor_arr [ind * curr_dev_info + 17], &descriptor_wfd_coupled_sink_status, sizeof(t_u8)); memcpy(&wfd_dev_descriptor_arr [ind * curr_dev_info + 18], &dev_info_coupled_add, ETH_ALEN); curr_dev_info++; } else if (strcmp(args[0], "}") == 0) { switch (wifiDisplay_level) { case DISPLAY_DEVICE_INFO: { tlvbuf_wfdisplay_device_info *tlv = NULL; /* Append a new TLV */ tlv_len = sizeof (tlvbuf_wfdisplay_device_info); tlv = (tlvbuf_wfdisplay_device_info *)(buffer + cmd_len_wifidisplay); cmd_len_wifidisplay += tlv_len; /* Set TLV fields */ tlv->tag = TLV_TYPE_WIFIDISPLAY_DEVICE_INFO; tlv->length = htons(tlv_len - (sizeof(t_u8) + sizeof(t_u16))); *ie_len_wifidisplay = cmd_len_wifidisplay; temp = htons(display_device_info); memcpy(&tlv->display_device_info, &temp, 2); temp = htons(session_mgmt_control_port); memcpy(&tlv->session_mgmt_control_port, &temp, 2); temp = htons(wfd_device_throuput); memcpy(&tlv->wfd_device_throuput, &temp, 2); wifiDisplay_level = 0; break; } case DISPLAY_ASSOCIATED_BSSID: { tlvbuf_wfdisplay_assoc_bssid *tlv = NULL; if (memcmp (default_mac, assoc_bssid, ETH_ALEN)) { /* Append a new TLV */ tlv_len = sizeof (tlvbuf_wfdisplay_assoc_bssid); tlv = (tlvbuf_wfdisplay_assoc_bssid *)(buffer + cmd_len_wifidisplay); cmd_len_wifidisplay += tlv_len; *ie_len_wifidisplay = cmd_len_wifidisplay; /* Set TLV fields */ tlv->tag = TLV_TYPE_WIFIDISPLAY_ASSOC_BSSID; tlv->length = htons(tlv_len - (sizeof(t_u8) + sizeof(t_u16))); memcpy(tlv->assoc_bssid, assoc_bssid, ETH_ALEN); wifiDisplay_level = 0; } break; } case DISPLAY_COUPLED_SINK: { tlvbuf_wfdisplay_coupled_sink *tlv = NULL; tlv_len = sizeof (tlvbuf_wfdisplay_coupled_sink); tlv = (tlvbuf_wfdisplay_coupled_sink *)(buffer + cmd_len_wifidisplay); cmd_len_wifidisplay += tlv_len; *ie_len_wifidisplay = cmd_len_wifidisplay; /* Set TLV fields */ tlv->tag = TLV_TYPE_WIFIDISPLAY_COUPLED_SINK; tlv->length = htons(tlv_len - (sizeof(t_u8) + sizeof(t_u16))); memcpy(tlv->peer_mac, peer_mac, ETH_ALEN); tlv->coupled_sink = coupled_sink_bitmap; wifiDisplay_level = 0; } break; case DISPLAY_SESSION_INFO: { tlvbuf_wifi_display_session_info *tlv = NULL; if (curr_dev_info > 0) { tlv_len = DEVICE_DESCRIPTOR_LEN * curr_dev_info + 2; tlv = (tlvbuf_wifi_display_session_info *)(buffer + cmd_len_wifidisplay); cmd_len_wifidisplay += tlv_len; *ie_len_wifidisplay = cmd_len_wifidisplay; /* Set TLV fields */ tlv->tag = TLV_TYPE_SESSION_INFO_SUBELEM; tlv->length = htons(tlv_len - (sizeof(t_u8) + sizeof(t_u16))); memcpy((t_u8 *)&tlv-> WFDDevInfoDesc, (t_u8 *) &wfd_dev_descriptor_arr, (tlv_len - 2)); wifiDisplay_level = 0; } } break; case DISPLAY_ALTERNATE_MAC_ADDR: { tlvbuf_wfdisplay_alternate_mac *tlv = NULL; if (memcmp (default_mac, alternate_mac, ETH_ALEN)) { /* Append a new TLV */ tlv_len = sizeof (tlvbuf_wfdisplay_alternate_mac); tlv = (tlvbuf_wfdisplay_alternate_mac *)(buffer + cmd_len_wifidisplay); cmd_len_wifidisplay += tlv_len; *ie_len_wifidisplay = cmd_len_wifidisplay; /* Set TLV fields */ tlv->tag = TLV_TYPE_WIFIDISPLAY_ALTERNATE_MAC; tlv->length = htons(tlv_len - (sizeof(t_u8) + sizeof(t_u16))); memcpy(tlv->alternate_mac, alternate_mac, ETH_ALEN); wifiDisplay_level = 0; } } break; default: break; } } } *len_ptr = cmd_len_wifidisplay - 2; done: fclose(config_file); if (line) free(line); if (extra) free(extra); if (args) free(args); return; } /** * @brief Show usage information for the wifidisplay_discovery commands * * $return N/A */ static void print_wifidisplay_discovery_usage(void) { printf("\nUsage : wifidisplay_discovery_request/response [CONFIG_FILE]\n"); printf("CONFIG_FILE contains WIFIDISPLAY service discovery payload.\n"); return; } /* @brief Creates a wifidirect_service_discovery request/response and * sends to the driver * * Usage: "Usage : wifidirect_discovery_request/response [CONFIG_FILE]" * * @param argc Number of arguments * @param argv Pointer to the arguments * @return SUCCESS or FAILURE **/ void wifidisplaycmd_service_discovery(int argc, char *argv[]) { wifidisplay_discovery_request *req_buf = NULL; wifidisplay_discovery_response *resp_buf = NULL; char *line = NULL; FILE *config_file = NULL; int i, opt, li = 0, arg_num = 0, ret = 0, wifidirect_level = 0; char *args[30], *pos = NULL, wifidisplay_mac[20], wifidisplay_cmd[32]; t_u8 dev_address[ETH_ALEN], cmd_found = 0; t_u8 *buffer = NULL, *buf = NULL, *tmp_buffer = NULL; t_u8 req_resp = 0; /* req = 0, resp = 1 */ t_u16 cmd_len = 0, query_len = 0, vendor_len = 0, service_len = 0; t_u16 ie_len_wifidisplay = 0; strncpy(wifidisplay_cmd, argv[2], sizeof(wifidisplay_cmd) - 1); while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { switch (opt) { default: print_wifidisplay_discovery_usage(); return; } } argc -= optind; argv += optind; /* Check arguments */ if (argc != 3) { printf("ERR:Incorrect number of arguments.\n"); print_wifidisplay_discovery_usage(); return; } /* Check if file exists */ config_file = fopen(argv[2], "r"); if (config_file == NULL) { printf("\nERR:Config file can not open.\n"); return; } line = (char *)malloc(MAX_CONFIG_LINE); if (!line) { printf("ERR:Cannot allocate memory for line\n"); goto done; } memset(line, 0, MAX_CONFIG_LINE); buf = (t_u8 *)malloc(MRVDRV_SIZE_OF_CMD_BUFFER); if (!buf) { printf("ERR:Cannot allocate memory!\n"); goto done; } if (strcmp(args[0], "wifidisplay_discovery_response") == 0) { t_u8 wfd_oui_header = 6; wifidisplay_file_params_config(argv[2], NULL, buf, &ie_len_wifidisplay); ie_len_wifidisplay += wfd_oui_header; buf += wfd_oui_header; } else { buf[0] = 0x03; buf[1] = TLV_TYPE_WIFIDISPLAY_DEVICE_INFO; buf[2] = TLV_TYPE_SESSION_INFO_SUBELEM; buf[3] = TLV_TYPE_WIFIDISPLAY_COUPLED_SINK; ie_len_wifidisplay = 4; } /* Parse file and process */ while (config_get_line(line, MAX_CONFIG_LINE, config_file, &li, &pos)) { arg_num = parse_line(line, args); if (!cmd_found && strncmp(args[0], wifidisplay_cmd, strlen(args[0]))) continue; cmd_found = 1; if (strcmp(args[0], "wifidisplay_discovery_request") == 0) { wifidirect_level = WIFIDIRECT_DISCOVERY_REQUEST_RESPONSE; /* For wifidirect_service_discovery, basic initialization here */ cmd_len = sizeof(wifidisplay_discovery_request); buffer = (t_u8 *)malloc(cmd_len); if (!buffer) { printf("ERR:Cannot allocate memory!\n"); goto done; } req_buf = (wifidisplay_discovery_request *)buffer; req_buf->cmd_code = HostCmd_CMD_WIFIDIRECT_SERVICE_DISCOVERY; req_buf->size = cmd_len; req_buf->seq_num = 0; req_buf->result = 0; } else if (strcmp(args[0], "wifidisplay_discovery_response") == 0) { wifidirect_level = WIFIDIRECT_DISCOVERY_REQUEST_RESPONSE; req_resp = 1; /* For wifidirect_service_discovery, basic initialization here */ cmd_len = sizeof(wifidisplay_discovery_response); buffer = (t_u8 *)malloc(cmd_len); if (!buffer) { printf("ERR:Cannot allocate memory!\n"); goto done; } resp_buf = (wifidisplay_discovery_response *)buffer; resp_buf->cmd_code = HostCmd_CMD_WIFIDIRECT_SERVICE_DISCOVERY; resp_buf->size = cmd_len; resp_buf->seq_num = 0; resp_buf->result = 0; } else if (strcmp(args[0], "PeerAddr") == 0) { strncpy(wifidisplay_mac, args[1], 20 - 1); if ((ret = mac2raw(wifidisplay_mac, dev_address)) != SUCCESS) { printf("ERR: %s Address \n", ret == FAILURE ? "Invalid MAC" : ret == WIFIDIRECT_RET_MAC_BROADCAST ? "Broadcast" : "Multicast"); goto done; } (!req_resp) ? memcpy(req_buf->peer_mac_addr, dev_address, ETH_ALEN) : memcpy(resp_buf-> peer_mac_addr, dev_address, ETH_ALEN); } else if (strcmp(args[0], "Category") == 0) { if (is_input_valid (WIFIDIRECT_CATEGORY, arg_num - 1, args + 1) != SUCCESS) { goto done; } (!req_resp) ? (req_buf->category = (t_u8)atoi(args[1])) : (resp_buf-> category = (t_u8) atoi(args[1])); } else if (strcmp(args[0], "Action") == 0) { if (is_input_valid (WIFIDIRECT_ACTION, arg_num - 1, args + 1) != SUCCESS) { goto done; } (!req_resp) ? (req_buf->action = (t_u8)A2HEXDECIMAL(args[1])) : (resp_buf->action = (t_u8)A2HEXDECIMAL(args[1])); } else if (strcmp(args[0], "DialogToken") == 0) { if (is_input_valid (WIFIDIRECT_DIALOGTOKEN, arg_num - 1, args + 1) != SUCCESS) { goto done; } (!req_resp) ? (req_buf->dialog_taken = (t_u8)atoi(args[1])) : (resp_buf-> dialog_taken = (t_u8) atoi(args[1])); } else if (strcmp(args[0], "StatusCode") == 0) { resp_buf->status_code = (t_u8)atoi(args[1]); } else if (strcmp(args[0], "GasComebackDelay") == 0) { if (is_input_valid (WIFIDIRECT_GAS_COMEBACK_DELAY, arg_num - 1, args + 1) != SUCCESS) { goto done; } resp_buf->gas_reply = (t_u16)A2HEXDECIMAL(args[1]); resp_buf->gas_reply = cpu_to_le16(resp_buf->gas_reply); } else if (strcmp(args[0], "AdvertizementProtocolIE") == 0) { if (is_input_valid (WIFIDIRECT_DISC_ADPROTOIE, arg_num - 1, args + 1) != SUCCESS) { goto done; } if (!req_resp) { for (i = 0; i < arg_num - 1; i++) req_buf->advertize_protocol_ie[i] = (t_u8)A2HEXDECIMAL(args[i + 1]); } else { for (i = 0; i < arg_num - 1; i++) resp_buf->advertize_protocol_ie[i] = (t_u8)A2HEXDECIMAL(args[i + 1]); } } else if (strcmp(args[0], "InfoId") == 0) { if (is_input_valid (WIFIDIRECT_DISC_INFOID, arg_num - 1, args + 1) != SUCCESS) { goto done; } if (!req_resp) { for (i = 0; i < arg_num - 1; i++) req_buf->info_id[i] = (t_u8)A2HEXDECIMAL(args[i + 1]); } else { for (i = 0; i < arg_num - 1; i++) resp_buf->info_id[i] = (t_u8)A2HEXDECIMAL(args[i + 1]); } query_len += arg_num - 1; } else if (strcmp(args[0], "OUI") == 0) { if (is_input_valid (WIFIDIRECT_OUI, arg_num - 1, args + 1) != SUCCESS) { goto done; } if (!req_resp) { for (i = 0; i < arg_num - 1; i++) req_buf->oui[i] = (t_u8)A2HEXDECIMAL(args[i + 1]); } else { for (i = 0; i < arg_num - 1; i++) resp_buf->oui[i] = (t_u8)A2HEXDECIMAL(args[i + 1]); } service_len += arg_num - 1; query_len += arg_num - 1; } else if (strcmp(args[0], "OUISubType") == 0) { if (is_input_valid (WIFIDIRECT_OUISUBTYPE, arg_num - 1, args + 1) != SUCCESS) { goto done; } (!req_resp) ? (req_buf->oui_sub_type = (t_u8)atoi(args[1])) : (resp_buf-> oui_sub_type = (t_u8) atoi(args[1])); service_len++; query_len++; } else if (strcmp(args[0], "QueryRequestLen") == 0 || strcmp(args[0], "QueryResponseLen") == 0) { wifidirect_level = WIFIDIRECT_DISCOVERY_QUERY; } else if (strcmp(args[0], "RequestLen") == 0 || strcmp(args[0], "ResponseLen") == 0) { wifidirect_level = WIFIDIRECT_DISCOVERY_SERVICE; query_len += 2; } else if (strcmp(args[0], "VendorLen") == 0) { wifidirect_level = WIFIDIRECT_DISCOVERY_VENDOR; service_len += 2; query_len += 2; } else if (strcmp(args[0], "QueryData") == 0 || strcmp(args[0], "ResponseData") == 0) { wifidirect_level = WIFIDIRECT_DISCOVERY_QUERY_RESPONSE_PER_PROTOCOL; tmp_buffer = realloc(buffer, cmd_len + ie_len_wifidisplay); if (!tmp_buffer) { printf("ERR:Cannot add DNS name to buffer!\n"); goto done; } else { buffer = tmp_buffer; tmp_buffer = NULL; } if (!req_resp) { for (i = 0; i < ie_len_wifidisplay; i++) req_buf->disc_query[i] = (t_u8)buf[i]; } else { resp_buf = (wifidisplay_discovery_response *) buffer; for (i = 0; i < ie_len_wifidisplay; i++) buffer[i + cmd_len] = (t_u8)buf[i]; } cmd_len += (ie_len_wifidisplay); vendor_len += (ie_len_wifidisplay); service_len += (ie_len_wifidisplay); query_len += (ie_len_wifidisplay); } else if (strcmp(args[0], "ServiceProtocol") == 0) { if (!req_resp) { req_buf->service_protocol = (t_u8)atoi(args[1]); /* * For uPnP, due to union allocation, a extra byte * is allocated reduce it here for uPnP */ if (req_buf->service_protocol == 2) cmd_len--; } else { resp_buf->service_protocol = (t_u8)atoi(args[1]); if (resp_buf->service_protocol == 2) cmd_len--; } vendor_len++; service_len++; query_len++; } else if (strcmp(args[0], "ServiceUpdateIndicator") == 0) { if (is_input_valid (WIFIDIRECT_SERVICEUPDATE_INDICATOR, arg_num - 1, args + 1) != SUCCESS) { goto done; } (!req_resp) ? (req_buf->service_update_indicator = cpu_to_le16((t_u16)atoi(args[1]))) : (resp_buf->service_update_indicator = cpu_to_le16((t_u16)atoi(args[1]))); service_len += 2; query_len += 2; } else if (strcmp(args[0], "ServiceTransactionId") == 0) { if (is_input_valid (WIFIDIRECT_DISC_SERVICETRANSACID, arg_num - 1, args + 1) != SUCCESS) { goto done; } (!req_resp) ? (req_buf->service_transaction_id = (t_u8)atoi(args[1])) : (resp_buf-> service_transaction_id = (t_u8) atoi(args[1])); vendor_len++; service_len++; query_len++; } else if (strcmp(args[0], "}") == 0) { switch (wifidirect_level) { case WIFIDIRECT_DISCOVERY_QUERY: (!req_resp) ? (req_buf->query_len = cpu_to_le16(query_len)) : (resp_buf->query_len = cpu_to_le16(query_len)); break; case WIFIDIRECT_DISCOVERY_SERVICE: (!req_resp) ? (req_buf->request_len = cpu_to_le16(service_len)) : (resp_buf->response_len = cpu_to_le16(service_len)); break; case WIFIDIRECT_DISCOVERY_VENDOR: (!req_resp) ? (req_buf->vendor_len = cpu_to_le16(vendor_len)) : (resp_buf->vendor_len = cpu_to_le16(vendor_len)); break; default: break; } if (wifidirect_level) { if (wifidirect_level == WIFIDIRECT_DISCOVERY_REQUEST_RESPONSE) break; wifidirect_level--; } } } /* Send collective command */ wifidirect_ioctl((t_u8 *)buffer, &cmd_len, cmd_len); done: fclose(config_file); if (buffer) free(buffer); if (line) free(line); } /** * @brief Show usage information for the wfd display status command * * $return N/A */ static void print_wifi_display_status_usage(void) { printf("\nUsage : wifi_display [STATUS]"); printf("\nOptions: STATUS : 0 - stop wfd display"); printf("\n 1 - start wfd display"); printf("\n empty - get current wfd display status\n"); return; } /** * @brief Creates wfd display start or stop request and send to driver * * Usage: "Usage : wifi_display [STATUS]" * * Options: STATUS : 0 - start wfd status * 1 - stop wfd status * * @param argc Number of arguments * @param argv Pointer to the arguments * @return N/A */ void wifidisplay_cmd_status(int argc, char *argv[]) { int opt, ret; t_u16 data = 0; t_u16 cmd_len = 0; t_u8 *buffer = NULL; wifi_display_mode_config *cmd_buf = NULL; while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { switch (opt) { default: print_wifi_display_status_usage(); return; } } argc -= optind; argv += optind; /* Check arguments */ if (argc < 2) { printf("ERR:wrong arguments.\n"); print_wifi_display_status_usage(); return; } if (argc == 3) { if ((ISDIGIT(argv[2]) == 0) || (atoi(argv[2]) < 0) || (atoi(argv[2]) > 3)) { printf("ERR:Illegal wfd mode %s. Must be in range from '0' to '3'.\n", argv[2]); print_wifi_display_status_usage(); return; } data = (t_u16)atoi(argv[2]); } /* send hostcmd now */ cmd_len = sizeof(wifi_display_mode_config); buffer = (t_u8 *)malloc(cmd_len); if (!buffer) { printf("ERR:Cannot allocate memory!\n"); return; } cmd_buf = (wifi_display_mode_config *)buffer; cmd_buf->cmd_code = HostCmd_CMD_WFD_DISPLAY_MODE_CONFIG; cmd_buf->size = cmd_len - BUF_HEADER_SIZE; cmd_buf->seq_num = 0; cmd_buf->result = 0; if (argc == 2) { cmd_buf->action = ACTION_GET; } else { cmd_buf->action = ACTION_SET; cmd_buf->mode = cpu_to_le16(data); } cmd_buf->action = cpu_to_le16(cmd_buf->action); ret = wifidirect_ioctl((t_u8 *)buffer, &cmd_len, cmd_len); if (ret != SUCCESS) { printf("Error executing wfd display_mode command\n"); free(buffer); return; } data = le16_to_cpu(cmd_buf->mode); switch (data) { case 0: printf("wfd display status = stopped\n"); break; case 1: printf("wfd display status = started\n"); break; default: printf("wfd display status = %d\n", data); break; } free(buffer); return; } /** * @brief Checkes a particular input for validatation for wifidisplay. * * @param cmd Type of input * @param argc Number of arguments * @param argv Pointer to the arguments * @return SUCCESS or FAILURE */ int is_wifidisplay_input_valid(display_valid_inputs cmd, int argc, char *argv[]) { if (argc == 0) return FAILURE; if (argc != 1) { printf("ERR:Incorrect number of arguments\n"); return FAILURE; } switch (cmd) { case WFD_DEVICE_INFO: /*Bits 10-15 are reserved for device info */ if ((ISDIGIT(argv[0]) == 0) || (atoi(argv[0]) < 0) || (atoi(argv[0]) > ((1 << 10) - 1))) { printf("ERR:Coupled sink paramater must be > 0 and < %d", ((1 << 10) - 1)); return FAILURE; } /*bits 4 and 5 values 10 and 11 are reserved */ if ((atoi(argv[0]) & 48) > 16) { printf("ERR:Coupled sink paramater must not have bit 4 and 5 equal to 10 or 11 "); return FAILURE; } break; case WFD_SESSION_MGMT_CONTROL_PORT: case WFD_DEVICE_THROUGHPUT: if ((ISDIGIT(argv[0]) == 0) || (atoi(argv[0]) < 0) || (atoi(argv[0]) > ((1 << 16) - 1))) { printf("ERR:Paramater must be > 0 and < %d", ((1 << 16) - 1)); return FAILURE; } break; case WFD_COUPLED_SINK: /*Maximum value of coupled sink is 2 */ if ((ISDIGIT(argv[0]) == 0) || (atoi(argv[0]) < 0) || (atoi(argv[0]) > 2)) { printf("ERR:Coupled sink paramater must be > 0 and < 3"); return FAILURE; } break; } return SUCCESS; } #define WFD_IE_HEADER_LEN 3 /** * @brief Wifi display update custom ie command * * $return N/A */ void wifidisplay_update_custom_ie(int argc, char *argv[]) { t_s16 display_ie_index = -1; t_u8 *buf; int opt; tlvbuf_custom_ie *tlv = NULL; custom_ie *ie_ptr = NULL; t_u16 len = 0, ie_len_wfd_org, ie_len_wfd, i = 0, new_wfd_dev_info = 0; t_u8 *wfd_ptr; while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { switch (opt) { default: printf("ERR:Incorrect arguments.\n"); return; } } argc -= optind; argv += optind; /* Check arguments */ if (argc < 2) { printf("ERR:wrong arguments.\n"); return; } if (argc == 3) { if (ISDIGIT(argv[2]) == 0) { printf("ERR:Illegal wfd mode %s. Must not be '0'.\n", argv[2]); return; } new_wfd_dev_info = (t_u16)atoi(argv[2]); } buf = (t_u8 *)malloc(MRVDRV_SIZE_OF_CMD_BUFFER); if (!buf) { printf("ERR:Cannot allocate memory!\n"); return; } wifiDisplay_ie_config(&display_ie_index, 0, buf); /* Clear WPS IE */ if (display_ie_index < 0) { free(buf); return; } if (display_ie_index < (MAX_MGMT_IE_INDEX - 1)) { tlv = (tlvbuf_custom_ie *)buf; if (tlv->tag == MRVL_MGMT_IE_LIST_TLV_ID) { ie_ptr = (custom_ie *)(tlv->ie_data); /* Goto appropriate Ie Index */ for (i = 0; i < display_ie_index; i++) { ie_ptr = (custom_ie *)((t_u8 *)ie_ptr + sizeof(custom_ie) + ie_ptr->ie_length); } ie_len_wfd_org = ie_ptr->ie_length; wfd_ptr = ie_ptr->ie_buffer; ie_len_wfd = *(wfd_ptr + 1); wfd_ptr += sizeof(t_u8) + sizeof(t_u8); wfd_ptr += (WIFIDISPLAY_OUI_LEN + WIFIDISPLAY_OUI_TYPE); while (ie_len_wfd > WFD_IE_HEADER_LEN) { memcpy(&len, wfd_ptr + 1, sizeof(t_u16)); len = ntohs(len); /* check capability type */ if (*wfd_ptr == TLV_TYPE_WIFIDISPLAY_DEVICE_INFO) { tlvbuf_wfdisplay_device_info *wfd_tlv = (tlvbuf_wfdisplay_device_info *) wfd_ptr; new_wfd_dev_info = ntohs(new_wfd_dev_info); memcpy((t_u8 *)&wfd_tlv-> display_device_info, (t_u8 *)&new_wfd_dev_info, sizeof(t_u16)); break; } wfd_ptr += len + WFD_IE_HEADER_LEN; ie_len_wfd -= len + WFD_IE_HEADER_LEN; } /* Update New IE now */ wifiDisplay_ie_config((t_s16 *)&display_ie_index, ie_len_wfd_org, (t_u8 *)ie_ptr - sizeof(tlvbuf_custom_ie)); } } return; } /** * @brief Wifi display update custom ie command * * $return N/A */ void wifidisplay_update_coupledsink_bitmap(int argc, char *argv[]) { t_s16 display_ie_index = -1; t_u8 *buf; int opt; tlvbuf_custom_ie *tlv = NULL; custom_ie *ie_ptr = NULL; t_u16 len = 0, ie_len_wfd_org, ie_len_wfd, i = 0; t_u8 new_wfd_coupled_sink_bitmap = 0; t_u8 *wfd_ptr; while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) { switch (opt) { default: printf("ERR:Incorrect arguments.\n"); return; } } argc -= optind; argv += optind; /* Check arguments */ if (argc < 2) { printf("ERR:wrong arguments.\n"); return; } if (argc == 3) { if (ISDIGIT(argv[2]) == 0) { printf("ERR:Illegal wfd mode %s. Must not be '0'.\n", argv[2]); return; } new_wfd_coupled_sink_bitmap = (t_u16)atoi(argv[2]); } buf = (t_u8 *)malloc(MRVDRV_SIZE_OF_CMD_BUFFER); if (!buf) { printf("ERR:Cannot allocate memory!\n"); return; } wifiDisplay_ie_config(&display_ie_index, 0, buf); /* Clear WPS IE */ if (display_ie_index < 0) { free(buf); return; } if (display_ie_index < (MAX_MGMT_IE_INDEX - 1)) { tlv = (tlvbuf_custom_ie *)buf; if (tlv->tag == MRVL_MGMT_IE_LIST_TLV_ID) { ie_ptr = (custom_ie *)(tlv->ie_data); /* Goto appropriate Ie Index */ for (i = 0; i < display_ie_index; i++) { ie_ptr = (custom_ie *)((t_u8 *)ie_ptr + sizeof(custom_ie) + ie_ptr->ie_length); } ie_len_wfd_org = ie_ptr->ie_length; wfd_ptr = ie_ptr->ie_buffer; ie_len_wfd = *(wfd_ptr + 1); wfd_ptr += sizeof(t_u8) + sizeof(t_u8); wfd_ptr += (WIFIDISPLAY_OUI_LEN + WIFIDISPLAY_OUI_TYPE); while (ie_len_wfd > WFD_IE_HEADER_LEN) { memcpy(&len, wfd_ptr + 1, sizeof(t_u16)); len = ntohs(len); /* check capability type */ if (*wfd_ptr == TLV_TYPE_WIFIDISPLAY_COUPLED_SINK) { tlvbuf_wfdisplay_coupled_sink *wfd_tlv = (tlvbuf_wfdisplay_coupled_sink *)wfd_ptr; wfd_tlv->coupled_sink = new_wfd_coupled_sink_bitmap; break; } wfd_ptr += len + WFD_IE_HEADER_LEN; ie_len_wfd -= len + WFD_IE_HEADER_LEN; } /* Update New IE now */ wifiDisplay_ie_config((t_s16 *)&display_ie_index, ie_len_wfd_org, (t_u8 *)ie_ptr - sizeof(tlvbuf_custom_ie)); } } free(buf); return; }