/** @file wlan_exp_node.c * @brief Experiment Framework (Node) * * This contains the code for WLAN Experiments Framework. This is both the entry point for commands processing * as well as one of the command groups. * * @copyright Copyright 2013-2019, Mango Communications. All rights reserved. * Distributed under the Mango Communications Reference Design License * See LICENSE.txt included in the design archive or * at http://mangocomm.com/802.11/license * * This file is part of the Mango 802.11 Reference Design (https://mangocomm.com/802.11) */ #include "wlan_mac_high_sw_config.h" #if WLAN_SW_CONFIG_ENABLE_WLAN_EXP // Xilinx / Standard library includes #include "xil_io.h" #include "stdlib.h" #include "stdio.h" #include "string.h" // WLAN includes #include "wlan_high_types.h" #include "wlan_mac_pkt_buf_util.h" #include "wlan_platform_common.h" #include "wlan_platform_high.h" #include "wlan_mac_event_log.h" #include "wlan_mac_entries.h" #include "wlan_mac_ltg.h" #include "wlan_mac_schedule.h" #include "wlan_mac_scan.h" #include "wlan_mac_network_info.h" #include "wlan_mac_station_info.h" #include "wlan_mac_eth_util.h" #include "wlan_mac_high.h" #include "wlan_mac_common.h" #include "wlan_mac_dl_list.h" #include "wlan_mac_queue.h" #include "wlan_platform_high.h" // WLAN Exp includes #include "wlan_exp.h" #include "wlan_exp_common.h" #include "wlan_exp_node.h" #include "wlan_exp_transport.h" #include "wlan_exp_user.h" #include "wlan_exp_ip_udp_socket.h" #include "wlan_exp_ip_udp_arp.h" // Declared in wlan_mac_high.c extern u8 low_param_rx_ant_mode; extern u8 low_param_channel; extern platform_common_dev_info_t platform_common_dev_info; extern platform_high_dev_info_t platform_high_dev_info; extern wlan_mac_hw_info_t wlan_mac_hw_info; // Local functions void _send_response(cmd_resp_hdr_t* resp_hdr, eth_tx_queue_buffer_t* eth_tx_queue_buffer, u8 fill_headers); void _prepare_response_for_send(cmd_resp_hdr_t* resp_hdr); int _process_node_cmd(cmd_resp_hdr_t* cmd_hdr, eth_tx_queue_buffer_t* eth_tx_queue_buffer); void _ltg_cleanup(u32 id, void* callback_arg); u32 _transfer_log_data( eth_tx_queue_buffer_t* first_eth_tx_queue_buffer, u32 start_index, u32 total_num_bytes ); u32 _send_list_response( eth_tx_queue_buffer_t* first_eth_tx_queue_buffer, dl_entry* start_entry, u32 num_entries, u32 offset_per_entry, u32 size_per_entry ); int _null_process_cmd_callback(u32 cmd_id, void* param); wlan_exp_node_info_t wlan_exp_node_info; static function_ptr_t wlan_exp_process_node_cmd_callback; function_ptr_t wlan_exp_purge_all_wireless_tx_queue_callback; function_ptr_t wlan_exp_process_user_cmd_callback; function_ptr_t wlan_exp_beacon_ts_update_mode_callback; function_ptr_t wlan_exp_process_config_bss_callback; function_ptr_t wlan_exp_active_network_info_getter_callback; /*****************************************************************************/ /** * @brief This initializes the node so it can communicate with a wlan_exp host. * * @return int - Status of the command: * WLAN_SUCCESS - Command completed successfully * WLAN_FAILURE - There was an error in the command * *****************************************************************************/ int wlan_exp_node_init() { int status = WLAN_SUCCESS; #if WLAN_SW_CONFIG_ENABLE_LOGGING u64 mac_timestamp; u64 system_timestamp; #endif xil_printf("------------------------\n"); xil_printf("Initializing wlan_exp v%d.%d.%d...\n", WLAN_EXP_VER_MAJOR, WLAN_EXP_VER_MINOR, WLAN_EXP_VER_REV); wlan_exp_reset_all_callbacks(); // ------------------------------------------ // Initialize Node information // Node ID / Network information must be set using dynamic node configuration process // Initial IP Address should be NODE_IP_ADDR_BASE for all nodes // wlan_exp_node_info.scheduler_interval = platform_high_dev_info.timer_dur_us; wlan_exp_node_info.node_id = 0xFFFF; wlan_exp_node_info.platform_id = wlan_mac_hw_info.platform_id; wlan_exp_node_info.platform_config = wlan_mac_hw_info.platform_config; wlan_exp_node_info.serial_number = wlan_mac_hw_info.serial_number; wlan_exp_node_info.wlan_exp_version = REQ_WLAN_EXP_HW_VER; memcpy(wlan_exp_node_info.wlan_mac_addr, wlan_mac_hw_info.hw_addr_wlan, MAC_ADDR_LEN); wlan_exp_node_info.wlan_exp_eth_mtu = wlan_platform_wlan_exp_eth_get_mtu(); #if WLAN_SW_CONFIG_ENABLE_LOGGING // ------------------------------------------ // By default, enable all subtype logging wlan_exp_log_set_entry_en_mask(ENTRY_EN_MASK_TXRX_CTRL | ENTRY_EN_MASK_TXRX_MPDU); // ------------------------------------------ // Reset the System Time ID wlan_exp_log_reset_system_time_id(); // ------------------------------------------ // Add a time info entry to the log to record the initial MAC time and system time mac_timestamp = get_mac_time_usec(); system_timestamp = get_system_time_usec(); add_time_info_entry(mac_timestamp, mac_timestamp, system_timestamp, TIME_INFO_ENTRY_TIME_RSVD_VAL_64, TIME_INFO_ENTRY_SYSTEM, 0, 0); #endif // ------------------------------------------ // Transport initialization // status = transport_init(); if (status == WLAN_FAILURE) { xil_printf(" Error in transport_init()! Exiting...\n"); return WLAN_FAILURE; } return status; } /*****************************************************************************/ /** * @brief Returns a pointer to the framework's wlan_exp_node_info_t struct * * @return wlan_exp_node_info_t* * *****************************************************************************/ wlan_exp_node_info_t* wlan_exp_get_node_info(){ return &wlan_exp_node_info; } /*****************************************************************************/ /** * @brief Adds a u32 argument to the provided response packet and updates the response * header to account for the new word. * * @param eth_tx_queue_buffer_t* eth_tx_queue_buffer - Pointer to the Ethernet queue buffer * that contains the respone * @param cmd_resp_hdr_t* resp_hdr - Pointer to the response header in the Ethernet queue * buffer's seg0 segment * @param u32 arg - argument to be added to response * @return None * *****************************************************************************/ void wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer_t* eth_tx_queue_buffer, cmd_resp_hdr_t* resp_hdr, u32 arg) { // Add the argument to the end of the response arguments array ((u32*)((u8*)resp_hdr + sizeof(cmd_resp_hdr_t)))[resp_hdr->num_u32_args] = Xil_Htonl(arg); // Update the response header to include the new argument resp_hdr->num_u32_args++; resp_hdr->length += sizeof(u32); // Update the response packet buffer length to include the new argument eth_tx_queue_buffer->seg0_len += sizeof(u32); return; } /**********************************************************************************************************************/ /** * @brief Process an Ethernet reception for wlan_exp * * This function deals with Ethernet receptions and has the following outcomes: * 1) It will enqueue the transmission of an ARP reply as a response to an ARP request * with this node's IP address * 2) It will enqueue the transmission of an ICMP (ping) reply as a response to an ICMP * echo request * 3) It will enqueue UDP packets that meet requirements of currently opened sockets * for future processing. * * The goal of this function is to be very lightweight as it may be called in an interrupt * context and we do not want to adversely affect performance of critical 802.11 functions. * Any wlan_exp UDP messages will be enqueued for later processing outside of any * interrupt contexts (regardless of whether the underlying Ethernet peripheral was polling * or interrupt-based) * * @return 1 if claiming packet, 0 otherwise. * **********************************************************************************************************************/ int wlan_exp_process_eth_rx(eth_rx_queue_buffer_t* eth_rx_queue_buffer){ eth_tx_queue_buffer_t* eth_tx_queue_buffer; dl_entry* eth_tx_queue_entry; ethernet_header_t* eth_hdr; u8 node_addr_match; u8 mcast_addr_match; u8 hw_addr[ETH_ADDR_LEN]; int rx_length = -1; eth_tx_queue_entry = queue_checkout(); // Check out space for a Tx response (if needed) if (eth_tx_queue_entry == NULL){ // We were not able to check out a queue buffer for a response, so we'll report to // the calling context that we did not want this reception so it can be freed return 0; } eth_tx_queue_buffer = (eth_tx_queue_buffer_t*)(eth_tx_queue_entry->data); // Set segment lengths to zero. If these fields are non-zero, we will use that // as an indicator that the IP/UDP library wants to send something. eth_tx_queue_buffer->seg0_len = 0; eth_tx_queue_buffer->seg1_len = 0; eth_hdr = (ethernet_header_t*)eth_rx_queue_buffer->pkt; eth_get_hw_addr(hw_addr); node_addr_match = wlan_addr_eq(eth_hdr->dest_mac_addr, hw_addr); mcast_addr_match = wlan_addr_mcast(eth_hdr->dest_mac_addr); // Process the packet based on the EtherType if (node_addr_match | mcast_addr_match) { switch (Xil_Ntohs(eth_hdr->ethertype)) { // ARP packet case ETHERTYPE_ARP: rx_length = arp_process_packet(eth_rx_queue_buffer, eth_tx_queue_buffer); break; // IP packet case ETHERTYPE_IP_V4: rx_length = ipv4_process_packet(eth_rx_queue_buffer, eth_tx_queue_buffer); break; } } if((eth_tx_queue_buffer->seg0_len + eth_tx_queue_buffer->seg1_len) > 0 ){ // If IP/UDP processing generated a response and filled in eth_tx_queue_buffer, // submit it to the transport for future processing. wlan_exp_append_tx(eth_tx_queue_entry); } else { // No response was needed. Return this queue buffer to the free pool. queue_checkin(eth_tx_queue_entry); } if (rx_length > 0){ // This Ethernet frame passed a check against open sockets, so we will claim it // and enqueue it for further processing from the wlan_exp transport. // Add the queue entry to the list of packets to be processed by wlan_exp wlan_exp_append_rx(eth_rx_queue_buffer->pyld_queue_hdr.dle); return 1; } else { return 0; // Calling context responsible for garbage collection since this frame may be consumed by // another module in the framework. } } /*****************************************************************************/ /** * @brief Set CPU_HIGH Type * * This function sets the CPU_HIGH type bits in the node_info.node_type field. * * @param application_role_t - CPU_HIGH application role * @param char* date - string of date that CPU_HIGH was compiled * @param char* time - string of time that CPU_HIWH was compiled * ******************************************************************************/ void wlan_exp_node_set_type_high(application_role_t application_role, char* date, char* time){ u32 sw_id = 0; switch(application_role){ case APPLICATION_ROLE_AP: sw_id = WLAN_EXP_HIGH_SW_ID_AP; break; case APPLICATION_ROLE_STA: sw_id = WLAN_EXP_HIGH_SW_ID_STA; break; case APPLICATION_ROLE_IBSS: sw_id = WLAN_EXP_HIGH_SW_ID_IBSS; break; case APPLICATION_ROLE_UNKNOWN: sw_id = 0; break; } strncpy(wlan_exp_node_info.high_compilation_date, date, 12); strncpy(wlan_exp_node_info.high_compilation_time, time, 9); wlan_exp_node_info.high_sw_id = sw_id; wlan_exp_node_info.high_sw_config = 0; } /*****************************************************************************/ /** * @brief Set CPU_LOW Type * * This function sets the CPU_LOW type bits in the node_info.node_type field. * The MAC High Framework will call this function after receiving an IPC message * from CPU_LOW indicating its wlan_exp type. * * @param type_low - CPU_LOW Type from wlan_exp.h * @param char* date - string of date that CPU_HIGH was compiled * @param char* time - string of time that CPU_HIWH was compiled * ******************************************************************************/ void wlan_exp_node_set_type_low(u32 sw_id, char* date, char* time){ strncpy(wlan_exp_node_info.low_compilation_date, date, 12); strncpy(wlan_exp_node_info.low_compilation_time, time, 9); wlan_exp_node_info.low_sw_id = sw_id; wlan_exp_node_info.low_sw_config = 0; } /*****************************************************************************/ /** * @brief Null Process Command Callback * * This function is part of the callback system for processing WLAN Exp commands. If * there are no additional node commands, then this will return an appropriate value. * * To processes additional node commands, please set the process_node_cmd_callback * * @param cmd_id - Command ID from node_process_cmd * @param param - Generic parameters for the callback * * @return int - Status of the command: * NO_RESP_SENT - No response has been sent * ******************************************************************************/ int _null_process_cmd_callback(u32 cmd_id, void* param){ wlan_exp_printf(WLAN_EXP_PRINT_ERROR, print_type_node, "Unknown node command: %d\n", cmd_id); return NO_RESP_SENT; }; /*****************************************************************************/ /** * @brief Node Transport Processing (Host to Node) * * This function is called by the transport to deal with any wlan_exp commands * that are addressed to this node. It must return whether or not it has sent * a response packet so the transport knows whether or not it must acknowledge * the command. * * @param wlan_exp_eth_rx_queue_buffer - Ethernet queue buffer that contains command * @param wlan_exp_eth_tx_queue_buffer - Ethernet queue buffer for response that should be filled in * * @return RESP_SENT or NO_RESP_SENT * *****************************************************************************/ int process_msg_from_host(wlan_exp_eth_rx_queue_buffer_t* wlan_exp_eth_rx_queue_buffer, eth_tx_queue_buffer_t* eth_tx_queue_buffer) { u8 cmd_group; int resp_sent = NO_RESP_SENT; cmd_resp_hdr_t* cmd_hdr = NULL; cmd_resp_hdr_t* resp_hdr = NULL; // Initialize the Command/Response pointers cmd_hdr = (cmd_resp_hdr_t*)(wlan_exp_eth_rx_queue_buffer->pkt + sizeof(ethernet_header_t) + sizeof(ipv4_header_t) + sizeof(udp_header_t) + sizeof(wlan_exp_transport_header)); resp_hdr = (cmd_resp_hdr_t*)(eth_tx_queue_buffer->seg0 + eth_tx_queue_buffer->seg0_len); // Endian swap the command header so future processing can understand it cmd_hdr->cmd = Xil_Ntohl(cmd_hdr->cmd); // Length field might be longer than what is actually in the packet // depending on the maximum packet sizes supported by the host, the node, and the Ethernet network // We will sanitize these values to the smaller of their set values or the largest // values they can be given the total length of the received Ethernet frame. cmd_hdr->length = WLAN_MIN ( Xil_Ntohs(cmd_hdr->length), wlan_exp_eth_rx_queue_buffer->length - sizeof(ethernet_header_t) - sizeof(ipv4_header_t) - sizeof(udp_header_t) - sizeof(cmd_resp_hdr_t) ); cmd_hdr->num_u32_args = Xil_Ntohs(cmd_hdr->num_u32_args); // Set up the minimum required response header needed to form an acknowledgment resp_hdr->cmd = cmd_hdr->cmd; resp_hdr->length = 0; resp_hdr->num_u32_args = 0; eth_tx_queue_buffer->seg0_len += sizeof(cmd_resp_hdr_t); // Send command to appropriate processing sub-system cmd_group = CMD_TO_GROUP(cmd_hdr->cmd); switch(cmd_group){ case GROUP_NODE: resp_sent = _process_node_cmd(cmd_hdr, eth_tx_queue_buffer); break; case GROUP_TRANSPORT: resp_sent = process_transport_cmd(cmd_hdr, eth_tx_queue_buffer); break; case GROUP_USER: resp_sent = process_user_cmd(cmd_hdr, eth_tx_queue_buffer); break; default: wlan_exp_printf(WLAN_EXP_PRINT_ERROR, print_type_node, "Unknown command group: %d\n", cmd_group); break; } // Adjust the length of the response to include the response data from the sub-system and the // response header // if(resp_sent == NO_RESP_SENT && resp_hdr) { _prepare_response_for_send(resp_hdr); } // Return the status return resp_sent; } /*****************************************************************************/ /** * @brief Node Send Early Response * * Allows a node to send a response back to the host. Calling context is responsible * for informing the transport it has sent a response so the transport can skip * sending an acknowledgment. * * @param resp_hdr - Pointer to Command / Response header for outgoing message * @param eth_tx_queue_buffer - Pointer to packet queue buffer containing message * @param fill_headers - 1 indicates that Eth/IP/UDP headers should be filled in, 0 otherwise * * @return None * * *****************************************************************************/ void _send_response(cmd_resp_hdr_t* resp_hdr, eth_tx_queue_buffer_t* eth_tx_queue_buffer, u8 fill_headers) { _prepare_response_for_send(resp_hdr); if( fill_headers) wlan_exp_transport_fill_headers_response(eth_tx_queue_buffer); wlan_exp_transport_send(eth_tx_queue_buffer); } /*****************************************************************************/ /** * @brief Prepare response header * * This function is responsible for endian swapping the contents of cmd_resp_hdr_t * in the outgoing frame before passing the frame off to the transport for * transmission. * * @param resp_hdr - Pointer to Command / Response header for outgoing message * * @return None * * *****************************************************************************/ void _prepare_response_for_send(cmd_resp_hdr_t* resp_hdr){ resp_hdr->cmd = Xil_Ntohl(resp_hdr->cmd); resp_hdr->length = Xil_Ntohs(resp_hdr->length); resp_hdr->num_u32_args = Xil_Ntohs(resp_hdr->num_u32_args); } /*****************************************************************************/ /** * @brief Process Node Commands * * Process commands from a host meant for the node group * * @param cmd_hdr - pointer to the command header * @param eth_tx_queue_buffer - pointer to a Ethernet queue buffer that should be * filled in with response arguments * * @return int - NO_RESP_SENT or RESP_SENT * *****************************************************************************/ int _process_node_cmd(cmd_resp_hdr_t* cmd_hdr, eth_tx_queue_buffer_t* eth_tx_queue_buffer) { // // IMPORTANT ENDIAN NOTES: // - command // - header - Already endian swapped by the framework (safe to access directly) // - args - Must be endian swapped as necessary by code (framework does not know the contents of the command) // - response // - header - Will be endian swapped by the framework (safe to write directly) // - args - Must be endian swapped as necessary by code (framework does not know the contents of the response) // int resp_sent = NO_RESP_SENT; cmd_resp_hdr_t* resp_hdr = NULL; u32 cmd_id = CMD_TO_CMDID(cmd_hdr->cmd); // Segment 0 length includes a fully formed command response header // because one was created with default values suitable for a responseless // acknowledgment. resp_hdr = (cmd_resp_hdr_t*)(eth_tx_queue_buffer->seg0 + eth_tx_queue_buffer->seg0_len - sizeof(cmd_resp_hdr_t)); // We explicitly zero response header fields here so commands that don't need // any u32 argument responses do not have have to touch the header // resp_hdr->cmd_id has already been set in the calling context, copied from the received command resp_hdr->length = 0; resp_hdr->num_u32_args = 0; u32* cmd_args_32 = (u32*)((u8*)cmd_hdr + sizeof(cmd_resp_hdr_t)); // Process the command switch(cmd_id){ //----------------------------------------------------------------------------- // General Commands //----------------------------------------------------------------------------- //--------------------------------------------------------------------- case CMDID_NODE_TYPE: { wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, wlan_mac_hw_info.platform_id); wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, wlan_exp_node_info.high_sw_id); wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, wlan_exp_node_info.low_sw_id); } break; //--------------------------------------------------------------------- case CMDID_NODE_INFO: { int platform_info_size; u32 resp_size; u8* dest_ptr; dest_ptr = eth_tx_queue_buffer->seg0 + eth_tx_queue_buffer->seg0_len; // First, copy the platform-independent wlan_exp_node_info struct into the response packet memcpy(dest_ptr, &wlan_exp_node_info, sizeof(wlan_exp_node_info_t)); dest_ptr += sizeof(wlan_exp_node_info_t); // Second, ask the platform to copy in its platform-specific info struct into the response packet platform_info_size = wlan_platform_high_copy_info(dest_ptr); // Finalize response resp_size = sizeof(wlan_exp_node_info_t) + platform_info_size; resp_hdr->length += resp_size; eth_tx_queue_buffer->seg0_len += resp_size; } break; //--------------------------------------------------------------------- case CMDID_NODE_IDENTIFY: { // Blink the HEX display LEDs // - cmd_args_32[0] - Platform ID // - cmd_args_32[1] - Serial Number u32 platform_id; u32 serial_number; // Get command parameters platform_id = Xil_Ntohl(cmd_args_32[0]); serial_number = Xil_Ntohl(cmd_args_32[1]); xil_printf("NODE IDENTIFY: \n"); if( ((serial_number == CMD_PARAM_NODE_IDENTIFY_ALL) || (serial_number == wlan_mac_hw_info.serial_number)) && ((platform_id == CMD_PARAM_NODE_IDENTIFY_ALL) || (platform_id == wlan_mac_hw_info.platform_id)) ){ // Print Node information xil_printf(" Node: %d\n", wlan_exp_node_info.node_id); // Send the response early so that code does not time out while waiting for blinks // The host is responsible for waiting until the LED blinking is done before issuing the // node another command. wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, CMD_PARAM_SUCCESS); if(serial_number != CMD_PARAM_NODE_IDENTIFY_ALL){ _send_response(resp_hdr, eth_tx_queue_buffer, 1); resp_sent = RESP_SENT; } wlan_platform_high_userio_disp_status(USERIO_DISP_STATUS_IDENTIFY, 0); } else { wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, CMD_PARAM_ERROR); } } break; //--------------------------------------------------------------------- case CMDID_NODE_CONFIG_SETUP: { // NODE_CONFIG_SETUP Packet Format: // - Note: All u32 parameters in cmd_args_32 are byte swapped so use Xil_Ntohl() // // - cmd_args_32[0] - Platform ID // - cmd_args_32[1] - Serial Number // - cmd_args_32[2] - Node ID // - cmd_args_32[3] - IP Address // - cmd_args_32[4] - Unicast Port // - cmd_args_32[5] - Broadcast Port // int status; u32 node_id; int unicast_port, broadcast_port; u8 ip_addr[IP_ADDR_LEN]; u32 serial_number; u32 platform_id; platform_id = Xil_Ntohl(cmd_args_32[0]); serial_number = Xil_Ntohl(cmd_args_32[1]); if( (serial_number == wlan_mac_hw_info.serial_number) && (platform_id == wlan_mac_hw_info.platform_id) ){ // Set Node ID // NOTE: We need to set the node ID in both the node info and the eth_dev_info // node_id = Xil_Ntohl(cmd_args_32[2]) & 0xFFFF; wlan_exp_node_info.node_id = node_id; // Get New IP Address ip_addr[0] = (Xil_Ntohl(cmd_args_32[3]) >> 24) & 0xFF; ip_addr[1] = (Xil_Ntohl(cmd_args_32[3]) >> 16) & 0xFF; ip_addr[2] = (Xil_Ntohl(cmd_args_32[3]) >> 8) & 0xFF; ip_addr[3] = (Xil_Ntohl(cmd_args_32[3]) ) & 0xFF; // Get new ports unicast_port = Xil_Ntohl(cmd_args_32[4]); broadcast_port = Xil_Ntohl(cmd_args_32[5]); // Set Transport IP Addresses / Ports transport_set_ip_addr(ip_addr); status = transport_config_sockets(unicast_port, broadcast_port); if(status != 0) { xil_printf("Error binding transport...\n"); } else { // Print new configuration information xil_printf("NODE_CONFIG_SETUP: Configured wlan_exp with node ID %d, ", wlan_exp_node_info.node_id); xil_printf("IP address %d.%d.%d.%d\n", ip_addr[0], ip_addr[1], ip_addr[2], ip_addr[3]); // Set right decimal point to indicate WLAN Exp network is configured wlan_platform_high_userio_disp_status(USERIO_DISP_STATUS_WLAN_EXP_CONFIGURE, 1); } } } break; //--------------------------------------------------------------------- case CMDID_NODE_CONFIG_RESET: { // NODE_CONFIG_RESET Packet Format: // - Note: All u32 parameters in cmd_args_32 are byte swapped so use Xil_Ntohl() // // - cmd_args_32[i] - Platform ID // - cmd_args_32[1] - Serial Number // // This command is always handed as non-robust - the node never sends a response packet, since the whole // purpose of this command is to reset the node's network configuration. Python only sends this command // via the (inherently non-robust) multicast transport u32 platform_id; u32 serial_number; u8 ip_addr[IP_ADDR_LEN]; platform_id = Xil_Ntohl(cmd_args_32[0]); serial_number = Xil_Ntohl(cmd_args_32[1]); if( ((serial_number == CMD_PARAM_NODE_CONFIG_RESET_ALL) || (serial_number == wlan_mac_hw_info.serial_number)) && ((platform_id == CMD_PARAM_NODE_CONFIG_RESET_ALL) || (platform_id == wlan_mac_hw_info.platform_id)) ){ // Reset node to 0xFFFF // NOTE: We need to set the node ID in both the node info and the eth_dev_info // wlan_exp_node_info.node_id = 0xFFFF; ip_addr[0] = (WLAN_EXP_DEFAULT_IP_ADDR >> 24) & 0xFF; ip_addr[1] = (WLAN_EXP_DEFAULT_IP_ADDR >> 16) & 0xFF; ip_addr[2] = (WLAN_EXP_DEFAULT_IP_ADDR >> 8) & 0xFF; ip_addr[3] = (WLAN_EXP_DEFAULT_IP_ADDR ) & 0xFF; // IP ADDR = w.x.y.z transport_set_ip_addr(ip_addr); transport_config_sockets(WLAN_EXP_DEFAULT_UDP_UNICAST_PORT, WLAN_EXP_DEFAULT_UDP_MULTICAST_PORT); transport_set_max_resp_pkt_words(WLAN_EXP_DEFAULT_MAX_PACKET_WORDS); // Print information xil_printf("NODE_CONFIG_RESET: Reset wlan_exp network config\n"); // Clear right decimal point to indicate WLAN Exp network is not configured wlan_platform_high_userio_disp_status(USERIO_DISP_STATUS_WLAN_EXP_CONFIGURE, 0); } } break; //--------------------------------------------------------------------- case CMDID_NODE_TEMPERATURE: { // NODE_TEMPERATURE // - If the system monitor exists, return the current, min and max temperature of the node // wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, wlan_platform_get_current_temp()); wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, wlan_platform_get_min_temp()); wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, wlan_platform_get_max_temp()); } break; //----------------------------------------------------------------------------- // Log Commands //----------------------------------------------------------------------------- //--------------------------------------------------------------------- case CMDID_LOG_CONFIG: { #if WLAN_SW_CONFIG_ENABLE_LOGGING // NODE_LOG_CONFIG Packet Format: // - cmd_args_32[0] - flags // [ 0] - Logging Enabled = 1; Logging Disabled = 0; // [ 1] - Wrap = 1; No Wrap = 0; // [ 2] - Full Payloads Enabled = 1; Full Payloads Disabled = 0; // [ 3] - Log WN Cmds Enabled = 1; Log WN Cmds Disabled = 0; // - cmd_args_32[1] - mask for flags // // - resp_args_32[0] - CMD_PARAM_SUCCESS // - CMD_PARAM_ERROR // int status = CMD_PARAM_SUCCESS; u8 entry_mask = wlan_exp_log_get_entry_en_mask(); u32 flags = Xil_Ntohl(cmd_args_32[0]); u32 mask = Xil_Ntohl(cmd_args_32[1]); wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_event_log, "Configure flags = 0x%08x mask = 0x%08x\n", flags, mask); // Configure the LOG based on the flag bit / mask if (mask & CMD_PARAM_LOG_CONFIG_FLAG_LOGGING) { if (flags & CMD_PARAM_LOG_CONFIG_FLAG_LOGGING) { event_log_config_logging(EVENT_LOG_LOGGING_ENABLE); } else { event_log_config_logging(EVENT_LOG_LOGGING_DISABLE); } } if (mask & CMD_PARAM_LOG_CONFIG_FLAG_WRAP) { if (flags & CMD_PARAM_LOG_CONFIG_FLAG_WRAP) { event_log_config_wrap(EVENT_LOG_WRAP_ENABLE); } else { event_log_config_wrap(EVENT_LOG_WRAP_DISABLE); } } if (mask & CMD_PARAM_LOG_CONFIG_FLAG_PAYLOADS) { if (flags & CMD_PARAM_LOG_CONFIG_FLAG_PAYLOADS) { wlan_exp_log_set_mac_payload_len(MAX_MAC_PAYLOAD_LOG_LEN); } else { wlan_exp_log_set_mac_payload_len(MIN_MAC_PAYLOAD_LOG_LEN); } } if (mask & CMD_PARAM_LOG_CONFIG_FLAG_TXRX_MPDU) { if (flags & CMD_PARAM_LOG_CONFIG_FLAG_TXRX_MPDU) { entry_mask |= ENTRY_EN_MASK_TXRX_MPDU; } else { entry_mask &= ~ENTRY_EN_MASK_TXRX_MPDU; } } if (mask & CMD_PARAM_LOG_CONFIG_FLAG_TXRX_CTRL) { if (flags & CMD_PARAM_LOG_CONFIG_FLAG_TXRX_CTRL) { entry_mask |= ENTRY_EN_MASK_TXRX_CTRL; } else { entry_mask &= ~ENTRY_EN_MASK_TXRX_CTRL; } } wlan_exp_log_set_entry_en_mask(entry_mask); // Send response of status wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, status); #endif //WLAN_SW_CONFIG_ENABLE_LOGGING } break; //--------------------------------------------------------------------- case CMDID_LOG_GET_STATUS: { #if WLAN_SW_CONFIG_ENABLE_LOGGING // NODE_LOG_GET_INFO Packet Format: // - resp_args_32[0] - Next empty entry index // - resp_args_32[1] - Oldest empty entry index // - resp_args_32[2] - Number of wraps // - resp_args_32[3] - Flags // [0] - Log enabled // [1] - Log wrapping enabled // [2] - Log full payloads enabled // [3] - Log Tx / Rx MPDU frames enabled // [4] - Log Tx / Rx CTRL frames enabled // u32 flags = event_log_get_flags(); u32 log_length = wlan_exp_log_get_mac_payload_len(); u8 entry_en_mask = wlan_exp_log_get_entry_en_mask(); if (log_length == MAX_MAC_PAYLOAD_LOG_LEN) { flags |= CMD_PARAM_LOG_CONFIG_FLAG_PAYLOADS; } if (entry_en_mask & ENTRY_EN_MASK_TXRX_MPDU) { flags |= CMD_PARAM_LOG_CONFIG_FLAG_TXRX_MPDU; } if (entry_en_mask & ENTRY_EN_MASK_TXRX_CTRL) { flags |= CMD_PARAM_LOG_CONFIG_FLAG_TXRX_CTRL; } // Set response wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, event_log_get_next_entry_index()); wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, event_log_get_oldest_entry_index()); wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, event_log_get_num_wraps()); wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, flags); #endif //WLAN_SW_CONFIG_ENABLE_LOGGING } break; //--------------------------------------------------------------------- case CMDID_LOG_GET_CAPACITY: { #if WLAN_SW_CONFIG_ENABLE_LOGGING // NODE_LOG_GET_CAPACITY Packet Format: // - resp_args_32[0] - Max log size // - resp_args_32[1] - Current log size // wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, event_log_get_capacity()); wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, event_log_get_total_size()); #endif //WLAN_SW_CONFIG_ENABLE_LOGGING } break; //--------------------------------------------------------------------- case CMDID_LOG_GET_ENTRIES: { #if WLAN_SW_CONFIG_ENABLE_LOGGING // NODE_LOG_GET_ENTRIES Packet Format: // - Note: All u32 parameters in cmd_args_32 are byte swapped so use Xil_Ntohl() // // - cmd_args_32[0] - start_address of transfer // - cmd_args_32[1] - size of transfer (in bytes) // 0xFFFF_FFFF -> Get everything in the event log // // Return Value: // - bytes_remaining - uint32 - Number of bytes remaining in the transfer // - start_byte - uint32 - Byte index of the first byte in this packet // - size - uint32 - Number of payload bytes in this packet // - byte[] - uint8[] - Array of payload bytes // // NOTE: The address passed via the command is the address relative to the current // start of the event log. It is not an absolute address and should not be treated // as such. // // When you transfer "everything" in the event log, the command will take a // snapshot of the size of the log to the "end" at the time the command is received // (ie either the next_entry_index or the end of the log before it wraps). It will then // only transfer those events. It will not any new events that are added to the log while // we are transferring the current log as well as transfer any events after a wrap. // u32 start_index = Xil_Ntohl(cmd_args_32[0]); u32 size = Xil_Ntohl(cmd_args_32[1]); u32 event_log_size = event_log_get_size(start_index); // Check if we should transfer everything or if the request was larger than the current log if ((size == CMD_PARAM_LOG_GET_ALL_ENTRIES) || (size > event_log_size)) { size = event_log_size; } // Transfer data to host resp_sent = _transfer_log_data(eth_tx_queue_buffer, start_index, size); #endif //WLAN_SW_CONFIG_ENABLE_LOGGING } break; //--------------------------------------------------------------------- case CMDID_LOG_ADD_EXP_INFO_ENTRY: { #if WLAN_SW_CONFIG_ENABLE_LOGGING // Add EXP_INFO entry to the log // // Message format: // cmd_args_32[0] info_type (lower 16 bits) // cmd_args_32[1] msg_len (255 bytes max enforced in Python) // Payload: // Arbitrary message payload, msg_len bytes exp_info_entry* exp_info; u32 entry_size; u32 info_type = Xil_Ntohl(cmd_args_32[0]); u32 msg_len = Xil_Ntohl(cmd_args_32[1]); u8* msg_ptr = (u8*)&cmd_args_32[2]; int msg_len_words; if(msg_len > 255) { xil_printf("WARNING: truncating EXP_INFO_ENTRY msg_len from %d to 255\n", msg_len); msg_len = 255; } // Compute the total entry size, required to allocate the log entry if (msg_len == 0) { entry_size = sizeof(exp_info_entry); } else { // 32-bit align msg_len; not strictly required, but helps keep // later log entries aligned to u32 boundaries for quicker DMA'ing msg_len_words = msg_len/4; if(msg_len_words*4 < msg_len) msg_len_words++; entry_size = sizeof(exp_info_entry) + msg_len_words*4; } exp_info = (exp_info_entry *)wlan_exp_log_create_entry(ENTRY_TYPE_EXP_INFO, entry_size); if (exp_info != NULL) { wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_event_log, "Adding EXP INFO entry with type %d, msg_len %d to log\n", info_type, msg_len); xil_printf("Adding EXP INFO entry with type %d, msg_len %d to log\n", info_type, msg_len); exp_info->timestamp = get_mac_time_usec(); exp_info->info_type = info_type; exp_info->msg_len = msg_len; // Copy the message to the log entry if (msg_len > 0){ // message packed immediately after the EXP_INFO header struct memcpy((void *)((u8*)&exp_info + sizeof(exp_info_entry)), (void *)msg_ptr, msg_len); } } #endif //WLAN_SW_CONFIG_ENABLE_LOGGING } break; //----------------------------------------------------------------------------- // Counts Commands //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // Local Traffic Generator (LTG) Commands //----------------------------------------------------------------------------- //--------------------------------------------------------------------- case CMDID_LTG_CONFIG: { #if WLAN_SW_CONFIG_ENABLE_LTG // NODE_LTG_START Packet Format: // - cmd_args_32[0] - Flags // [0] - Auto-start the LTG flow // - cmd_args_32[1] - Schedule type // --------- // - _ltg_sched_periodic_params_otw or _ltg_sched_uniform_rand_params_otw // - ltg_pyld_fixed_t, ltg_pyld_uniform_rand_t, ltg_pyld_all_assoc_fixed_t, or ltg_pyld_ctrl_resp_t // // - resp_args_32[0] - CMD_PARAM_SUCCESS // - CMD_PARAM_ERROR + CMD_PARAM_LTG_ERROR; // // The over-the-wire format for the schedule parameters specifies things in units of microseconds. // For architectural reasons, the framework chooses to represent these values in units of counts // of the scheduler clock. This function is responsible for converting the OTW parameters into ones // the framework can understand. typedef struct _ltg_sched_periodic_params_otw{ u32 interval_usec; u64 duration_usec; } __attribute__((__packed__)) _ltg_sched_periodic_params_otw; ASSERT_TYPE_SIZE(_ltg_sched_periodic_params_otw, 12); // Note: count variables are in units of FAST_TIMER_DUR_US typedef struct _ltg_sched_uniform_rand_params_otw{ u32 min_interval_usec; u32 max_interval_usec; u64 duration_usec; } __attribute__((__packed__)) _ltg_sched_uniform_rand_params_otw; ASSERT_TYPE_SIZE(_ltg_sched_uniform_rand_params_otw, 16); u8* ltg_payload_cmd; u8* ltg_sched_cmd; int ltg_payload_size; int ltg_sched_size; u8* ltg_payload = NULL; // Since there are only two schedules, we'll skip a round of malloc/free by reserving space for // the larger of the two schedules in the stack. u8 ltg_sched_arr[WLAN_MAX(sizeof(ltg_sched_periodic_params_t), sizeof(ltg_sched_uniform_rand_params_t))]; u8* ltg_sched = &(ltg_sched_arr[0]); u32 status = CMD_PARAM_SUCCESS; u32 id = LTG_ID_INVALID; u32 flags = Xil_Ntohl(cmd_args_32[0]); u32 schedule_type = Xil_Ntohl(cmd_args_32[1]); // Lay struct stencils on top of command payload // and check validity of parameters. ltg_sched_cmd = (u8*)(&cmd_args_32[cmd_hdr->num_u32_args]); switch(schedule_type){ case LTG_SCHED_TYPE_PERIODIC: ltg_sched_size = sizeof(_ltg_sched_periodic_params_otw); ((ltg_sched_periodic_params_t*)ltg_sched)->duration_count = \ (((_ltg_sched_periodic_params_otw*)ltg_sched_cmd)->duration_usec / platform_high_dev_info.timer_dur_us); ((ltg_sched_periodic_params_t*)ltg_sched)->interval_count = \ (((_ltg_sched_periodic_params_otw*)ltg_sched_cmd)->interval_usec / platform_high_dev_info.timer_dur_us); break; case LTG_SCHED_TYPE_UNIFORM_RAND: ltg_sched_size = sizeof(_ltg_sched_uniform_rand_params_otw); ((ltg_sched_uniform_rand_params_t*)ltg_sched)->duration_count = \ (((_ltg_sched_uniform_rand_params_otw*)ltg_sched_cmd)->duration_usec / platform_high_dev_info.timer_dur_us); ((ltg_sched_uniform_rand_params_t*)ltg_sched)->max_interval_count = \ (((_ltg_sched_uniform_rand_params_otw*)ltg_sched_cmd)->max_interval_usec / platform_high_dev_info.timer_dur_us); ((ltg_sched_uniform_rand_params_t*)ltg_sched)->min_interval_count = \ (((_ltg_sched_uniform_rand_params_otw*)ltg_sched_cmd)->min_interval_usec / platform_high_dev_info.timer_dur_us); break; default: ltg_sched_size = -1; break; } // switch(schedule_type) if(ltg_sched_size > 0){ ltg_payload_cmd = ltg_sched_cmd + ltg_sched_size; switch(((ltg_pyld_hdr_t*)ltg_payload_cmd)->type){ case LTG_PYLD_TYPE_FIXED: ltg_payload_size = sizeof(ltg_pyld_fixed_t); break; case LTG_PYLD_TYPE_UNIFORM_RAND: ltg_payload_size = sizeof(ltg_pyld_uniform_rand_t); break; case LTG_PYLD_TYPE_ALL_ASSOC_FIXED: ltg_payload_size = sizeof(ltg_pyld_all_assoc_fixed_t); break; case LTG_PYLD_TYPE_CTRL_RESP: ltg_payload_size = sizeof(ltg_pyld_ctrl_resp_t); break; default: ltg_payload_size = -1; break; } // switch(((ltg_pyld_hdr_t*)ltg_payload_cmd)->type) } // if(ltg_sched_size > 0) if((ltg_sched_size > 0) && (ltg_payload_size > 0)){ // We know we have both a valid LTG schedule and payload type, so we can continue processing. // The bytes in the command payload are transient -- after we leave this context they will be gone. // The framework will make its own copy of schedule parameters, but we need to make sure that // the payload parameters survive the duration of the LTG. So, we need to copy them into the heap. ltg_payload = wlan_mac_high_malloc(ltg_payload_size); if(ltg_payload) { memcpy(ltg_payload, ltg_payload_cmd, ltg_payload_size); // Configure the LTG id = ltg_sched_create(schedule_type, ltg_sched, ltg_payload, &_ltg_cleanup); if(id != LTG_ID_INVALID){ wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_ltg, "Configured %d\n", id); if (flags & CMD_PARAM_LTG_CONFIG_FLAG_AUTOSTART) { wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_ltg, "Starting %d\n", id); ltg_sched_start( id ); } } else { status = CMD_PARAM_ERROR + CMD_PARAM_LTG_ERROR; wlan_exp_printf(WLAN_EXP_PRINT_ERROR, print_type_ltg, "Could not create LTG\n"); wlan_mac_high_free(ltg_payload); } } else { status = CMD_PARAM_ERROR + CMD_PARAM_LTG_ERROR; wlan_exp_printf(WLAN_EXP_PRINT_ERROR, print_type_ltg, "Could not allocate memory for CMDID_LTG_CONFIG\n"); } // if((ltg_payload != NULL) && (ltg_sched != NULL)) } else { status = CMD_PARAM_ERROR + CMD_PARAM_LTG_ERROR; wlan_exp_printf(WLAN_EXP_PRINT_ERROR, print_type_ltg, "Invalid LTG schedule or payload type\n"); } // if((ltg_sched_size > 0) && (ltg_payload_size > 0)) // Send response wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, status); wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, id); #endif //WLAN_SW_CONFIG_ENABLE_LTG } break; //--------------------------------------------------------------------- case CMDID_LTG_START: { #if WLAN_SW_CONFIG_ENABLE_LTG // NODE_LTG_START Packet Format: // - cmd_args_32[0] - LTG ID // // - resp_args_32[0] - CMD_PARAM_SUCCESS // - CMD_PARAM_ERROR + CMD_PARAM_LTG_ERROR; // u32 status = CMD_PARAM_SUCCESS; u32 id = Xil_Ntohl(cmd_args_32[0]); int ltg_status = ltg_sched_start(id); if (ltg_status == 0) { if (id != CMD_PARAM_LTG_ALL_LTGS){ wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_ltg, "Starting %d\n", id); } else { wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_ltg, "Starting all LTGs\n"); } } else { if (id != CMD_PARAM_LTG_ALL_LTGS){ wlan_exp_printf(WLAN_EXP_PRINT_ERROR, print_type_ltg, "Failed to start %d\n", id); } else { wlan_exp_printf(WLAN_EXP_PRINT_ERROR, print_type_ltg, "Failed to start all LTGs\n"); } status = CMD_PARAM_ERROR + CMD_PARAM_LTG_ERROR; } // Send response of current rate wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, status); #endif } break; //--------------------------------------------------------------------- case CMDID_LTG_STOP: { #if WLAN_SW_CONFIG_ENABLE_LTG // NODE_LTG_STOP Packet Format: // - cmd_args_32[0] - LTG ID // // - resp_args_32[0] - CMD_PARAM_SUCCESS // - CMD_PARAM_ERROR + CMD_PARAM_LTG_ERROR; // u32 status = CMD_PARAM_SUCCESS; u32 id = Xil_Ntohl(cmd_args_32[0]); int ltg_status = ltg_sched_stop(id); if (ltg_status == 0) { if (id != CMD_PARAM_LTG_ALL_LTGS){ wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_ltg, "Stopping %d\n", id); } else { wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_ltg, "Stopping all LTGs\n"); } } else { if (id != CMD_PARAM_LTG_ALL_LTGS){ wlan_exp_printf(WLAN_EXP_PRINT_ERROR, print_type_ltg, "Failed to stop %d\n", id); } else { wlan_exp_printf(WLAN_EXP_PRINT_ERROR, print_type_ltg, "Failed to stop all LTGs\n"); } status = CMD_PARAM_ERROR + CMD_PARAM_LTG_ERROR; } // Send response of current rate wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, status); #endif } break; //--------------------------------------------------------------------- case CMDID_LTG_REMOVE: { #if WLAN_SW_CONFIG_ENABLE_LTG // NODE_LTG_REMOVE Packet Format: // - cmd_args_32[0] - LTG ID // // - resp_args_32[0] - CMD_PARAM_SUCCESS // - CMD_PARAM_ERROR + CMD_PARAM_LTG_ERROR; // u32 status = CMD_PARAM_SUCCESS; u32 id = Xil_Ntohl(cmd_args_32[0]); int ltg_status = ltg_sched_remove(id); if (ltg_status == 0) { if (id != CMD_PARAM_LTG_ALL_LTGS){ wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_ltg, "Removing %d\n", id); } else { wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_ltg, "Removing all LTGs\n"); } } else { if (id != CMD_PARAM_LTG_ALL_LTGS){ wlan_exp_printf(WLAN_EXP_PRINT_ERROR, print_type_ltg, "Failed to remove %d\n", id); } else { wlan_exp_printf(WLAN_EXP_PRINT_ERROR, print_type_ltg, "Failed to remove all LTGs\n"); } status = CMD_PARAM_ERROR + CMD_PARAM_LTG_ERROR; } // Send response of status wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, status); #endif //WLAN_SW_CONFIG_ENABLE_LTG } break; //--------------------------------------------------------------------- case CMDID_LTG_STATUS: { #if WLAN_SW_CONFIG_ENABLE_LTG // NODE_LTG_STATUS Packet Format: // - cmd_args_32[0] - LTG ID // // - resp_args_32[0] - CMD_PARAM_SUCCESS // - CMD_PARAM_ERROR + CMD_PARAM_LTG_ERROR; // - resp_args_32[1] - CMD_PARAM_LTG_RUNNING // - CMD_PARAM_LTG_STOPPED // - resp_args_32[3:2] - Last start timestamp // - resp_args_32[5:4] - Last stop timestamp // u32 i; u32* state; dl_entry* curr_tg_dl_entry; u32 status = CMD_PARAM_SUCCESS; u32 id = Xil_Ntohl(cmd_args_32[0]); u32 max_args = sizeof(ltg_sched_state_hdr_t) / 4; // Maximum number of return args curr_tg_dl_entry = ltg_sched_find_tg_schedule(id); if(curr_tg_dl_entry != NULL){ state = (u32 *)((tg_schedule*)(curr_tg_dl_entry->data))->state; } else { status = CMD_PARAM_ERROR + CMD_PARAM_LTG_ERROR; } // Send response of status wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, status); if(curr_tg_dl_entry != NULL){ for (i = 0; i < max_args; i++) { wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, state[i]); } } else { for (i = 0; i < max_args; i++) { wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, 0xFFFFFFFF); } } #endif //WLAN_SW_CONFIG_ENABLE_LTG } break; //----------------------------------------------------------------------------- // Node Commands //----------------------------------------------------------------------------- //--------------------------------------------------------------------- case CMDID_NODE_CHANNEL: { // - cmd_args_32[0] - Command // - cmd_args_32[1] - Channel // u32 status = CMD_PARAM_SUCCESS; u32 msg_cmd = Xil_Ntohl(cmd_args_32[0]); u32 channel = Xil_Ntohl(cmd_args_32[1]); if (msg_cmd == CMD_PARAM_WRITE_VAL) { // Set the Channel if (wlan_verify_channel(channel) == 0){ wlan_mac_high_set_radio_channel(channel); wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_node, "Set Channel = %d\n", channel); } else { status = CMD_PARAM_ERROR; wlan_exp_printf(WLAN_EXP_PRINT_ERROR, print_type_node, "Channel %d is not supported by the node.\n", channel); } } // Send response wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, status); wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, low_param_channel); } break; //--------------------------------------------------------------------- // CMDID_NODE_RESET_STATE implemented in child classes // //--------------------------------------------------------------------- case CMDID_NODE_CONFIGURE: { // CMDID_NODE_CONFIGURE Packet Format: // - cmd_args_32[0] - Flags // [0] - NODE_CONFIG_FLAG_DSSS_ENABLE // [1] - NODE_CONFIG_FLAG_ // - cmd_args_32[1] - Flag mask // - cmd_args_32[2] - WLAN Exp debug level // [31] - Set debug level // [7:0] - Debug level // u32 status = CMD_PARAM_SUCCESS; u32 flags = Xil_Ntohl(cmd_args_32[0]); u32 mask = Xil_Ntohl(cmd_args_32[1]); u32 debug_level = Xil_Ntohl(cmd_args_32[2]); wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_node, "Configure flags = 0x%08x mask = 0x%08x\n", flags, mask); // Set DSS Enable / Disable if (mask & CMD_PARAM_NODE_CONFIG_FLAG_DSSS_ENABLE) { if (flags & CMD_PARAM_NODE_CONFIG_FLAG_DSSS_ENABLE) { wlan_mac_high_set_dsss(0x1); wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_node, "Enabled DSSS\n"); } else { wlan_mac_high_set_dsss(0x0); wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_node, "Disabled DSSS\n"); } } // Set MAC time update from beacon Enable / Disable if (mask & CMD_PARAM_NODE_CONFIG_FLAG_BEACON_TIME_UPDATE) { if (flags & CMD_PARAM_NODE_CONFIG_FLAG_BEACON_TIME_UPDATE) { wlan_exp_beacon_ts_update_mode_callback(1); wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_node, "Enable MAC time update from beacons\n"); } else { wlan_exp_beacon_ts_update_mode_callback(0); wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_node, "Disabled MAC time update from beacons\n"); } } // Set debug print level if (debug_level & CMD_PARAM_NODE_CONFIG_SET_WLAN_EXP_PRINT_LEVEL) { wlan_exp_set_print_level(debug_level & 0xFF); } #if WLAN_SW_CONFIG_ENABLE_ETH_BRIDGE // Set Eth A portal behavior if (mask & CMD_PARAM_NODE_CONFIG_FLAG_ETH_PORTAL) { if (flags & CMD_PARAM_NODE_CONFIG_FLAG_ETH_PORTAL) { wlan_eth_portal_en(1); wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_node, "Enable ETH A Portal\n"); } else { wlan_eth_portal_en(0); wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_node, "Disable ETH A Portal\n"); } } #endif // Send response of status wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, status); } break; //--------------------------------------------------------------------- case CMDID_NODE_TIME: { // Set / Get node time // // Message format: // cmd_args_32[0] Command: // - Write (NODE_WRITE_VAL) // - Read (NODE_READ_VAL) // - Add to log (NODE_TIME_ADD_TO_LOG_VAL) // - Add to log on change (NODE_TIME_ADD_ON_CHANGE) // cmd_args_32[1] Time ID // cmd_args_32[2] New MAC Time in microseconds - lower 32 bits (or NODE_TIME_RSVD_VAL) // cmd_args_32[3] New MAC Time in microseconds - upper 32 bits (or NODE_TIME_RSVD_VAL) // cmd_args_32[4] Host Time in microseconds - lower 32 bits (or NODE_TIME_RSVD_VAL) // cmd_args_32[5] Host Time in microseconds - upper 32 bits (or NODE_TIME_RSVD_VAL) // // Response format: // resp_args_32[0] Status // resp_args_32[1] MAC Time on node in microseconds - lower 32 bits // resp_args_32[2] MAC Time on node in microseconds - upper 32 bits // resp_args_32[3] System Time on node in microseconds - lower 32 bits // resp_args_32[4] System Time on node in microseconds - upper 32 bits // u32 temp_lo, temp_hi; u32 status = CMD_PARAM_SUCCESS; u32 msg_cmd = Xil_Ntohl(cmd_args_32[0]); #if WLAN_SW_CONFIG_ENABLE_LOGGING u32 id = Xil_Ntohl(cmd_args_32[1]); u64 host_timestamp; #endif //WLAN_SW_CONFIG_ENABLE_LOGGING u64 new_mac_time; u64 mac_timestamp = get_mac_time_usec(); u64 system_timestamp = get_system_time_usec(); switch (msg_cmd) { case CMD_PARAM_WRITE_VAL: case CMD_PARAM_NODE_TIME_ADD_TO_LOG_VAL: // Get the new time temp_lo = Xil_Ntohl(cmd_args_32[2]); temp_hi = Xil_Ntohl(cmd_args_32[3]); new_mac_time = (((u64)temp_hi) << 32) + ((u64)temp_lo); // If this is a write, then update the time on the node if (msg_cmd == CMD_PARAM_WRITE_VAL){ set_mac_time_usec(new_mac_time); wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_node, "Set time = 0x%08x 0x%08x\n", temp_hi, temp_lo); } // Get the Host time temp_lo = Xil_Ntohl(cmd_args_32[4]); temp_hi = Xil_Ntohl(cmd_args_32[5]); wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_node, "Host time = 0x%08x 0x%08x\n", temp_hi, temp_lo); #if WLAN_SW_CONFIG_ENABLE_LOGGING host_timestamp = (((u64)temp_hi) << 32) + ((u64)temp_lo); // Add a time info log entry if (msg_cmd == CMD_PARAM_WRITE_VAL) { add_time_info_entry(mac_timestamp, new_mac_time, system_timestamp, host_timestamp, TIME_INFO_ENTRY_WLAN_EXP_SET_TIME, id, WLAN_EXP_TRUE); } else { add_time_info_entry(mac_timestamp, new_mac_time, system_timestamp, host_timestamp, TIME_INFO_ENTRY_WLAN_EXP_ADD_LOG, id, WLAN_EXP_TRUE); } #endif //WLAN_SW_CONFIG_ENABLE_LOGGING // If this was a write, then update the time value so we can return it to the host // This is done after the log entry to the fields are correct in the entry. if (msg_cmd == CMD_PARAM_WRITE_VAL){ mac_timestamp = new_mac_time; } break; case CMD_PARAM_READ_VAL: break; default: wlan_exp_printf(WLAN_EXP_PRINT_ERROR, print_type_node, "Unknown command for 0x%6x: %d\n", cmd_id, msg_cmd); status = CMD_PARAM_ERROR; break; } // Send response wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, status); // Add the MAC time to the response temp_lo = mac_timestamp & 0xFFFFFFFF; temp_hi = (mac_timestamp >> 32) & 0xFFFFFFFF; wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, temp_lo); wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, temp_hi); // Add the System time to the response temp_lo = system_timestamp & 0xFFFFFFFF; temp_hi = (system_timestamp >> 32) & 0xFFFFFFFF; wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, temp_lo); wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, temp_hi); } break; //--------------------------------------------------------------------- case CMDID_NODE_LOW_TO_HIGH_FILTER: { // Set node MAC low to high filter // // Message format: // cmd_args_32[0] Command // cmd_args_32[1] RX Filter // // Response format: // resp_args_32[0] Status // u32 status = CMD_PARAM_SUCCESS; u32 msg_cmd = Xil_Ntohl(cmd_args_32[0]); u32 filter_mode = Xil_Ntohl(cmd_args_32[1]); switch (msg_cmd) { case CMD_PARAM_WRITE_VAL: wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_node, "Set RX filter = 0x%08x\n", filter_mode); wlan_mac_high_set_rx_filter_mode(filter_mode); break; default: wlan_exp_printf(WLAN_EXP_PRINT_ERROR, print_type_node, "Unknown command for 0x%6x: %d\n", cmd_id, msg_cmd); status = CMD_PARAM_ERROR; break; } // Send response wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, status); } break; //--------------------------------------------------------------------- case CMDID_NODE_RANDOM_SEED: { // Set the random seed for the random number generator for cpu high / low // // Message format: // cmd_args_32[0] Command (only writes are supported // cmd_args_32[1] CPU High Seed Valid // cmd_args_32[2] CPU High Seed // cmd_args_32[3] CPU Low Seed Valid // cmd_args_32[4] CPU Low Seed // // Response format: // resp_args_32[0] Status // u32 seed; u32 seed_valid; u32 status = CMD_PARAM_SUCCESS; u32 msg_cmd = Xil_Ntohl(cmd_args_32[0]); switch (msg_cmd) { case CMD_PARAM_WRITE_VAL: // Process the seed for CPU high seed_valid = Xil_Ntohl(cmd_args_32[1]); seed = Xil_Ntohl(cmd_args_32[2]); if (seed_valid == CMD_PARAM_RANDOM_SEED_VALID) { wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_node, "Set CPU High random seed = 0x%08x\n", seed); srand(seed); } // Process the seed for CPU low seed_valid = Xil_Ntohl(cmd_args_32[3]); seed = Xil_Ntohl(cmd_args_32[4]); if (seed_valid == CMD_PARAM_RANDOM_SEED_VALID) { wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_node, "Set CPU Low random seed = 0x%08x\n", seed); wlan_mac_high_set_srand(seed); } break; default: wlan_exp_printf(WLAN_EXP_PRINT_ERROR, print_type_node, "Unknown command for 0x%6x: %d\n", cmd_id, msg_cmd); status = CMD_PARAM_ERROR; break; } // Send response wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, status); } break; //--------------------------------------------------------------------- case CMDID_NODE_LOW_PARAM: { // Set node MAC low to high filter // // Message format: // cmd_args_32[0] Command // cmd_args_32[1] Size in words of LOW_PARAM_MESSAGE // cmd_args_32[2] LOW_PARAM_MESSAGE // [0] PARAM_ID // [1:N] ARGS // // Response format: // resp_args_32[0] Status // u32 i; u32 id; u32 status = CMD_PARAM_SUCCESS; u32 msg_cmd = Xil_Ntohl(cmd_args_32[0]); u32 size = Xil_Ntohl(cmd_args_32[1]); // Byte swap all the payload words for the LOW_PARAM_MESSAGE for (i = 2; i < (size + 2); i++) { cmd_args_32[i] = Xil_Ntohl(cmd_args_32[i]); } id = cmd_args_32[2]; // Already byte swapped in for loop above switch (msg_cmd) { case CMD_PARAM_WRITE_VAL: wlan_mac_high_write_low_param(size, &(cmd_args_32[2])); break; case CMD_PARAM_READ_VAL: wlan_exp_printf(WLAN_EXP_PRINT_ERROR, print_type_node, "Parameter read not allowed.\n"); status = CMD_PARAM_ERROR + id; break; default: wlan_exp_printf(WLAN_EXP_PRINT_ERROR, print_type_node, "Unknown command for 0x%6x: %d\n", cmd_id, msg_cmd); status = CMD_PARAM_ERROR + id; break; } // Send default response wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, status); } break; //--------------------------------------------------------------------- case CMDID_NODE_TX_POWER: { int power; u8 mac_addr[MAC_ADDR_LEN]; u32 status = CMD_PARAM_SUCCESS; //Extract arguments u32 msg_cmd = Xil_Ntohl(cmd_args_32[0]); u32 frame_type = Xil_Ntohl(cmd_args_32[1]); u32 update_default_unicast = Xil_Ntohl(cmd_args_32[2]); u32 update_default_multicast = Xil_Ntohl(cmd_args_32[3]); u32 power_xmit = Xil_Ntohl(cmd_args_32[4]); u32 addr_sel = Xil_Ntohl(cmd_args_32[5]); int iter; dl_list* station_info_list; station_info_entry_t* station_info_entry; station_info_t* station_info; tx_params_t tx_params; // Shift power value from transmission to get the power power = power_xmit + platform_common_dev_info.tx_power_min_dbm; // Adjust the power so that it falls in an acceptable range if(power < platform_common_dev_info.tx_power_min_dbm){ power = platform_common_dev_info.tx_power_min_dbm; } if(power > platform_common_dev_info.tx_power_max_dbm){ power = platform_common_dev_info.tx_power_max_dbm; } // Process the command if( msg_cmd == CMD_PARAM_WRITE_VAL ){ if( frame_type & CMD_PARAM_TXPARAM_MASK_CTRL ){ wlan_mac_high_set_tx_ctrl_power(power); } // 1. Update default values if needed if(update_default_unicast){ if(frame_type & CMD_PARAM_TXPARAM_MASK_DATA){ tx_params = wlan_mac_get_default_tx_params(unicast_data); tx_params.phy.power = power; wlan_mac_set_default_tx_params(unicast_data, &tx_params); } if(frame_type & CMD_PARAM_TXPARAM_MASK_MGMT){ tx_params = wlan_mac_get_default_tx_params(unicast_mgmt); tx_params.phy.power = power; wlan_mac_set_default_tx_params(unicast_mgmt, &tx_params); } } if(update_default_multicast){ if(frame_type & CMD_PARAM_TXPARAM_MASK_DATA){ tx_params = wlan_mac_get_default_tx_params(mcast_data); tx_params.phy.power = power; wlan_mac_set_default_tx_params(mcast_data, &tx_params); } if(frame_type & CMD_PARAM_TXPARAM_MASK_MGMT){ tx_params = wlan_mac_get_default_tx_params(mcast_mgmt); tx_params.phy.power = power; wlan_mac_set_default_tx_params(mcast_mgmt, &tx_params); } } // 2. Update station_info_t value depending on addr_sel switch(addr_sel){ default: status = CMD_PARAM_ERROR; break; case CMD_PARAM_TXPARAM_ADDR_NONE: break; case CMD_PARAM_TXPARAM_ADDR_ALL: case CMD_PARAM_TXPARAM_ADDR_ALL_UNICAST: case CMD_PARAM_TXPARAM_ADDR_ALL_MULTICAST: station_info_list = station_info_get_list(); station_info_entry = (station_info_entry_t*)(station_info_list->first); iter = (station_info_list->length)+1; while(station_info_entry && ((iter--) > 0)){ station_info = station_info_entry->data; if( (!wlan_addr_mcast(station_info->addr) && ((addr_sel == CMD_PARAM_TXPARAM_ADDR_ALL_UNICAST) || (addr_sel == CMD_PARAM_TXPARAM_ADDR_ALL))) || (wlan_addr_mcast(station_info->addr) && ((addr_sel == CMD_PARAM_TXPARAM_ADDR_ALL_MULTICAST) || (addr_sel == CMD_PARAM_TXPARAM_ADDR_ALL))) ){ if(frame_type & CMD_PARAM_TXPARAM_MASK_DATA){ station_info->tx_params_data.phy.power = power; } if(frame_type & CMD_PARAM_TXPARAM_MASK_MGMT){ station_info->tx_params_mgmt.phy.power = power; } } station_info_entry = (station_info_entry_t*)dl_entry_next((dl_entry*)station_info_entry); } break; case CMD_PARAM_TXPARAM_ADDR_SINGLE: // Get MAC Address wlan_exp_get_mac_addr(&((u32 *)cmd_args_32)[6], &mac_addr[0]); station_info = station_info_create(&mac_addr[0]); if(station_info){ if(frame_type & CMD_PARAM_TXPARAM_MASK_DATA){ station_info->tx_params_data.phy.power = power; } if(frame_type & CMD_PARAM_TXPARAM_MASK_MGMT){ station_info->tx_params_mgmt.phy.power = power; } } break; } } else { // We do not support CMD_PARAM_READ_VAL for Tx parameters status = CMD_PARAM_ERROR; } // Send response wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, status); } break; //--------------------------------------------------------------------- case CMDID_NODE_TX_RATE: { u8 mac_addr[MAC_ADDR_LEN]; u32 status = CMD_PARAM_SUCCESS; //Extract arguments u32 msg_cmd = Xil_Ntohl(cmd_args_32[0]); u32 frame_type = Xil_Ntohl(cmd_args_32[1]); u32 update_default_unicast = Xil_Ntohl(cmd_args_32[2]); u32 update_default_multicast = Xil_Ntohl(cmd_args_32[3]); u32 mcs = Xil_Ntohl(cmd_args_32[4]) & 0xFF; u32 phy_mode = Xil_Ntohl(cmd_args_32[5]) & 0xFF; u32 addr_sel = Xil_Ntohl(cmd_args_32[6]); int iter; dl_list* station_info_list; station_info_entry_t* station_info_entry; station_info_t* station_info; tx_params_t tx_params; // Force invalid mcs / phy_mode values to sane defaults if (mcs > 7) { mcs = 7; } if ((phy_mode & (PHY_MODE_NONHT | PHY_MODE_HTMF)) == 0) { phy_mode = PHY_MODE_NONHT; } // Process the command if( msg_cmd == CMD_PARAM_WRITE_VAL ){ if( frame_type & CMD_PARAM_TXPARAM_MASK_CTRL ){ //We do not support setting the Tx antenna mode for control packets. //CPU_LOW will choose what antenna is used for Tx for these packets. status = CMD_PARAM_ERROR; } // 1. Update default values if needed if(update_default_unicast){ if(frame_type & CMD_PARAM_TXPARAM_MASK_DATA){ tx_params = wlan_mac_get_default_tx_params(unicast_data); tx_params.phy.mcs = mcs; tx_params.phy.phy_mode = phy_mode; wlan_mac_set_default_tx_params(unicast_data, &tx_params); } if(frame_type & CMD_PARAM_TXPARAM_MASK_MGMT){ tx_params = wlan_mac_get_default_tx_params(unicast_mgmt); tx_params.phy.mcs = mcs; tx_params.phy.phy_mode = phy_mode; wlan_mac_set_default_tx_params(unicast_mgmt, &tx_params); } } if(update_default_multicast){ if(frame_type & CMD_PARAM_TXPARAM_MASK_DATA){ tx_params = wlan_mac_get_default_tx_params(mcast_data); tx_params.phy.mcs = mcs; tx_params.phy.phy_mode = phy_mode; wlan_mac_set_default_tx_params(mcast_data, &tx_params); } if(frame_type & CMD_PARAM_TXPARAM_MASK_MGMT){ tx_params = wlan_mac_get_default_tx_params(mcast_mgmt); tx_params.phy.mcs = mcs; tx_params.phy.phy_mode = phy_mode; wlan_mac_set_default_tx_params(mcast_mgmt, &tx_params); } } // 2. Update station_info_t value depending on addr_sel switch(addr_sel){ default: status = CMD_PARAM_ERROR; break; case CMD_PARAM_TXPARAM_ADDR_NONE: break; case CMD_PARAM_TXPARAM_ADDR_ALL: case CMD_PARAM_TXPARAM_ADDR_ALL_UNICAST: case CMD_PARAM_TXPARAM_ADDR_ALL_MULTICAST: station_info_list = station_info_get_list(); station_info_entry = (station_info_entry_t*)(station_info_list->first); iter = (station_info_list->length)+1; while(station_info_entry && ((iter--) > 0)){ station_info = station_info_entry->data; if( (!wlan_addr_mcast(station_info->addr) && ((addr_sel == CMD_PARAM_TXPARAM_ADDR_ALL_UNICAST) || (addr_sel == CMD_PARAM_TXPARAM_ADDR_ALL))) || (wlan_addr_mcast(station_info->addr) && ((addr_sel == CMD_PARAM_TXPARAM_ADDR_ALL_MULTICAST) || (addr_sel == CMD_PARAM_TXPARAM_ADDR_ALL))) ){ if(frame_type & CMD_PARAM_TXPARAM_MASK_DATA){ station_info->tx_params_data.phy.mcs = mcs; station_info->tx_params_data.phy.phy_mode = phy_mode; } if(frame_type & CMD_PARAM_TXPARAM_MASK_MGMT){ station_info->tx_params_mgmt.phy.mcs = mcs; station_info->tx_params_mgmt.phy.phy_mode = phy_mode; } } station_info_entry = (station_info_entry_t*)dl_entry_next((dl_entry*)station_info_entry); } break; case CMD_PARAM_TXPARAM_ADDR_SINGLE: // Get MAC Address wlan_exp_get_mac_addr(&((u32 *)cmd_args_32)[7], &mac_addr[0]); station_info = station_info_create(&mac_addr[0]); if(station_info){ if(frame_type & CMD_PARAM_TXPARAM_MASK_DATA){ station_info->tx_params_data.phy.mcs = mcs; station_info->tx_params_data.phy.phy_mode = phy_mode; } if(frame_type & CMD_PARAM_TXPARAM_MASK_MGMT){ station_info->tx_params_mgmt.phy.mcs = mcs; station_info->tx_params_mgmt.phy.phy_mode = phy_mode; } } break; } } else { // We do not support CMD_PARAM_READ_VAL for Tx parameters status = CMD_PARAM_ERROR; } // Send response wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, status); } break; //--------------------------------------------------------------------- case CMDID_NODE_TX_ANT_MODE: { u8 mac_addr[MAC_ADDR_LEN]; u32 status = CMD_PARAM_SUCCESS; //Extract arguments u32 msg_cmd = Xil_Ntohl(cmd_args_32[0]); u32 frame_type = Xil_Ntohl(cmd_args_32[1]); u32 update_default_unicast = Xil_Ntohl(cmd_args_32[2]); u32 update_default_multicast = Xil_Ntohl(cmd_args_32[3]); u32 ant_mode = Xil_Ntohl(cmd_args_32[4]); u32 addr_sel = Xil_Ntohl(cmd_args_32[5]); int iter; dl_list* station_info_list; station_info_entry_t* station_info_entry; station_info_t* station_info; tx_params_t tx_params; // Need to convert antenna mode from: Python C // - TX_ANTMODE_SISO_ANTA: 0x0 to 0x10 // - TX_ANTMODE_SISO_ANTB: 0x1 to 0x20 // - TX_ANTMODE_SISO_ANTC: 0x2 to 0x30 // - TX_ANTMODE_SISO_ANTD: 0x3 to 0x40 // // Formula: y = (x + 1) << 4; // ant_mode = (ant_mode + 1) << 4; // Process the command if( msg_cmd == CMD_PARAM_WRITE_VAL ){ if( frame_type & CMD_PARAM_TXPARAM_MASK_CTRL ){ //We do not support setting the Tx antenna mode for control packets. //CPU_LOW will choose what antenna is used for Tx for these packets. status = CMD_PARAM_ERROR; } // 1. Update default values if needed if(update_default_unicast){ if(frame_type & CMD_PARAM_TXPARAM_MASK_DATA){ tx_params = wlan_mac_get_default_tx_params(unicast_data); tx_params.phy.antenna_mode = ant_mode; wlan_mac_set_default_tx_params(unicast_data, &tx_params); } if(frame_type & CMD_PARAM_TXPARAM_MASK_MGMT){ tx_params = wlan_mac_get_default_tx_params(unicast_mgmt); tx_params.phy.antenna_mode = ant_mode; wlan_mac_set_default_tx_params(unicast_mgmt, &tx_params); } } if(update_default_multicast){ if(frame_type & CMD_PARAM_TXPARAM_MASK_DATA){ tx_params = wlan_mac_get_default_tx_params(mcast_data); tx_params.phy.antenna_mode = ant_mode; wlan_mac_set_default_tx_params(mcast_data, &tx_params); } if(frame_type & CMD_PARAM_TXPARAM_MASK_MGMT){ tx_params = wlan_mac_get_default_tx_params(mcast_mgmt); tx_params.phy.antenna_mode = ant_mode; wlan_mac_set_default_tx_params(mcast_mgmt, &tx_params); } } // 2. Update station_info_t value depending on addr_sel switch(addr_sel){ default: status = CMD_PARAM_ERROR; break; case CMD_PARAM_TXPARAM_ADDR_NONE: break; case CMD_PARAM_TXPARAM_ADDR_ALL: case CMD_PARAM_TXPARAM_ADDR_ALL_UNICAST: case CMD_PARAM_TXPARAM_ADDR_ALL_MULTICAST: station_info_list = station_info_get_list(); station_info_entry = (station_info_entry_t*)(station_info_list->first); iter = (station_info_list->length)+1; while(station_info_entry && ((iter--) > 0)){ station_info = station_info_entry->data; if( (!wlan_addr_mcast(station_info->addr) && ((addr_sel == CMD_PARAM_TXPARAM_ADDR_ALL_UNICAST) || (addr_sel == CMD_PARAM_TXPARAM_ADDR_ALL))) || (wlan_addr_mcast(station_info->addr) && ((addr_sel == CMD_PARAM_TXPARAM_ADDR_ALL_MULTICAST) || (addr_sel == CMD_PARAM_TXPARAM_ADDR_ALL))) ){ if(frame_type & CMD_PARAM_TXPARAM_MASK_DATA){ station_info->tx_params_data.phy.antenna_mode = ant_mode; } if(frame_type & CMD_PARAM_TXPARAM_MASK_MGMT){ station_info->tx_params_mgmt.phy.antenna_mode = ant_mode; } } station_info_entry = (station_info_entry_t*)dl_entry_next((dl_entry*)station_info_entry); } break; case CMD_PARAM_TXPARAM_ADDR_SINGLE: // Get MAC Address wlan_exp_get_mac_addr(&((u32 *)cmd_args_32)[6], &mac_addr[0]); station_info = station_info_create(&mac_addr[0]); if(station_info){ if(frame_type & CMD_PARAM_TXPARAM_MASK_DATA){ station_info->tx_params_data.phy.antenna_mode = ant_mode; } if(frame_type & CMD_PARAM_TXPARAM_MASK_MGMT){ station_info->tx_params_mgmt.phy.antenna_mode = ant_mode; } } break; } } else { // We do not support CMD_PARAM_READ_VAL for Tx parameters status = CMD_PARAM_ERROR; } // Send response wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, status); } break; //--------------------------------------------------------------------- case CMDID_NODE_RX_ANT_MODE: { // NODE_RX_ANT_MODE Packet Format: // - cmd_args_32[0] - Command // - cmd_args_32[1] - Antenna Mode // // NOTE: This method assumes that the Antenna mode received is valid. // The checking will be done on either the host, in CPU Low or both. // u32 status = CMD_PARAM_SUCCESS; u32 msg_cmd = Xil_Ntohl(cmd_args_32[0]); u32 ant_mode = Xil_Ntohl(cmd_args_32[1]); switch (msg_cmd) { case CMD_PARAM_WRITE_VAL: wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_node, "Set RX antenna mode = %d\n", ant_mode); wlan_mac_high_set_rx_ant_mode(ant_mode); break; case CMD_PARAM_READ_VAL: ant_mode = low_param_rx_ant_mode; break; default: wlan_exp_printf(WLAN_EXP_PRINT_ERROR, print_type_node, "Unknown command for 0x%6x: %d\n", cmd_id, msg_cmd); status = CMD_PARAM_ERROR; break; } // Send response wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, status); wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, ant_mode); } break; //----------------------------------------------------------------------------- // Scan Commands //----------------------------------------------------------------------------- //--------------------------------------------------------------------- case CMDID_NODE_SCAN_PARAM: { // Set the active scan parameters // // Message format: // cmd_args_32[0] Command: // - Write (NODE_WRITE_VAL) // cmd_args_32[1] Time per channel (in microseconds) // (or CMD_PARAM_NODE_TIME_RSVD_VAL if not setting the parameter) // cmd_args_32[2] Number of probe request Tx per channel // (or CMD_PARAM_RSVD if not setting the parameter) // cmd_args_32[3] Length of channel list // (or CMD_PARAM_RSVD if not setting channel list) // cmd_args_32[4:N] Channel // cmd_args_32[N+1] Length of SSID // (or CMD_PARAM_RSVD if not setting SSID) // cmd_args_32[N+2] SSID // // Response format: // resp_args_32[0] Status // u32 i; volatile scan_parameters_t* scan_params; u32 time_per_channel; u32 num_probe_tx; u32 channel_list_len; u8* channel_list; u32 is_scanning; u32 ssid_len; char* ssid; u32 update_probe_interval = 0; u32 curr_num_probe_tx = 0; u32 status = CMD_PARAM_SUCCESS; u32 msg_cmd = Xil_Ntohl(cmd_args_32[0]); switch (msg_cmd) { case CMD_PARAM_WRITE_VAL: wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_node, "Set Scan Parameters\n"); // Check if node is currently in a scan is_scanning = wlan_mac_scan_is_scanning(); // Stop the current scan to update the scan parameters // - Because the underlying channel list can be updated, the scan is stopped // vs being paused. This will reduce any corner cases. if (is_scanning) { wlan_mac_scan_stop(); } // Get current scan parameters scan_params = wlan_mac_scan_get_parameters(); // Set the time per channel time_per_channel = Xil_Ntohl(cmd_args_32[1]); if (time_per_channel != CMD_PARAM_NODE_TIME_RSVD_VAL) { // Compute current num_probe_tx if (scan_params->probe_tx_interval_usec == 0) { curr_num_probe_tx = 0; } else { curr_num_probe_tx = scan_params->time_per_channel_usec / scan_params->probe_tx_interval_usec; } wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_node, " Time per channel = %d us\n", time_per_channel); scan_params->time_per_channel_usec = time_per_channel; update_probe_interval = 1; } // Set Probe request interval num_probe_tx = Xil_Ntohl(cmd_args_32[2]); if (num_probe_tx != CMD_PARAM_RSVD) { wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_node, " Num Probe Req = %d \n", num_probe_tx); curr_num_probe_tx = num_probe_tx; update_probe_interval = 1; } // Set the probe_tx_interval if (update_probe_interval) { if (curr_num_probe_tx == 0) { scan_params->probe_tx_interval_usec = 0; } else { scan_params->probe_tx_interval_usec = scan_params->time_per_channel_usec / curr_num_probe_tx; } wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_node, " Probe Req interval = %d us\n", scan_params->probe_tx_interval_usec); } // Set the scan channels channel_list_len = Xil_Ntohl(cmd_args_32[3]); if (channel_list_len != CMD_PARAM_RSVD){ // Free the current channel list in the scan parameters wlan_mac_high_free(scan_params->channel_vec); // Update new channel list channel_list = wlan_mac_high_malloc(channel_list_len); for (i = 0; i < channel_list_len; i++) { channel_list[i] = Xil_Ntohl(cmd_args_32[4 + i]); } // Set scan parameters scan_params->channel_vec_len = channel_list_len; scan_params->channel_vec = channel_list; // Print information about the new channels wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_node, " Channels = "); for (i = 0; i < channel_list_len; i++) { wlan_exp_printf(WLAN_EXP_PRINT_INFO, NULL, "%d ",channel_list[i]); } wlan_exp_printf(WLAN_EXP_PRINT_INFO, NULL, "\n"); } else { // No channel list to process channel_list_len = 0; } // Set the SSID ssid_len = Xil_Ntohl(cmd_args_32[4 + channel_list_len]); if (ssid_len != CMD_PARAM_RSVD){ // Get pointer to new SSID ssid = (char *) &cmd_args_32[5 + channel_list_len]; // Free the current ssid in the scan parameters wlan_mac_high_free(scan_params->ssid); // Update new ssid scan_params->ssid = strndup(ssid, SSID_LEN_MAX); // Print information about the new channels wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_node, " SSID = %s\n", scan_params->ssid); } // If the node was scanning, re-start the scan if (is_scanning) { wlan_mac_scan_start(); } break; default: wlan_exp_printf(WLAN_EXP_PRINT_ERROR, print_type_node, "Unknown command for 0x%6x: %d\n", cmd_id, msg_cmd); status = CMD_PARAM_ERROR; break; } // Send response of status wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, status); } break; //--------------------------------------------------------------------- case CMDID_NODE_SCAN: { // Enable / Disable active scan // // Scans initiated by WLAN Exp will use the current scan parameters. To // update the scan parameters use the CMDID_NODE_SCAN_PARAM command. // // Message format: // cmd_args_32[0] Enable / Disable scan // - CMD_PARAM_NODE_SCAN_ENABLE - Enable scan // - CMD_PARAM_NODE_SCAN_DISABLE - Disable scan // - CMD_PARAM_RSVD - Do nothing // // Response format: // resp_args_32[0] Status // resp_args_32[1] Is Scanning? // u32 status = CMD_PARAM_SUCCESS; u32 enable = Xil_Ntohl(cmd_args_32[0]); network_info_t* active_network_info = ((network_info_t*)wlan_exp_active_network_info_getter_callback()); switch (enable) { case CMD_PARAM_NODE_SCAN_ENABLE: // Enable scan if (active_network_info == NULL) { wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_node, "Scan enabled.\n"); wlan_mac_scan_start(); } else { // "my_bss_info" must be NULL to start a scan // - This will avoid any corner cases with scanning status = CMD_PARAM_ERROR; } break; case CMD_PARAM_NODE_SCAN_DISABLE: // Disable scan wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_node, "Scan disabled.\n"); wlan_mac_scan_stop(); break; } // Send response of status wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, status); wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, wlan_mac_scan_is_scanning()); } break; //----------------------------------------------------------------------------- // Association Commands //----------------------------------------------------------------------------- //--------------------------------------------------------------------- case CMDID_NODE_CONFIG_BSS: { // Configure the BSS // // Message format: // < no u32 arguments > // ------ // _wlan_exp_bss_config_update_t // // Response format: // resp_args_32[0] - Status // typedef struct __attribute__((__packed__)){ u32 update_mask; bss_config_t bss_config; } _wlan_exp_bss_config_update_t; ASSERT_TYPE_SIZE(_wlan_exp_bss_config_update_t, 52); u32 status = CMD_PARAM_SUCCESS; // CONFIG_BSS message has raw bss_config_update struct immediately after command arguments // Current CONFIG_BSS command always has zero arguments _wlan_exp_bss_config_update_t* wlan_exp_bss_config_update; if(cmd_hdr->num_u32_args == 0) { wlan_exp_bss_config_update = (_wlan_exp_bss_config_update_t*)(&cmd_args_32[cmd_hdr->num_u32_args]); // Each MAC implementation is responsible for the implementation of this command. status = wlan_exp_process_config_bss_callback(&(wlan_exp_bss_config_update->bss_config), wlan_exp_bss_config_update->update_mask); } else { xil_printf("ERROR: CMDID_NODE_CONFIG_BSS received with nonzero (%d) command args - leaving BSS config unchanged\n", cmd_hdr->num_u32_args); status = CMD_PARAM_ERROR; } // If there was an error, add CMD_PARAM_ERROR bits on return value if (status != CMD_PARAM_SUCCESS) { status |= CMD_PARAM_ERROR; } // Send response wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, status); } break; //--------------------------------------------------------------------- // Case NODE_DISASSOCIATE is implemented in the child classes //--------------------------------------------------------------------- case CMDID_NODE_GET_BSS_MEMBERS: { // NODE_GET_STATION_INFO Packet Format: // - cmd_args_32[0] - start_address of transfer //TODO: Unusued and should be removed from OTW format // - cmd_args_32[1] - size of transfer (in bytes) //TODO: Unusued and should be removed from OTW format // - cmd_args_32[2:3] - MAC Address (All 0x00 means all entries) // // Always returns a valid WLAN Exp Buffer (either 1 or more packets) // - bytes_remaining - uint32 - Number of bytes remaining in the transfer // - start_byte - uint32 - Byte index of the first byte in this packet // - size - uint32 - Number of payload bytes in this packet // - byte[] - uint8[] - Array of payload bytes // u8 mac_addr[MAC_ADDR_LEN]; // If unchanged, (start_entry == NULL, num_entries = 0) // will result in a transport-level response that serves as an // acknowledgment. dl_entry* start_entry = NULL; u32 num_entries = 0; dl_list* member_list = NULL; // Convert the u32-packed MAC address into a 6-byte array wlan_exp_get_mac_addr(&(cmd_args_32)[2], mac_addr); // These lists are highly mutable and typically small. For these reasons, // we disable interrupts while retrieving them and sending them as responses. interrupt_state_t curr_interrupt_state = wlan_platform_intc_stop(); member_list = get_network_member_list(); if (wlan_addr_eq(mac_addr, zero_addr)) { // Retrieve all entries if(member_list){ start_entry = (member_list)->first; num_entries = (member_list)->length; } } else { // Retrieve one entry if(member_list){ start_entry = (dl_entry*)station_info_find_by_addr(mac_addr, member_list); if(start_entry) num_entries = 1; } } if(start_entry){ resp_sent = _send_list_response( eth_tx_queue_buffer, start_entry, num_entries, 0, sizeof(station_info_t) - sizeof(rate_selection_info_t) ); } wlan_platform_intc_set_state(curr_interrupt_state); } break; //--------------------------------------------------------------------- case CMDID_NODE_GET_STATION_INFO_LIST: { // NODE_GET_STATION_INFO Packet Format: // - cmd_args_32[0] - start_address of transfer //TODO: Unusued and should be removed from OTW format // - cmd_args_32[1] - size of transfer (in bytes) //TODO: Unusued and should be removed from OTW format // - cmd_args_32[2:3] - MAC Address (All 0xFF means all entries) // // Always returns a valid WLAN Exp Buffer (either 1 or more packets) // - bytes_remaining - uint32 - Number of bytes remaining in the transfer // - start_byte - uint32 - Byte index of the first byte in this packet // - size - uint32 - Number of payload bytes in this packet // - byte[] - uint8[] - Array of payload bytes // u8 mac_addr[MAC_ADDR_LEN]; // If unchanged, (start_entry == NULL, num_entries = 0) // will result in a transport-level response that serves as an // acknowledgment. dl_entry* start_entry = NULL; u32 num_entries = 0; // Convert the u32-packed MAC address into a 6-byte array wlan_exp_get_mac_addr(&(cmd_args_32)[2], mac_addr); // These lists are highly mutable and typically small. For these reasons, // we disable interrupts while retrieving them and sending them as responses. interrupt_state_t curr_interrupt_state = wlan_platform_intc_stop(); if (wlan_addr_eq(mac_addr, zero_addr)) { // Retrieve all entries start_entry = station_info_get_list()->first; num_entries = station_info_get_list()->length; } else { // Retrieve one entry start_entry = (dl_entry*)station_info_find_by_addr(mac_addr, NULL); if(start_entry) num_entries = 1; } if(start_entry){ resp_sent = _send_list_response( eth_tx_queue_buffer, start_entry, num_entries, 0, sizeof(station_info_t) - sizeof(rate_selection_info_t) ); } wlan_platform_intc_set_state(curr_interrupt_state); } break; //--------------------------------------------------------------------- case CMDID_NODE_GET_NETWORK_INFO: { // NODE_GET_NETWORK_INFO Packet Format: // - cmd_args_32[0] - start_address of transfer // - cmd_args_32[1] - size of transfer (in bytes) // - cmd_args_32[2:3] - MAC Address (All 0x00 means all entries) // // Always returns a valid WLAN Exp Buffer (either 1 or more packets) // - bytes_remaining - uint32 - Number of bytes remaining in the transfer // - start_byte - uint32 - Byte index of the first byte in this packet // - size - uint32 - Number of payload bytes in this packet // - byte[] - uint8[] - Array of payload bytes // u8 mac_addr[MAC_ADDR_LEN]; // If unchanged, (start_entry == NULL, num_entries = 0) // will result in a transport-level response that serves as an // acknowledgment. dl_entry* start_entry = NULL; u32 num_entries = 0; // Convert the u32-packed MAC address into a 6-byte array wlan_exp_get_mac_addr(&(cmd_args_32)[2], mac_addr); // These lists are highly mutable and typically small. For these reasons, // we disable interrupts while retrieving them and sending them as responses. interrupt_state_t curr_interrupt_state = wlan_platform_intc_stop(); // There are a few different retrieval conditions determined by the MAC address argument // in this command: // 1) If the MAC Address is zero (00-00-00-00-00-00), we should retrieve the entire list // of known network_info_t and return them as response packets. // 2) If the MAC Address is broadcast (FF-FF-FF-FF-FF-FF) and // a) the node currently has an active network, then the network_info_t that describes // it should be returned as a response. // b) the node currently has no active network, then a blank network_info_t should be // returned as a response. // 3) If the MAC address is any other address, we should search for that address within // the list of known network_info_t. If it is found, we will return those network // details as a response. If not, we will either return a zeroed network_info_t or // blank transport-level response depending on the CMD_PARAM_COUNTS_RETURN_ZEROED_IF_NONE // flag in the command arguments. if (wlan_addr_eq(mac_addr, zero_addr)) { // For this command, and only this command, zero-valued MAC // retrieve the active network info. // Retrieve all entries start_entry = wlan_mac_high_get_network_info_list()->first; num_entries = wlan_mac_high_get_network_info_list()->length; } else if (wlan_addr_eq(mac_addr, bcast_addr)){ network_info_t* active_network_info = ((network_info_t*)wlan_exp_active_network_info_getter_callback()); if(active_network_info){ start_entry = (dl_entry*)wlan_mac_high_find_network_info_BSSID(active_network_info->bss_config.bssid); if(start_entry) num_entries = 1; } } else { start_entry = (dl_entry*)wlan_mac_high_find_network_info_BSSID(mac_addr); if(start_entry) num_entries = 1; } if(start_entry){ resp_sent = _send_list_response( eth_tx_queue_buffer, start_entry, num_entries, 0, sizeof(network_info_t) - sizeof(dl_list) ); } wlan_platform_intc_set_state(curr_interrupt_state); } break; //----------------------------------------------------------------------------- // Queue Commands //----------------------------------------------------------------------------- //--------------------------------------------------------------------- case CMDID_QUEUE_PURGE_ALL_WIRELESS_TX: { interrupt_state_t curr_interrupt_state = wlan_platform_intc_stop(); wlan_exp_purge_all_wireless_tx_queue_callback(); wlan_platform_intc_set_state(curr_interrupt_state); } break; //----------------------------------------------------------------------------- // Memory Access Commands - For developer use only //----------------------------------------------------------------------------- //--------------------------------------------------------------------- case CMDID_DEV_MEM_HIGH: { // FIXME: this definitely needs testing // Read/write memory in CPU High // // Write Message format: // cmd_args_32[0] Command == CMD_PARAM_WRITE_VAL // cmd_args_32[1] Address // cmd_args_32[2] Length (number of u32 words to write) // cmd_args_32[3:] Values to write (integral number of u32 words) // Response format: // resp_args_32[0] Status // // Read Message format: // cmd_args_32[0] Command == CMD_PARAM_READ_VAL // cmd_args_32[1] Address // cmd_args_32[2] Length (number of u32 words to read) // Response format: // resp_args_32[0] Status // resp_args_32[1] Length (number of u32 values) // resp_args_32[2:] Memory values (length u32 values) // u32 mem_idx; u32 status = CMD_PARAM_SUCCESS; u32 msg_cmd = Xil_Ntohl(cmd_args_32[0]); u32 mem_addr = Xil_Ntohl(cmd_args_32[1]); u32 num_words = Xil_Ntohl(cmd_args_32[2]); u32 use_default_resp = WLAN_EXP_TRUE; u32 max_resp_len = wlan_exp_transport_get_max_pkt_words(); switch (msg_cmd) { case CMD_PARAM_WRITE_VAL: wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_node, "Write CPU High Mem\n"); wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_node, " Addr: 0x%08x\n", mem_addr); wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_node, " Len: %d\n", num_words); // Don't bother if length is clearly bogus if(num_words < max_resp_len) { for (mem_idx = 0; mem_idx < num_words; mem_idx++) { wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_node, " W[%2d]: 0x%08x\n", mem_idx, Xil_Ntohl(cmd_args_32[3 + mem_idx])); Xil_Out32((mem_addr + mem_idx*sizeof(u32)), Xil_Ntohl(cmd_args_32[3 + mem_idx])); } } else { wlan_exp_printf(WLAN_EXP_PRINT_ERROR, print_type_node, "CMDID_DEV_MEM_HIGH write longer than 1400 bytes\n"); status = CMD_PARAM_ERROR; } break; case CMD_PARAM_READ_VAL: wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_node, "Read CPU High Mem:\n"); wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_node, " Addr: 0x%08x\n", mem_addr); wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_node, " Len: %d\n", num_words); // Add payload to response if(num_words < max_resp_len) { // Don't set the default response use_default_resp = WLAN_EXP_FALSE; // Add length argument to response wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, status); wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, num_words); for (mem_idx = 0; mem_idx < num_words; mem_idx++) { wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, Xil_In32((u32)((void*)(mem_addr) + mem_idx*sizeof(u32)))); } } else { wlan_exp_printf(WLAN_EXP_PRINT_ERROR, print_type_node, "CMDID_DEV_MEM_HIGH read longer than 1400 bytes\n"); status = CMD_PARAM_ERROR; } break; default: wlan_exp_printf(WLAN_EXP_PRINT_ERROR, print_type_node, "Unknown command for 0x%6x: %d\n", cmd_id, msg_cmd); status = CMD_PARAM_ERROR; break; } if (use_default_resp) { // Send default response wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, status); } } break; //--------------------------------------------------------------------- case CMDID_DEV_MEM_LOW: { // Read/write memory in CPU Low via IPC message // // Write Message format: // cmd_args_32[0] Command == CMD_PARAM_WRITE_VAL // cmd_args_32[1] Address // cmd_args_32[2] Length (number of u32 words to write) // cmd_args_32[3:] Values to write (integral number of u32 words) // Response format: // resp_args_32[0] Status // // Read Message format: // cmd_args_32[0] Command == CMD_PARAM_READ_VAL // cmd_args_32[1] Address // cmd_args_32[2] Length (number of u32 words to read) // Response format: // resp_args_32[0] Status // resp_args_32[1] Length (number of u32 values) // resp_args_32[2:] Memory values (length u32 values) // u32 mem_idx; int mem_status; u32 status = CMD_PARAM_SUCCESS; u32 msg_cmd = Xil_Ntohl(cmd_args_32[0]); u32 mem_addr = Xil_Ntohl(cmd_args_32[1]); u32 num_words = Xil_Ntohl(cmd_args_32[2]); u32 use_default_resp = WLAN_EXP_TRUE; u32 max_resp_len = wlan_exp_transport_get_max_pkt_words(); u32* resp_args_32; switch (msg_cmd) { case CMD_PARAM_WRITE_VAL: wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_node, "Write CPU Low Mem:\n"); wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_node, " Addr: 0x%08x\n", mem_addr); wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_node, " Len: %d\n", num_words); // Don't bother if length is clearly bogus if(num_words < max_resp_len) { // Endian swap payload here - CPU Low requires payload that is ready to use as-is for (mem_idx = 0; mem_idx < num_words+2; mem_idx++) { cmd_args_32[1 + mem_idx] = Xil_Ntohl(cmd_args_32[1 + mem_idx]); } mem_status = wlan_mac_high_write_low_mem(num_words + 2, &(cmd_args_32[1])); if (mem_status == -1) { wlan_exp_printf(WLAN_EXP_PRINT_ERROR, print_type_node, "CMDID_DEV_MEM_LOW write failed\n"); status = CMD_PARAM_ERROR; } } else { wlan_exp_printf(WLAN_EXP_PRINT_ERROR, print_type_node, "CMDID_DEV_MEM_LOW write longer than 1400 bytes\n"); status = CMD_PARAM_ERROR; } break; case CMD_PARAM_READ_VAL: wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_node, "Read CPU Low Mem:\n"); wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_node, " Addr: 0x%08x\n", mem_addr); wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_node, " Len: %d\n", num_words); #define _CMDID_DEV_MEM_LOW_NUM_RESP_ARGS 2 if(num_words < max_resp_len) { resp_args_32 = (u32*)(eth_tx_queue_buffer->seg0 + eth_tx_queue_buffer->seg0_len + (_CMDID_DEV_MEM_LOW_NUM_RESP_ARGS*sizeof(u32))); mem_status = wlan_mac_high_read_low_mem(num_words, mem_addr, resp_args_32); if(mem_status == 0) { //Success // Don't set the default response use_default_resp = WLAN_EXP_FALSE; // Add length argument to response wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, status); wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, num_words); // Endian swap payload returned by CPU Low for (mem_idx = 0; mem_idx < num_words; mem_idx++) { //The packet payload already contains the data we need, but we'll add it word-by-word // in order to get the proper network order and update header values. wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, resp_args_32[mem_idx]); } } else { //failed wlan_exp_printf(WLAN_EXP_PRINT_ERROR, print_type_node, "CMDID_DEV_MEM_LOW read failed\n"); status = CMD_PARAM_ERROR; } } else { wlan_exp_printf(WLAN_EXP_PRINT_ERROR, print_type_node, "CMDID_DEV_MEM_LOW read longer than 1400 bytes\n"); status = CMD_PARAM_ERROR; } break; default: wlan_exp_printf(WLAN_EXP_PRINT_ERROR, print_type_node, "Unknown command for 0x%6x: %d\n", cmd_id, msg_cmd); status = CMD_PARAM_ERROR; break; } if (use_default_resp) { // Send default response wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, status); } } break; //----------------------------------------------------------------------------- // Child Commands //----------------------------------------------------------------------------- //--------------------------------------------------------------------- default: { u8 cmd_processed; // Call function in platform code resp_sent = wlan_platform_wlan_exp_process_node_cmd(cmd_hdr, eth_tx_queue_buffer, &cmd_processed); if(cmd_processed == 0){ // If platform code did not deal with this command, then // call standard function in child class to parse parameters implemented there resp_sent = wlan_exp_process_node_cmd_callback(cmd_hdr, eth_tx_queue_buffer); } } break; } return resp_sent; } /*****************************************************************************/ /** * @brief Send a doubly linked list as a response * * This function will send one or more response packets to retrieve data from a * doubly-linked list. Each response packet contains 5 u32 arguments followed by * raw payload containing the list data. * * resp_args_32[0] Number of bytes remaining, not including the bytes in this packet. * resp_args_32[1] Starting byte index of list data in this packet * resp_args_32[2] Number of bytes of list payload contained in this packet * resp_args_32[3] Retrieval timestamp (least significant bytes) * resp_arts_32[4] Retrieval timestamp (most significant bytes) * * @param first_eth_tx_queue_buffer - framework's pre-created first response packet * @param start_entry - first entry in the list to be copied * @param num_entries - number of entries from the list to send * @param offset_per_entry - how far into each entry the copy should begin (to avoid unwanted header fields) * @param size_per_entry - how many bytes to send from each entry (allows avoiding unwanted footer fields) * * @return NO_RESP_SENT * RESP_SENT * *****************************************************************************/ u32 _send_list_response( eth_tx_queue_buffer_t* first_eth_tx_queue_buffer, dl_entry* start_entry, u32 num_entries, u32 offset_per_entry, u32 size_per_entry ){ u32 resp_sent = 0; u32 max_bytes_per_pkt; u32 num_pkts; u32 total_num_bytes; u32 pkt_idx; u32 curr_index; u32 sent_bytes; u32 next_index; u32 transfer_length; u32 num_bytes; interrupt_state_t prev_interrupt_state; dl_entry* tmp_entry; cmd_resp_hdr_t* curr_cmd_resp_hdr; dl_entry* curr_entry; dl_entry* end_entry; u32 max_num_entries_per_pkt; eth_tx_queue_buffer_t* curr_eth_tx_queue_buffer; eth_tx_queue_buffer_t* next_eth_tx_queue_buffer; u64 retrieval_timestamp; retrieval_timestamp = get_system_time_usec(); #define _LIST_NUM_RESP_ARGS 5 u32 max_resp_len = wlan_exp_transport_get_max_pkt_words(); total_num_bytes = size_per_entry * num_entries; // Sanity check pointer arguments if( (first_eth_tx_queue_buffer == NULL) || (start_entry == NULL) || (total_num_bytes == 0) ){ return resp_sent; } next_eth_tx_queue_buffer = first_eth_tx_queue_buffer; curr_entry = start_entry; // First, we subtract the bytes that must be used for the list retrieval header max_bytes_per_pkt = ((max_resp_len) * 4) - (_LIST_NUM_RESP_ARGS * sizeof(u32)); // Integer division will properly floor the result so we can determine the largest // number of full entries that can be packed into a packet. max_num_entries_per_pkt = max_bytes_per_pkt / size_per_entry; // Update the maximum number of bytes to reflect an integer number of entries max_bytes_per_pkt = max_num_entries_per_pkt * size_per_entry; num_pkts = total_num_bytes/max_bytes_per_pkt; if((num_pkts * max_bytes_per_pkt) < total_num_bytes) num_pkts++; // We are going to be copying the header contents of the first response packet to all // subsequent response packets. Normally this is filled in at the time of sending, // but there's no point in repeating that code for every packet. Instead, we'll fill it // in early and skip the operation at the time of sending. wlan_exp_transport_fill_headers_response(first_eth_tx_queue_buffer); curr_index = 0; sent_bytes = 0; for (pkt_idx = 0; pkt_idx < num_pkts; pkt_idx++) { curr_eth_tx_queue_buffer = next_eth_tx_queue_buffer; next_eth_tx_queue_buffer = NULL; if( pkt_idx != (num_pkts-1) ){ prev_interrupt_state = wlan_platform_intc_stop(); do{ tmp_entry = queue_checkout(); if(tmp_entry == NULL){ // There are no free queue entries to handle this Tx. We don't have a way // of sending less than we are instructed, so we need to block until some // are freed up. This is made more complicated by the fact that we just // disabled interrupts since we are modifying dl_list. If an interrupt context // is going to free up a queue for us to use, we need to allow it to do so. // We'll briefly toggle interrupts so we can deal with any ISRs and get // back to this context to try again. // If this is happening a lot, we need to increase the total number of queue // entries or reduce their usage elsewhere. The intent is for this to rarely // occur. wlan_platform_intc_set_state(INTERRUPTS_ENABLED); wlan_usleep(1); wlan_platform_intc_stop(); } } while(tmp_entry == NULL); wlan_platform_intc_set_state(prev_interrupt_state); // The queue for outgoing wlan_exp transmissions is limited // to WLAN_EXP_MAX_QUEUE_LEN packets. If this queue is full, // subsequent packets will be dropped. This behavior is bad // for log and list retrieval since we could run into this // limit when returning a large amount of data. However, // disabling this limit is also not a good behavior -- the // intention is that wlan_exp cannot exhause queue entries // needed for other critical operations. So, instead, we'll // leave the limit in place and only proceed when we are sure // that the entry just checked out above will have a place // to go. Note: we give a little extra padding on // WLAN_EXP_MAX_QUEUE_LEN in case the wlan_exp transport steals // spots in the queue out from underneath us (e.g. ARP and ping // replies) while( wlan_exp_get_tx_queue_length() > (WLAN_EXP_MAX_QUEUE_LEN-5) ){ wlan_platform_intc_set_state(INTERRUPTS_ENABLED); wlan_usleep(1); wlan_platform_intc_set_state(prev_interrupt_state); } next_eth_tx_queue_buffer = (eth_tx_queue_buffer_t*)tmp_entry->data; // For all packets except the last in the array, we will start // a CDMA copy of wlan_exp_transport_header from the current packet // into the next. This will implicitly block if for some reason we run // into the CDMA still running from the previous loop (not likely). // wlan_mac_high_cdma_start_transfer(next_eth_tx_queue_buffer->seg0, curr_eth_tx_queue_buffer->seg0, curr_eth_tx_queue_buffer->seg0_len); // Update the length of the buffer next_eth_tx_queue_buffer->seg0_len = curr_eth_tx_queue_buffer->seg0_len; next_eth_tx_queue_buffer->seg1_len = 0; } transfer_length = WLAN_MIN( total_num_bytes-sent_bytes, max_bytes_per_pkt ); next_index = curr_index + transfer_length; curr_cmd_resp_hdr = (cmd_resp_hdr_t*)(curr_eth_tx_queue_buffer->seg0 + curr_eth_tx_queue_buffer->seg0_len - sizeof(cmd_resp_hdr_t)); num_bytes = dl_list_copy_data(curr_eth_tx_queue_buffer->seg0 + curr_eth_tx_queue_buffer->seg0_len + (_LIST_NUM_RESP_ARGS*sizeof(u32)), curr_entry, &end_entry, transfer_length/size_per_entry, offset_per_entry, size_per_entry); if (num_bytes > 0){ // 2) If the num_bytes was less than what we expected, but still non-zero, this is an edge condition where the list // was smaller than anticipated and this is the last packet we need to send. curr_cmd_resp_hdr->length += num_bytes; curr_eth_tx_queue_buffer->seg0_len += num_bytes; wlan_exp_add_u32_resp_arg(curr_eth_tx_queue_buffer, curr_cmd_resp_hdr, total_num_bytes-sent_bytes); wlan_exp_add_u32_resp_arg(curr_eth_tx_queue_buffer, curr_cmd_resp_hdr, curr_index); wlan_exp_add_u32_resp_arg(curr_eth_tx_queue_buffer, curr_cmd_resp_hdr, num_bytes); wlan_exp_add_u32_resp_arg(curr_eth_tx_queue_buffer, curr_cmd_resp_hdr, retrieval_timestamp & 0xFFFFFFFF); wlan_exp_add_u32_resp_arg(curr_eth_tx_queue_buffer, curr_cmd_resp_hdr, (retrieval_timestamp >> 32) & 0xFFFFFFFF); // Send the packet as a response _send_response(curr_cmd_resp_hdr, curr_eth_tx_queue_buffer, 0); resp_sent = RESP_SENT; } if (num_bytes < transfer_length){ // There wasn't enough log data to fill this full packet like we expected. If this isn't the last packet // we intended to send, we need to free the next packet queue buffer since we aren't going to use it. if (next_eth_tx_queue_buffer){ wlan_mac_high_cdma_finish_transfer(); // Finish the previous CDMA operation into the next packet queue buffer queue_checkin(next_eth_tx_queue_buffer->pyld_queue_hdr.dle); } break; } // Update our current address and bytes remaining curr_index = next_index; sent_bytes += transfer_length; curr_entry = NULL; if(end_entry) curr_entry = dl_entry_next(end_entry); if(curr_entry == NULL){ break; } } return resp_sent; } #if WLAN_SW_CONFIG_ENABLE_LOGGING /*****************************************************************************/ /** * @brief Send log data * * This function will send one or more response packets to retrieve data from a * the event log. Each response packet contains 3 u32 arguments followed by * raw payload containing the log data. * * resp_args_32[0] Number of bytes remaining, not including the bytes in this packet. * resp_args_32[1] Starting byte index of log data in this packet * resp_args_32[2] Number of bytes of log payload contained in this packet * * @param first_eth_tx_queue_buffer - framework's pre-created first response packet * @param start_index - byte index in log where to start the retrieval * @param total_num_bytes - number of entries from the list to send * * @return NO_RESP_SENT * RESP_SENT * *****************************************************************************/ u32 _transfer_log_data(eth_tx_queue_buffer_t* first_eth_tx_queue_buffer, u32 start_index, u32 total_num_bytes) { #define LOG_TRANSFER_NUM_PKT_BURST 6 u32 resp_sent = 0; int num_pkts; // must be signed, for defined behavior with (num_pkts-2) below u32 curr_index; u32 next_index; u32 sent_bytes; u32 max_bytes_per_pkt; u32 transfer_length; int pkt_idx; u32 num_bytes; dl_entry* tmp_queue_entry; cmd_resp_hdr_t* curr_cmd_resp_hdr; interrupt_state_t prev_interrupt_state; eth_tx_queue_buffer_t* curr_eth_tx_queue_buffer = NULL; eth_tx_queue_buffer_t* next_eth_tx_queue_buffer = NULL; eth_tx_queue_buffer_t* last_pkt_queue_buffer = NULL; u32 resp_args_offset; volatile u32* resp_args_32; #define _LOG_NUM_RESP_ARGS 3 u32 max_resp_len = wlan_exp_transport_get_max_pkt_words(); // Sanity check pointer arguments if( (first_eth_tx_queue_buffer == NULL) || (total_num_bytes == 0) ){ return resp_sent; } // Once we start adding arguments, seg0_len will encompass // those arguments. Before we do anything else, we'll save // away this value so we can always find where to place // response arguments in subsequent packets where seg0_len // has changed. resp_args_offset = first_eth_tx_queue_buffer->seg0_len; // The 0 here is a reminder that any bytes dedicated as a retrieval header // need to be accounted for as part of the response length. max_bytes_per_pkt = ((max_resp_len) * 4) - (_LOG_NUM_RESP_ARGS * sizeof(u32)); num_pkts = total_num_bytes/max_bytes_per_pkt; if((num_pkts * max_bytes_per_pkt) < total_num_bytes) num_pkts++; // Set the first pointer to the provided argument next_eth_tx_queue_buffer = first_eth_tx_queue_buffer; // The log subsystem uses "index" to refer to byte offsets relative to the base of // the log data memory block. In this context: // size: the number of log data bytes requested by the host // start_index: index of first log data byte requested by the host // end_index: index of the log data byte immediately after the last log data byte requested by the host // (thus the log data byte at end_index will not be transmitted to the host in this context) curr_index = start_index; sent_bytes = 0; // We are going to be copying the header contents of the first response packet to all // subsequent response packets. Normally this is filled in at the time of sending, // but there's no point in repeating that code for every packet. Instead, we'll fill it // in early and skip the operation at the time of sending. wlan_exp_transport_fill_headers_response(first_eth_tx_queue_buffer); if(num_pkts > 1) { // Check out a queue buffer to use a temporary scratch space that can be accessed // by the CDMA prev_interrupt_state = wlan_platform_intc_stop(); do{ tmp_queue_entry = queue_checkout(); if(tmp_queue_entry == NULL){ // There are no free queue entries to handle this Tx. We don't have a way // of sending less than we are instructed, so we need to block until some // are freed up. This is made more complicated by the fact that we just // disabled interrupts since we are modifying dl_list. If an interrupt context // is going to free up a queue for us to use, we need to allow it to do so. // We'll briefly toggle interrupts so we can deal with any ISRs and get // back to this context to try again. // If this is happening a lot, we need to increase the total number of queue // entries or reduce their usage elsewhere. The intent is for this to rarely // occur. wlan_platform_intc_set_state(INTERRUPTS_ENABLED); wlan_usleep(1); wlan_platform_intc_stop(); } } while(tmp_queue_entry == NULL); wlan_platform_intc_set_state(prev_interrupt_state); last_pkt_queue_buffer = (eth_tx_queue_buffer_t*)(tmp_queue_entry->data); // Copy the headers from the first packet into the last packet // Headers for any intermediate packets will be copied inside the for loop below last_pkt_queue_buffer->seg0_len = first_eth_tx_queue_buffer->seg0_len; last_pkt_queue_buffer->seg1_len = 0; wlan_mac_high_cdma_start_transfer(last_pkt_queue_buffer->seg0, first_eth_tx_queue_buffer->seg0, first_eth_tx_queue_buffer->seg0_len); } else { last_pkt_queue_buffer = NULL; } // We are going to temporarily disable the wlan_exp Eth Tx software // interrupt in order to minimize the number of context switches wlan_platform_clear_sw_intr_mask(SW_INTR_ID_WLAN_EXP_ETH_TX); for (pkt_idx = 0; pkt_idx < num_pkts; pkt_idx++) { if((num_pkts >= 2) && (pkt_idx == (num_pkts - 1))) { // The last packet queue buffer was allocated and initialized above this loop curr_eth_tx_queue_buffer = last_pkt_queue_buffer; } else { // next_eth_tx_queue_buffer was initialized above this loop, then updated // in previous iterations of this loop. This assignment must be used for all // packets except the last packet in a multi-packet response curr_eth_tx_queue_buffer = next_eth_tx_queue_buffer; } // Reset the next_ pointer, will be updated below if this is not the last iteration next_eth_tx_queue_buffer = NULL; // Allocate a queue buffer for the next packet, unless the next packet is the last packet if( (num_pkts >= 3) && (pkt_idx < (num_pkts-2))) { prev_interrupt_state = wlan_platform_intc_stop(); do{ tmp_queue_entry = queue_checkout(); if(tmp_queue_entry == NULL){ // There are no free queue entries to handle this Tx. We don't have a way // of sending less than we are instructed, so we need to block until some // are freed up. This is made more complicated by the fact that we just // disabled interrupts since we are modifying dl_list. If an interrupt context // is going to free up a queue for us to use, we need to allow it to do so. // We'll briefly toggle interrupts so we can deal with any ISRs and get // back to this context to try again. // If this is happening a lot, we need to increase the total number of queue // entries or reduce their usage elsewhere. The intent is for this to rarely // occur. wlan_platform_intc_set_state(INTERRUPTS_ENABLED); wlan_usleep(1); wlan_platform_intc_stop(); } } while(tmp_queue_entry == NULL); wlan_platform_intc_set_state(prev_interrupt_state); // The queue for outgoing wlan_exp transmissions is limited // to WLAN_EXP_MAX_QUEUE_LEN packets. If this queue is full, // subsequent packets will be dropped. This behavior is bad // for log and list retrieval since we could run into this // limit when returning a large amount of data. However, // disabling this limit is also not a good behavior -- the // intention is that wlan_exp cannot exhause queue entries // needed for other critical operations. So, instead, we'll // leave the limit in place and only proceed when we are sure // that the entry just checked out above will have a place // to go. Note: we give a little extra padding on // WLAN_EXP_MAX_QUEUE_LEN in case the wlan_exp transport steals // spots in the queue out from underneath us (e.g. ARP and ping // replies) while( wlan_exp_get_tx_queue_length() > (WLAN_EXP_MAX_QUEUE_LEN-5) ){ wlan_platform_intc_set_state(INTERRUPTS_ENABLED); wlan_usleep(1); wlan_platform_intc_set_state(prev_interrupt_state); } next_eth_tx_queue_buffer = (eth_tx_queue_buffer_t*)tmp_queue_entry->data; // For all packets except the last in the array, we will start // a CDMA copy of wlan_exp_transport_header from the current packet // into the next. This will implicitly block if for some reason we run // into the CDMA still running from the previous loop (not likely). } transfer_length = WLAN_MIN( total_num_bytes-sent_bytes, max_bytes_per_pkt ); next_index = curr_index + transfer_length; // Set up cmd_resp_hdr_t curr_cmd_resp_hdr = (cmd_resp_hdr_t*)(curr_eth_tx_queue_buffer->seg0 + curr_eth_tx_queue_buffer->seg0_len - sizeof(cmd_resp_hdr_t)); num_bytes = event_log_get_data(curr_index, transfer_length, &(curr_eth_tx_queue_buffer->seg1_addr)); if (num_bytes > 0){ wlan_mac_high_cdma_finish_transfer(); // If the previous iteration of the loop is still copying // bytes into this current queue buffer, we need to wait // for it to complete. curr_eth_tx_queue_buffer->seg1_len = num_bytes; resp_args_32 = (u32*)(curr_eth_tx_queue_buffer->seg0 + resp_args_offset); //Arg 0: Number of bytes remaining resp_args_32[0] = Xil_Htonl(total_num_bytes-sent_bytes); //Arg 1: Current byte index resp_args_32[1] = Xil_Htonl(curr_index); //Arg 2: Number of log bytes in this packet resp_args_32[2] = Xil_Htonl(num_bytes); if( (pkt_idx == 0) || (pkt_idx == (num_pkts-1)) ){ // The first and last packets of the transmission are unique in that their headers need to be // updated prior to being sent. // Every other packet of a log retrieval will have identical headers to the first, so we can // avoid the computational overhead of recalculating that data. curr_cmd_resp_hdr->length += _LOG_NUM_RESP_ARGS*sizeof(u32) + num_bytes; curr_cmd_resp_hdr->num_u32_args += _LOG_NUM_RESP_ARGS; curr_eth_tx_queue_buffer->seg0_len += _LOG_NUM_RESP_ARGS*sizeof(u32); _prepare_response_for_send(curr_cmd_resp_hdr); wlan_exp_transport_prepare_headers(curr_eth_tx_queue_buffer); } if((num_pkts >= 3) && (pkt_idx < (num_pkts-2))) { // The first and all intermediate packets (packets except the last) have the same Eth/IP/UDP/Transport/Response headers // However the packets are submitted to the queue/DMA on each iteration, and packets submitted to hardware must not be // accessed until the DMA is finishes. Thus, this loop copies headers from the current packet to the _next_ packet before // the current packet is submitted to the queue/DMA. wlan_mac_high_cdma_start_transfer(next_eth_tx_queue_buffer->seg0, curr_eth_tx_queue_buffer->seg0, curr_eth_tx_queue_buffer->seg0_len); // This CDMA operation must be finished before the first of two things happens: // 1) curr_eth_tx_queue_buffer is returned to the free pool. Look for the wlan_mac_high_cdma_finish_transfer() call // in platform code when transmitted packets are freed. // 2) next_eth_tx_queue_buffer is modified. This is why there is a call to wlan_mac_high_cdma_finish_transfer() earlier // in this for loop. // Update the length of the buffer next_eth_tx_queue_buffer->seg0_len = curr_eth_tx_queue_buffer->seg0_len; next_eth_tx_queue_buffer->seg1_len = 0; } // Send the Ethernet packet wlan_exp_append_tx(curr_eth_tx_queue_buffer->pyld_queue_hdr.dle); resp_sent = RESP_SENT; } if (num_bytes < transfer_length){ // There wasn't enough log data to fill this full packet like we expected. If this isn't the last packet // we intended to send, we need to free the next packet queue buffer since we aren't going to use it. if (next_eth_tx_queue_buffer) { wlan_mac_high_cdma_finish_transfer(); // Finish the previous CDMA operation into the next packet queue buffer queue_checkin(next_eth_tx_queue_buffer->pyld_queue_hdr.dle); } if (last_pkt_queue_buffer && (last_pkt_queue_buffer != next_eth_tx_queue_buffer)) { wlan_mac_high_cdma_finish_transfer(); // Finish the previous CDMA operation into the next packet queue buffer queue_checkin(last_pkt_queue_buffer->pyld_queue_hdr.dle); } break; } if( ((pkt_idx+1) % LOG_TRANSFER_NUM_PKT_BURST) == 0 ){ // Re-enable dequeueing from the wlan_exp Eth Tx queue // This will move the program counter to the software interrupt ISR // and other ISRs until the wlan_exp Eth Tx queue is completely // empty wlan_platform_set_sw_intr_mask(SW_INTR_ID_WLAN_EXP_ETH_TX); // Disable dequeueing from the wlan_exp Eth Tx queue wlan_platform_clear_sw_intr_mask(SW_INTR_ID_WLAN_EXP_ETH_TX); } // Update our current address and bytes remaining curr_index = next_index; sent_bytes += transfer_length; } // Re-enable dequeueing from the wlan_exp Eth Tx queue wlan_platform_set_sw_intr_mask(SW_INTR_ID_WLAN_EXP_ETH_TX); return resp_sent; } #endif //WLAN_SW_CONFIG_ENABLE_LOGGING void wlan_exp_reset_all_callbacks(){ wlan_exp_process_node_cmd_callback = (function_ptr_t) _null_process_cmd_callback; wlan_exp_purge_all_wireless_tx_queue_callback = (function_ptr_t) wlan_exp_null_callback; wlan_exp_process_user_cmd_callback = (function_ptr_t) _null_process_cmd_callback; wlan_exp_beacon_ts_update_mode_callback = (function_ptr_t) wlan_exp_null_callback; wlan_exp_process_config_bss_callback = (function_ptr_t) wlan_exp_null_callback; wlan_exp_active_network_info_getter_callback = (function_ptr_t) wlan_exp_null_callback; } void wlan_exp_set_process_node_cmd_callback(void(*callback)()){ wlan_exp_process_node_cmd_callback = (function_ptr_t) callback; } void wlan_exp_set_purge_all_wireless_tx_queue_callback(void(*callback)()){ wlan_exp_purge_all_wireless_tx_queue_callback = (function_ptr_t) callback; } void wlan_exp_set_process_user_cmd_callback(void(*callback)()){ wlan_exp_process_user_cmd_callback = (function_ptr_t) callback; } void wlan_exp_set_beacon_ts_update_mode_callback(void(*callback)()){ wlan_exp_beacon_ts_update_mode_callback = (function_ptr_t) callback; } void wlan_exp_set_process_config_bss_callback(void(*callback)()){ wlan_exp_process_config_bss_callback = (function_ptr_t) callback; } void wlan_exp_set_active_network_info_getter_callback(void(*callback)()){ wlan_exp_active_network_info_getter_callback = (function_ptr_t) callback; } /*****************************************************************************/ /** * This is a helper function to clean up the LTGs owned by WLAN Exp * * @param id - LTG id * callback_arg - Callback argument for LTG * * @return None * *****************************************************************************/ void _ltg_cleanup(u32 id, void* callback_arg){ wlan_mac_high_free(callback_arg); } #endif // End WLAN_SW_CONFIG_ENABLE_WLAN_EXP