source: ReferenceDesigns/w3_802.11/c/wlan_mac_high_framework/wlan_exp_node.c

Last change on this file was 6319, checked in by chunter, 5 years ago

1.8.0 release wlan-mac-se

File size: 138.8 KB
Line 
1/** @file wlan_exp_node.c
2 *  @brief Experiment Framework (Node)
3 *
4 *  This contains the code for WLAN Experiments Framework. This is both the entry point for commands processing
5 *  as well as one of the command groups.
6 *
7 *  @copyright Copyright 2013-2019, Mango Communications. All rights reserved.
8 *          Distributed under the Mango Communications Reference Design License
9 *              See LICENSE.txt included in the design archive or
10 *              at http://mangocomm.com/802.11/license
11 *
12 *  This file is part of the Mango 802.11 Reference Design (https://mangocomm.com/802.11)
13 */
14
15#include "wlan_mac_high_sw_config.h"
16
17#if WLAN_SW_CONFIG_ENABLE_WLAN_EXP
18
19// Xilinx / Standard library includes
20#include "xil_io.h"
21#include "stdlib.h"
22#include "stdio.h"
23#include "string.h"
24
25// WLAN includes
26#include "wlan_high_types.h"
27#include "wlan_mac_pkt_buf_util.h"
28#include "wlan_platform_common.h"
29#include "wlan_platform_high.h"
30#include "wlan_mac_event_log.h"
31#include "wlan_mac_entries.h"
32#include "wlan_mac_ltg.h"
33#include "wlan_mac_schedule.h"
34#include "wlan_mac_scan.h"
35#include "wlan_mac_network_info.h"
36#include "wlan_mac_station_info.h"
37#include "wlan_mac_eth_util.h"
38#include "wlan_mac_high.h"
39#include "wlan_mac_common.h"
40#include "wlan_mac_dl_list.h"
41#include "wlan_mac_queue.h"
42#include "wlan_platform_high.h"
43
44// WLAN Exp includes
45#include "wlan_exp.h"
46#include "wlan_exp_common.h"
47#include "wlan_exp_node.h"
48#include "wlan_exp_transport.h"
49#include "wlan_exp_user.h"
50#include "wlan_exp_ip_udp_socket.h"
51#include "wlan_exp_ip_udp_arp.h"
52
53// Declared in wlan_mac_high.c
54extern u8 low_param_rx_ant_mode;
55extern u8 low_param_channel;
56extern platform_common_dev_info_t platform_common_dev_info;
57extern platform_high_dev_info_t platform_high_dev_info;
58extern wlan_mac_hw_info_t wlan_mac_hw_info;
59
60// Local functions
61void _send_response(cmd_resp_hdr_t* resp_hdr,  eth_tx_queue_buffer_t* eth_tx_queue_buffer, u8 fill_headers);
62void _prepare_response_for_send(cmd_resp_hdr_t* resp_hdr);
63int _process_node_cmd(cmd_resp_hdr_t* cmd_hdr, eth_tx_queue_buffer_t* eth_tx_queue_buffer);
64void _ltg_cleanup(u32 id, void* callback_arg);
65u32 _transfer_log_data( eth_tx_queue_buffer_t* first_eth_tx_queue_buffer, u32 start_index, u32 total_num_bytes );
66u32 _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 );
67int _null_process_cmd_callback(u32 cmd_id, void* param);
68
69wlan_exp_node_info_t wlan_exp_node_info;
70
71static function_ptr_t wlan_exp_process_node_cmd_callback;
72       function_ptr_t wlan_exp_purge_all_wireless_tx_queue_callback;
73       function_ptr_t wlan_exp_process_user_cmd_callback;
74       function_ptr_t wlan_exp_beacon_ts_update_mode_callback;
75       function_ptr_t wlan_exp_process_config_bss_callback;
76       function_ptr_t wlan_exp_active_network_info_getter_callback;
77
78/*****************************************************************************/
79/**
80 * @brief This initializes the node so it can communicate with a wlan_exp host.
81 *
82 * @return  int  - Status of the command:
83 *                   WLAN_SUCCESS - Command completed successfully
84 *                   WLAN_FAILURE - There was an error in the command
85 *
86 *****************************************************************************/
87int wlan_exp_node_init() {
88
89    int status = WLAN_SUCCESS;
90
91#if WLAN_SW_CONFIG_ENABLE_LOGGING
92    u64 mac_timestamp;
93    u64 system_timestamp;
94#endif
95
96    xil_printf("------------------------\n");
97    xil_printf("Initializing wlan_exp v%d.%d.%d...\n", WLAN_EXP_VER_MAJOR, WLAN_EXP_VER_MINOR, WLAN_EXP_VER_REV);
98
99    wlan_exp_reset_all_callbacks();
100
101
102    // ------------------------------------------
103    // Initialize Node information
104    //   Node ID / Network information must be set using dynamic node configuration process
105    //   Initial IP Address should be NODE_IP_ADDR_BASE for all nodes
106    //
107    wlan_exp_node_info.scheduler_interval = platform_high_dev_info.timer_dur_us;
108
109    wlan_exp_node_info.node_id = 0xFFFF;
110    wlan_exp_node_info.platform_id = wlan_mac_hw_info.platform_id;
111    wlan_exp_node_info.platform_config = wlan_mac_hw_info.platform_config;
112    wlan_exp_node_info.serial_number = wlan_mac_hw_info.serial_number;
113    wlan_exp_node_info.wlan_exp_version = REQ_WLAN_EXP_HW_VER;
114
115    memcpy(wlan_exp_node_info.wlan_mac_addr, wlan_mac_hw_info.hw_addr_wlan, MAC_ADDR_LEN);
116
117    wlan_exp_node_info.wlan_exp_eth_mtu = wlan_platform_wlan_exp_eth_get_mtu();
118
119#if WLAN_SW_CONFIG_ENABLE_LOGGING
120    // ------------------------------------------
121    // By default, enable all subtype logging
122    wlan_exp_log_set_entry_en_mask(ENTRY_EN_MASK_TXRX_CTRL | ENTRY_EN_MASK_TXRX_MPDU);
123
124
125    // ------------------------------------------
126    // Reset the System Time ID
127    wlan_exp_log_reset_system_time_id();
128
129
130    // ------------------------------------------
131    // Add a time info entry to the log to record the initial MAC time and system time
132    mac_timestamp    = get_mac_time_usec();
133    system_timestamp = get_system_time_usec();
134
135    add_time_info_entry(mac_timestamp, mac_timestamp, system_timestamp, TIME_INFO_ENTRY_TIME_RSVD_VAL_64, TIME_INFO_ENTRY_SYSTEM, 0, 0);
136#endif
137
138    // ------------------------------------------
139    // Transport initialization
140    //
141    status = transport_init();
142
143    if (status == WLAN_FAILURE) {
144        xil_printf("  Error in transport_init()! Exiting...\n");
145        return WLAN_FAILURE;
146    }
147
148    return status;
149}
150
151/*****************************************************************************/
152/**
153 * @brief Returns a pointer to the framework's wlan_exp_node_info_t struct
154 *
155 * @return  wlan_exp_node_info_t*
156 *
157 *****************************************************************************/
158wlan_exp_node_info_t* wlan_exp_get_node_info(){
159    return &wlan_exp_node_info;
160}
161
162/*****************************************************************************/
163/**
164 * @brief Adds a u32 argument to the provided response packet and updates the response
165 * header to account for the new word.
166 *
167 * @param eth_tx_queue_buffer_t* eth_tx_queue_buffer - Pointer to the Ethernet queue buffer
168 *                                                    that contains the respone
169 * @param cmd_resp_hdr_t* resp_hdr - Pointer to the response header in the Ethernet queue
170 *                                   buffer's seg0 segment
171 * @param u32 arg - argument to be added to response
172 * @return  None
173 *
174 *****************************************************************************/
175void wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer_t* eth_tx_queue_buffer, cmd_resp_hdr_t* resp_hdr, u32 arg) {
176    // Add the argument to the end of the response arguments array
177    ((u32*)((u8*)resp_hdr + sizeof(cmd_resp_hdr_t)))[resp_hdr->num_u32_args] = Xil_Htonl(arg);
178
179    // Update the response header to include the new argument
180    resp_hdr->num_u32_args++;
181    resp_hdr->length += sizeof(u32);
182
183    // Update the response packet buffer length to include the new argument
184    eth_tx_queue_buffer->seg0_len += sizeof(u32);
185
186    return;
187}
188
189/**********************************************************************************************************************/
190/**
191 * @brief Process an Ethernet reception for wlan_exp
192 *
193 * This function deals with Ethernet receptions and has the following outcomes:
194 *      1) It will enqueue the transmission of an ARP reply as a response to an ARP request
195 *         with this node's IP address
196 *      2) It will enqueue the transmission of an ICMP (ping) reply as a response to an ICMP
197 *         echo request
198 *      3) It will enqueue UDP packets that meet requirements of currently opened sockets
199 *         for future processing.
200 *
201 * The goal of this function is to be very lightweight as it may be called in an interrupt
202 * context and we do not want to adversely affect performance of critical 802.11 functions.
203 * Any wlan_exp UDP messages will be enqueued for later processing outside of any
204 * interrupt contexts (regardless of whether the underlying Ethernet peripheral was polling
205 * or interrupt-based)
206 *
207 * @return 1 if claiming packet, 0 otherwise.
208 *
209 **********************************************************************************************************************/
210int wlan_exp_process_eth_rx(eth_rx_queue_buffer_t* eth_rx_queue_buffer){
211
212    eth_tx_queue_buffer_t* eth_tx_queue_buffer;
213    dl_entry* eth_tx_queue_entry;
214    ethernet_header_t* eth_hdr;
215
216    u8 node_addr_match;
217    u8 mcast_addr_match;
218    u8 hw_addr[ETH_ADDR_LEN];
219    int rx_length = -1;
220
221    eth_tx_queue_entry = queue_checkout(); // Check out space for a Tx response (if needed)
222
223    if (eth_tx_queue_entry == NULL){
224        // We were not able to check out a queue buffer for a response, so we'll report to
225        // the calling context that we did not want this reception so it can be freed
226        return 0;
227    }
228    eth_tx_queue_buffer = (eth_tx_queue_buffer_t*)(eth_tx_queue_entry->data);
229
230    // Set segment lengths to zero. If these fields are non-zero, we will use that
231    //  as an indicator that the IP/UDP library wants to send something.
232    eth_tx_queue_buffer->seg0_len = 0;
233    eth_tx_queue_buffer->seg1_len = 0;
234
235    eth_hdr = (ethernet_header_t*)eth_rx_queue_buffer->pkt;
236
237    eth_get_hw_addr(hw_addr);
238
239    node_addr_match = wlan_addr_eq(eth_hdr->dest_mac_addr, hw_addr);
240    mcast_addr_match = wlan_addr_mcast(eth_hdr->dest_mac_addr);
241
242    // Process the packet based on the EtherType
243    if (node_addr_match | mcast_addr_match) {
244        switch (Xil_Ntohs(eth_hdr->ethertype)) {
245            // ARP packet
246            case ETHERTYPE_ARP:
247                rx_length = arp_process_packet(eth_rx_queue_buffer, eth_tx_queue_buffer);
248            break;
249
250            // IP packet
251            case ETHERTYPE_IP_V4:
252                rx_length = ipv4_process_packet(eth_rx_queue_buffer, eth_tx_queue_buffer);
253            break;
254        }
255    }
256
257    if((eth_tx_queue_buffer->seg0_len + eth_tx_queue_buffer->seg1_len) > 0 ){
258        // If IP/UDP processing generated a response and filled in eth_tx_queue_buffer,
259        //  submit it to the transport for future processing.
260        wlan_exp_append_tx(eth_tx_queue_entry);
261    } else {
262        // No response was needed. Return this queue buffer to the free pool.
263        queue_checkin(eth_tx_queue_entry);
264    }
265
266    if (rx_length > 0){
267        // This Ethernet frame passed a check against open sockets, so we will claim it
268        // and enqueue it for further processing from the wlan_exp transport.
269
270        // Add the queue entry to the list of packets to be processed by wlan_exp
271        wlan_exp_append_rx(eth_rx_queue_buffer->pyld_queue_hdr.dle);
272
273        return 1;
274    } else {
275        return 0; // Calling context responsible for garbage collection since this frame may be consumed by
276                  // another module in the framework.
277    }
278
279}
280
281/*****************************************************************************/
282/**
283 * @brief Set CPU_HIGH Type
284 *
285 * This function sets the CPU_HIGH type bits in the node_info.node_type field.
286 *
287 * @param   application_role_t  - CPU_HIGH application role
288 * @param   char* date - string of date that CPU_HIGH was compiled
289 * @param   char* time - string of time that CPU_HIWH was compiled
290 *
291 ******************************************************************************/
292void wlan_exp_node_set_type_high(application_role_t application_role, char* date, char* time){
293    u32 sw_id = 0;
294
295    switch(application_role){
296        case APPLICATION_ROLE_AP:
297            sw_id = WLAN_EXP_HIGH_SW_ID_AP;
298        break;
299        case APPLICATION_ROLE_STA:
300            sw_id = WLAN_EXP_HIGH_SW_ID_STA;
301        break;
302        case APPLICATION_ROLE_IBSS:
303            sw_id = WLAN_EXP_HIGH_SW_ID_IBSS;
304        break;
305        case APPLICATION_ROLE_UNKNOWN:
306            sw_id = 0;
307        break;
308    }
309
310    strncpy(wlan_exp_node_info.high_compilation_date, date, 12);
311    strncpy(wlan_exp_node_info.high_compilation_time, time, 9);
312
313    wlan_exp_node_info.high_sw_id = sw_id;
314    wlan_exp_node_info.high_sw_config = 0;
315
316}
317
318/*****************************************************************************/
319/**
320 * @brief Set CPU_LOW Type
321 *
322 * This function sets the CPU_LOW type bits in the node_info.node_type field.
323 * The MAC High Framework will call this function after receiving an IPC message
324 * from CPU_LOW indicating its wlan_exp type.
325 *
326 * @param   type_low - CPU_LOW Type from wlan_exp.h
327 * @param   char* date - string of date that CPU_HIGH was compiled
328 * @param   char* time - string of time that CPU_HIWH was compiled
329 *
330 ******************************************************************************/
331void wlan_exp_node_set_type_low(u32 sw_id, char* date, char* time){
332
333    strncpy(wlan_exp_node_info.low_compilation_date, date, 12);
334    strncpy(wlan_exp_node_info.low_compilation_time, time, 9);
335
336    wlan_exp_node_info.low_sw_id = sw_id;
337    wlan_exp_node_info.low_sw_config = 0;
338}
339
340/*****************************************************************************/
341/**
342 * @brief Null Process Command Callback
343 *
344 * This function is part of the callback system for processing WLAN Exp commands. If
345 * there are no additional node commands, then this will return an appropriate value.
346 *
347 * To processes additional node commands, please set the process_node_cmd_callback
348 *
349 * @param   cmd_id           - Command ID from node_process_cmd
350 * @param   param            - Generic parameters for the callback
351 *
352 * @return  int              - Status of the command:
353 *                                 NO_RESP_SENT - No response has been sent
354 *
355 ******************************************************************************/
356int _null_process_cmd_callback(u32 cmd_id, void* param){
357
358    wlan_exp_printf(WLAN_EXP_PRINT_ERROR, print_type_node, "Unknown node command: %d\n", cmd_id);
359
360    return NO_RESP_SENT;
361};
362
363
364
365/*****************************************************************************/
366/**
367 * @brief Node Transport Processing (Host to Node)
368 *
369 * This function is called by the transport to deal with any wlan_exp commands
370 * that are addressed to this node. It must return whether or not it has sent
371 * a response packet so the transport knows whether or not it must acknowledge
372 * the command.
373 *
374 * @param wlan_exp_eth_rx_queue_buffer - Ethernet queue buffer that contains command
375 * @param wlan_exp_eth_tx_queue_buffer - Ethernet queue buffer for response that should be filled in
376 *
377 * @return  RESP_SENT or NO_RESP_SENT
378 *
379 *****************************************************************************/
380int 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) {
381
382    u8 cmd_group;
383    int resp_sent = NO_RESP_SENT;
384
385    cmd_resp_hdr_t* cmd_hdr = NULL;
386    cmd_resp_hdr_t* resp_hdr = NULL;
387
388    // Initialize the Command/Response pointers
389    cmd_hdr = (cmd_resp_hdr_t*)(wlan_exp_eth_rx_queue_buffer->pkt +
390                              sizeof(ethernet_header_t) +
391                              sizeof(ipv4_header_t) +
392                              sizeof(udp_header_t) +
393                              sizeof(wlan_exp_transport_header));
394
395    resp_hdr = (cmd_resp_hdr_t*)(eth_tx_queue_buffer->seg0 + eth_tx_queue_buffer->seg0_len);
396
397    // Endian swap the command header so future processing can understand it
398    cmd_hdr->cmd      = Xil_Ntohl(cmd_hdr->cmd);
399
400    // Length field might be longer than what is actually in the packet
401    // depending on the maximum packet sizes supported by the host, the node, and the Ethernet network
402    // We will sanitize these values to the smaller of their set values or the largest
403    // values they can be given the total length of the received Ethernet frame.
404    cmd_hdr->length   = WLAN_MIN ( Xil_Ntohs(cmd_hdr->length),
405                                   wlan_exp_eth_rx_queue_buffer->length
406                                   - sizeof(ethernet_header_t)
407                                   - sizeof(ipv4_header_t)
408                                   - sizeof(udp_header_t)
409                                   - sizeof(cmd_resp_hdr_t) );
410
411    cmd_hdr->num_u32_args = Xil_Ntohs(cmd_hdr->num_u32_args);
412
413    // Set up the minimum required response header needed to form an acknowledgment
414    resp_hdr->cmd      = cmd_hdr->cmd;
415    resp_hdr->length   = 0;
416    resp_hdr->num_u32_args = 0;
417
418    eth_tx_queue_buffer->seg0_len += sizeof(cmd_resp_hdr_t);
419
420    // Send command to appropriate processing sub-system
421    cmd_group = CMD_TO_GROUP(cmd_hdr->cmd);
422
423    switch(cmd_group){
424        case GROUP_NODE:
425            resp_sent = _process_node_cmd(cmd_hdr, eth_tx_queue_buffer);
426        break;
427        case GROUP_TRANSPORT:
428            resp_sent = process_transport_cmd(cmd_hdr, eth_tx_queue_buffer);
429        break;
430        case GROUP_USER:
431            resp_sent = process_user_cmd(cmd_hdr, eth_tx_queue_buffer);
432        break;
433        default:
434            wlan_exp_printf(WLAN_EXP_PRINT_ERROR, print_type_node, "Unknown command group: %d\n", cmd_group);
435        break;
436    }
437
438    // Adjust the length of the response to include the response data from the sub-system and the
439    // response header
440    //
441    if(resp_sent == NO_RESP_SENT && resp_hdr) {
442        _prepare_response_for_send(resp_hdr);
443    }
444
445    // Return the status
446    return resp_sent;
447}
448
449
450
451/*****************************************************************************/
452/**
453 * @brief Node Send Early Response
454 *
455 * Allows a node to send a response back to the host. Calling context is responsible
456 * for informing the transport it has sent a response so the transport can skip
457 * sending an acknowledgment.
458 *
459 * @param   resp_hdr  - Pointer to Command / Response header for outgoing message
460 * @param   eth_tx_queue_buffer - Pointer to packet queue buffer containing message
461 * @param   fill_headers - 1 indicates that Eth/IP/UDP headers should be filled in, 0 otherwise
462 *
463 * @return  None
464 *
465 *
466 *****************************************************************************/
467void _send_response(cmd_resp_hdr_t* resp_hdr,  eth_tx_queue_buffer_t* eth_tx_queue_buffer, u8 fill_headers) {
468
469    _prepare_response_for_send(resp_hdr);
470    if( fill_headers) wlan_exp_transport_fill_headers_response(eth_tx_queue_buffer);
471    wlan_exp_transport_send(eth_tx_queue_buffer);
472}
473
474/*****************************************************************************/
475/**
476 * @brief Prepare response header
477 *
478 * This function is responsible for endian swapping the contents of cmd_resp_hdr_t
479 * in the outgoing frame before passing the frame off to the transport for
480 * transmission.
481 *
482 * @param   resp_hdr  - Pointer to Command / Response header for outgoing message
483 *
484 * @return  None
485 *
486 *
487 *****************************************************************************/
488void _prepare_response_for_send(cmd_resp_hdr_t* resp_hdr){
489    resp_hdr->cmd = Xil_Ntohl(resp_hdr->cmd);
490    resp_hdr->length = Xil_Ntohs(resp_hdr->length);
491    resp_hdr->num_u32_args = Xil_Ntohs(resp_hdr->num_u32_args);
492}
493
494
495/*****************************************************************************/
496/**
497 * @brief Process Node Commands
498 *
499 * Process commands from a host meant for the node group
500 *
501 * @param cmd_hdr - pointer to the command header
502 * @param eth_tx_queue_buffer - pointer to a Ethernet queue buffer that should be
503 *                              filled in with response arguments
504 *
505 * @return  int - NO_RESP_SENT or RESP_SENT
506 *
507 *****************************************************************************/
508int _process_node_cmd(cmd_resp_hdr_t* cmd_hdr, eth_tx_queue_buffer_t* eth_tx_queue_buffer) {
509
510    //
511    // IMPORTANT ENDIAN NOTES:
512    //     - command
513    //         - header - Already endian swapped by the framework (safe to access directly)
514    //         - args   - Must be endian swapped as necessary by code (framework does not know the contents of the command)
515    //     - response
516    //         - header - Will be endian swapped by the framework (safe to write directly)
517    //         - args   - Must be endian swapped as necessary by code (framework does not know the contents of the response)
518    //
519
520    int resp_sent = NO_RESP_SENT;
521    cmd_resp_hdr_t* resp_hdr = NULL;
522
523    u32 cmd_id = CMD_TO_CMDID(cmd_hdr->cmd);
524
525    // Segment 0 length includes a fully formed command response header
526    //  because one was created with default values suitable for a responseless
527    //  acknowledgment.
528    resp_hdr = (cmd_resp_hdr_t*)(eth_tx_queue_buffer->seg0
529                                                 + eth_tx_queue_buffer->seg0_len
530                                                 - sizeof(cmd_resp_hdr_t));
531
532    // We explicitly zero response header fields here so commands that don't need
533    // any u32 argument responses do not have have to touch the header
534    // resp_hdr->cmd_id has already been set in the calling context, copied from the received command
535    resp_hdr->length = 0;
536    resp_hdr->num_u32_args = 0;
537
538    u32* cmd_args_32 = (u32*)((u8*)cmd_hdr + sizeof(cmd_resp_hdr_t));
539
540    // Process the command
541    switch(cmd_id){
542
543//-----------------------------------------------------------------------------
544// General Commands
545//-----------------------------------------------------------------------------
546
547        //---------------------------------------------------------------------
548        case CMDID_NODE_TYPE: {
549            wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, wlan_mac_hw_info.platform_id);
550            wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, wlan_exp_node_info.high_sw_id);
551            wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, wlan_exp_node_info.low_sw_id);
552        }
553        break;
554       
555   
556        //---------------------------------------------------------------------
557        case CMDID_NODE_INFO: {
558            int platform_info_size;
559            u32 resp_size;
560            u8* dest_ptr;
561
562            dest_ptr = eth_tx_queue_buffer->seg0 + eth_tx_queue_buffer->seg0_len;
563
564            // First, copy the platform-independent wlan_exp_node_info struct into the response packet
565            memcpy(dest_ptr, &wlan_exp_node_info, sizeof(wlan_exp_node_info_t));
566            dest_ptr += sizeof(wlan_exp_node_info_t);
567
568            // Second, ask the platform to copy in its platform-specific info struct into the response packet
569            platform_info_size = wlan_platform_high_copy_info(dest_ptr);
570
571            // Finalize response
572            resp_size = sizeof(wlan_exp_node_info_t) + platform_info_size;
573            resp_hdr->length  += resp_size;
574            eth_tx_queue_buffer->seg0_len += resp_size;
575        }
576        break;
577       
578
579        //---------------------------------------------------------------------
580        case CMDID_NODE_IDENTIFY: {
581            // Blink the HEX display LEDs
582            //   - cmd_args_32[0] - Platform ID
583            //   - cmd_args_32[1] - Serial Number
584            u32 platform_id;
585            u32 serial_number;
586
587            // Get command parameters
588            platform_id = Xil_Ntohl(cmd_args_32[0]);
589            serial_number = Xil_Ntohl(cmd_args_32[1]);
590
591            xil_printf("NODE IDENTIFY: \n");
592
593            if( ((serial_number == CMD_PARAM_NODE_IDENTIFY_ALL) || (serial_number == wlan_mac_hw_info.serial_number)) &&
594                ((platform_id == CMD_PARAM_NODE_IDENTIFY_ALL) || (platform_id == wlan_mac_hw_info.platform_id)) ){
595
596                // Print Node information
597                xil_printf("    Node: %d\n", wlan_exp_node_info.node_id);
598
599                // Send the response early so that code does not time out while waiting for blinks
600                //   The host is responsible for waiting until the LED blinking is done before issuing the
601                //   node another command.
602                wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, CMD_PARAM_SUCCESS);
603
604                if(serial_number != CMD_PARAM_NODE_IDENTIFY_ALL){
605                    _send_response(resp_hdr, eth_tx_queue_buffer, 1);
606                    resp_sent = RESP_SENT;
607                }
608
609                wlan_platform_high_userio_disp_status(USERIO_DISP_STATUS_IDENTIFY, 0);
610
611            } else {
612                wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, CMD_PARAM_ERROR);
613            }
614        }
615        break;
616
617
618        //---------------------------------------------------------------------
619        case CMDID_NODE_CONFIG_SETUP: {
620            // NODE_CONFIG_SETUP Packet Format:
621            //   - Note:  All u32 parameters in cmd_args_32 are byte swapped so use Xil_Ntohl()
622            //
623            //   - cmd_args_32[0] - Platform ID
624            //   - cmd_args_32[1] - Serial Number
625            //   - cmd_args_32[2] - Node ID
626            //   - cmd_args_32[3] - IP Address
627            //   - cmd_args_32[4] - Unicast Port
628            //   - cmd_args_32[5] - Broadcast Port
629            //
630            int status;
631            u32 node_id;
632            int unicast_port, broadcast_port;
633            u8 ip_addr[IP_ADDR_LEN];
634
635            u32 serial_number;
636            u32 platform_id;
637
638            platform_id = Xil_Ntohl(cmd_args_32[0]);
639            serial_number = Xil_Ntohl(cmd_args_32[1]);
640
641            if( (serial_number == wlan_mac_hw_info.serial_number) &&
642                (platform_id == wlan_mac_hw_info.platform_id) ){
643
644                // Set Node ID
645                //   NOTE:  We need to set the node ID in both the node info and the eth_dev_info
646                //
647                node_id = Xil_Ntohl(cmd_args_32[2]) & 0xFFFF;
648                wlan_exp_node_info.node_id = node_id;
649
650                // Get New IP Address
651                ip_addr[0] = (Xil_Ntohl(cmd_args_32[3]) >> 24) & 0xFF;
652                ip_addr[1] = (Xil_Ntohl(cmd_args_32[3]) >> 16) & 0xFF;
653                ip_addr[2] = (Xil_Ntohl(cmd_args_32[3]) >>  8) & 0xFF;
654                ip_addr[3] = (Xil_Ntohl(cmd_args_32[3])      ) & 0xFF;
655
656                // Get new ports
657                unicast_port = Xil_Ntohl(cmd_args_32[4]);
658                broadcast_port = Xil_Ntohl(cmd_args_32[5]);
659
660                // Set Transport IP Addresses / Ports
661                transport_set_ip_addr(ip_addr);
662
663                status = transport_config_sockets(unicast_port, broadcast_port);
664
665                if(status != 0) {
666                    xil_printf("Error binding transport...\n");
667                } else {
668                    // Print new configuration information
669                    xil_printf("NODE_CONFIG_SETUP: Configured wlan_exp with node ID %d, ", wlan_exp_node_info.node_id);
670                    xil_printf("IP address %d.%d.%d.%d\n", ip_addr[0], ip_addr[1], ip_addr[2], ip_addr[3]);
671
672                    // Set right decimal point to indicate WLAN Exp network is configured
673                    wlan_platform_high_userio_disp_status(USERIO_DISP_STATUS_WLAN_EXP_CONFIGURE, 1);
674                }
675            }
676        }
677        break;
678
679        //---------------------------------------------------------------------
680        case CMDID_NODE_CONFIG_RESET: {
681            // NODE_CONFIG_RESET Packet Format:
682            //   - Note:  All u32 parameters in cmd_args_32 are byte swapped so use Xil_Ntohl()
683            //
684            //   - cmd_args_32[i] - Platform ID
685            //   - cmd_args_32[1] - Serial Number
686            //
687            // This command is always handed as non-robust - the node never sends a response packet, since the whole
688            //  purpose of this command is to reset the node's network configuration. Python only sends this command
689            //  via the (inherently non-robust) multicast transport
690
691            u32 platform_id;
692            u32 serial_number;
693            u8 ip_addr[IP_ADDR_LEN];
694           
695            platform_id = Xil_Ntohl(cmd_args_32[0]);
696            serial_number = Xil_Ntohl(cmd_args_32[1]);
697
698            if( ((serial_number == CMD_PARAM_NODE_CONFIG_RESET_ALL) || (serial_number == wlan_mac_hw_info.serial_number)) &&
699                ((platform_id == CMD_PARAM_NODE_CONFIG_RESET_ALL) || (platform_id == wlan_mac_hw_info.platform_id)) ){
700
701                // Reset node to 0xFFFF
702                //   NOTE:  We need to set the node ID in both the node info and the eth_dev_info
703                //
704                wlan_exp_node_info.node_id = 0xFFFF;
705
706                ip_addr[0] = (WLAN_EXP_DEFAULT_IP_ADDR >> 24) & 0xFF;
707                ip_addr[1] = (WLAN_EXP_DEFAULT_IP_ADDR >> 16) & 0xFF;
708                ip_addr[2] = (WLAN_EXP_DEFAULT_IP_ADDR >>  8) & 0xFF;
709                ip_addr[3] = (WLAN_EXP_DEFAULT_IP_ADDR      ) & 0xFF;  // IP ADDR = w.x.y.z
710
711                transport_set_ip_addr(ip_addr);
712                transport_config_sockets(WLAN_EXP_DEFAULT_UDP_UNICAST_PORT, WLAN_EXP_DEFAULT_UDP_MULTICAST_PORT);
713                transport_set_max_resp_pkt_words(WLAN_EXP_DEFAULT_MAX_PACKET_WORDS);
714
715                // Print information
716                xil_printf("NODE_CONFIG_RESET: Reset wlan_exp network config\n");
717
718                // Clear right decimal point to indicate WLAN Exp network is not configured
719                wlan_platform_high_userio_disp_status(USERIO_DISP_STATUS_WLAN_EXP_CONFIGURE, 0);
720
721            }
722        }
723        break;
724
725
726        //---------------------------------------------------------------------
727        case CMDID_NODE_TEMPERATURE: {
728
729            // NODE_TEMPERATURE
730            //   - If the system monitor exists, return the current, min and max temperature of the node
731            //
732            wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, wlan_platform_get_current_temp());
733            wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, wlan_platform_get_min_temp());
734            wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, wlan_platform_get_max_temp());
735        }
736        break;
737
738
739//-----------------------------------------------------------------------------
740// Log Commands
741//-----------------------------------------------------------------------------
742
743
744        //---------------------------------------------------------------------
745        case CMDID_LOG_CONFIG: {
746#if WLAN_SW_CONFIG_ENABLE_LOGGING
747            // NODE_LOG_CONFIG Packet Format:
748            //   - cmd_args_32[0]  - flags
749            //                     [ 0] - Logging Enabled = 1; Logging Disabled = 0;
750            //                     [ 1] - Wrap = 1; No Wrap = 0;
751            //                     [ 2] - Full Payloads Enabled = 1; Full Payloads Disabled = 0;
752            //                     [ 3] - Log WN Cmds Enabled = 1; Log WN Cmds Disabled = 0;
753            //   - cmd_args_32[1]  - mask for flags
754            //
755            //   - resp_args_32[0] - CMD_PARAM_SUCCESS
756            //                     - CMD_PARAM_ERROR
757            //
758            int    status     = CMD_PARAM_SUCCESS;
759            u8     entry_mask = wlan_exp_log_get_entry_en_mask();
760            u32    flags      = Xil_Ntohl(cmd_args_32[0]);
761            u32    mask       = Xil_Ntohl(cmd_args_32[1]);
762
763            wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_event_log, "Configure flags = 0x%08x  mask = 0x%08x\n", flags, mask);
764
765            // Configure the LOG based on the flag bit / mask
766            if (mask & CMD_PARAM_LOG_CONFIG_FLAG_LOGGING) {
767                if (flags & CMD_PARAM_LOG_CONFIG_FLAG_LOGGING) {
768                    event_log_config_logging(EVENT_LOG_LOGGING_ENABLE);
769                } else {
770                    event_log_config_logging(EVENT_LOG_LOGGING_DISABLE);
771                }
772            }
773
774            if (mask & CMD_PARAM_LOG_CONFIG_FLAG_WRAP) {
775                if (flags & CMD_PARAM_LOG_CONFIG_FLAG_WRAP) {
776                    event_log_config_wrap(EVENT_LOG_WRAP_ENABLE);
777                } else {
778                    event_log_config_wrap(EVENT_LOG_WRAP_DISABLE);
779                }
780            }
781
782            if (mask & CMD_PARAM_LOG_CONFIG_FLAG_PAYLOADS) {
783                if (flags & CMD_PARAM_LOG_CONFIG_FLAG_PAYLOADS) {
784                    wlan_exp_log_set_mac_payload_len(MAX_MAC_PAYLOAD_LOG_LEN);
785                } else {
786                    wlan_exp_log_set_mac_payload_len(MIN_MAC_PAYLOAD_LOG_LEN);
787                }
788            }
789
790            if (mask & CMD_PARAM_LOG_CONFIG_FLAG_TXRX_MPDU) {
791                if (flags & CMD_PARAM_LOG_CONFIG_FLAG_TXRX_MPDU) {
792                    entry_mask |= ENTRY_EN_MASK_TXRX_MPDU;
793                } else {
794                    entry_mask &= ~ENTRY_EN_MASK_TXRX_MPDU;
795                }
796            }
797
798            if (mask & CMD_PARAM_LOG_CONFIG_FLAG_TXRX_CTRL) {
799                if (flags & CMD_PARAM_LOG_CONFIG_FLAG_TXRX_CTRL) {
800                    entry_mask |= ENTRY_EN_MASK_TXRX_CTRL;
801                } else {
802                    entry_mask &= ~ENTRY_EN_MASK_TXRX_CTRL;
803                }
804            }
805
806            wlan_exp_log_set_entry_en_mask(entry_mask);
807
808            // Send response of status
809            wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, status);
810#endif //WLAN_SW_CONFIG_ENABLE_LOGGING
811        }
812        break;
813
814
815        //---------------------------------------------------------------------
816        case CMDID_LOG_GET_STATUS: {
817#if WLAN_SW_CONFIG_ENABLE_LOGGING
818            // NODE_LOG_GET_INFO Packet Format:
819            //   - resp_args_32[0] - Next empty entry index
820            //   - resp_args_32[1] - Oldest empty entry index
821            //   - resp_args_32[2] - Number of wraps
822            //   - resp_args_32[3] - Flags
823            //                         [0] - Log enabled
824            //                         [1] - Log wrapping enabled
825            //                         [2] - Log full payloads enabled
826            //                         [3] - Log Tx / Rx MPDU frames enabled
827            //                         [4] - Log Tx / Rx CTRL frames enabled
828            //
829            u32 flags         = event_log_get_flags();
830            u32 log_length    = wlan_exp_log_get_mac_payload_len();
831            u8  entry_en_mask = wlan_exp_log_get_entry_en_mask();
832
833            if (log_length == MAX_MAC_PAYLOAD_LOG_LEN) {
834                flags |= CMD_PARAM_LOG_CONFIG_FLAG_PAYLOADS;
835            }
836
837            if (entry_en_mask & ENTRY_EN_MASK_TXRX_MPDU) {
838                flags |= CMD_PARAM_LOG_CONFIG_FLAG_TXRX_MPDU;
839            }
840
841            if (entry_en_mask & ENTRY_EN_MASK_TXRX_CTRL) {
842                flags |= CMD_PARAM_LOG_CONFIG_FLAG_TXRX_CTRL;
843            }
844
845            // Set response
846            wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, event_log_get_next_entry_index());
847            wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, event_log_get_oldest_entry_index());
848            wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, event_log_get_num_wraps());
849            wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, flags);
850#endif //WLAN_SW_CONFIG_ENABLE_LOGGING
851        }
852        break;
853
854
855        //---------------------------------------------------------------------
856        case CMDID_LOG_GET_CAPACITY: {
857#if WLAN_SW_CONFIG_ENABLE_LOGGING
858            // NODE_LOG_GET_CAPACITY Packet Format:
859            //   - resp_args_32[0] - Max log size
860            //   - resp_args_32[1] - Current log size
861            //
862            wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, event_log_get_capacity());
863            wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, event_log_get_total_size());
864#endif //WLAN_SW_CONFIG_ENABLE_LOGGING
865        }
866        break;
867
868
869        //---------------------------------------------------------------------
870        case CMDID_LOG_GET_ENTRIES: {
871#if WLAN_SW_CONFIG_ENABLE_LOGGING
872            // NODE_LOG_GET_ENTRIES Packet Format:
873            //   - Note:  All u32 parameters in cmd_args_32 are byte swapped so use Xil_Ntohl()
874            //
875            //   - cmd_args_32[0] - start_address of transfer
876            //   - cmd_args_32[1] - size of transfer (in bytes)
877            //                      0xFFFF_FFFF  -> Get everything in the event log
878            //
879            //   Return Value:
880            //   - bytes_remaining - uint32  - Number of bytes remaining in the transfer
881            //   - start_byte      - uint32  - Byte index of the first byte in this packet
882            //   - size            - uint32  - Number of payload bytes in this packet
883            //   - byte[]          - uint8[] - Array of payload bytes
884            //
885            // NOTE:  The address passed via the command is the address relative to the current
886            //   start of the event log.  It is not an absolute address and should not be treated
887            //   as such.
888            //
889            //     When you transfer "everything" in the event log, the command will take a
890            //   snapshot of the size of the log to the "end" at the time the command is received
891            //   (ie either the next_entry_index or the end of the log before it wraps).  It will then
892            //   only transfer those events.  It will not any new events that are added to the log while
893            //   we are transferring the current log as well as transfer any events after a wrap.
894            //
895
896            u32 start_index = Xil_Ntohl(cmd_args_32[0]);
897            u32 size = Xil_Ntohl(cmd_args_32[1]);
898            u32 event_log_size = event_log_get_size(start_index);
899
900            // Check if we should transfer everything or if the request was larger than the current log
901            if ((size == CMD_PARAM_LOG_GET_ALL_ENTRIES) || (size > event_log_size)) {
902                size = event_log_size;
903            }
904
905            // Transfer data to host
906            resp_sent = _transfer_log_data(eth_tx_queue_buffer, start_index, size);
907
908#endif //WLAN_SW_CONFIG_ENABLE_LOGGING
909        }
910        break;
911
912
913        //---------------------------------------------------------------------
914        case CMDID_LOG_ADD_EXP_INFO_ENTRY: {
915#if WLAN_SW_CONFIG_ENABLE_LOGGING
916            // Add EXP_INFO entry to the log
917            //
918            // Message format:
919            //     cmd_args_32[0]   info_type (lower 16 bits)
920            //     cmd_args_32[1]   msg_len (255 bytes max enforced in Python)
921            // Payload:
922            //     Arbitrary message payload, msg_len bytes
923
924            exp_info_entry* exp_info;
925            u32 entry_size;
926            u32 info_type = Xil_Ntohl(cmd_args_32[0]);
927            u32 msg_len = Xil_Ntohl(cmd_args_32[1]);
928            u8* msg_ptr = (u8*)&cmd_args_32[2];
929
930            int msg_len_words;
931
932            if(msg_len > 255) {
933                xil_printf("WARNING: truncating EXP_INFO_ENTRY msg_len from %d to 255\n", msg_len);
934                msg_len = 255;
935            }
936
937            // Compute the total entry size, required to allocate the log entry
938            if (msg_len == 0) {
939                entry_size = sizeof(exp_info_entry);
940            } else {
941                // 32-bit align msg_len; not strictly required, but helps keep
942                //  later log entries aligned to u32 boundaries for quicker DMA'ing
943                msg_len_words = msg_len/4;
944                if(msg_len_words*4 < msg_len) msg_len_words++;
945
946                entry_size = sizeof(exp_info_entry) + msg_len_words*4;
947            }
948
949            exp_info = (exp_info_entry *)wlan_exp_log_create_entry(ENTRY_TYPE_EXP_INFO, entry_size);
950
951            if (exp_info != NULL) {
952                wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_event_log,
953                                "Adding EXP INFO entry with type %d, msg_len %d to log\n", info_type, msg_len);
954                xil_printf("Adding EXP INFO entry with type %d, msg_len %d to log\n", info_type, msg_len);
955
956                exp_info->timestamp   = get_mac_time_usec();
957                exp_info->info_type   = info_type;
958                exp_info->msg_len     = msg_len;
959
960                // Copy the message to the log entry
961                if (msg_len > 0){
962                    // message packed immediately after the EXP_INFO header struct
963                    memcpy((void *)((u8*)&exp_info + sizeof(exp_info_entry)), (void *)msg_ptr, msg_len);
964                }
965            }
966#endif //WLAN_SW_CONFIG_ENABLE_LOGGING
967        }
968        break;
969
970//-----------------------------------------------------------------------------
971// Counts Commands
972//-----------------------------------------------------------------------------
973
974//-----------------------------------------------------------------------------
975// Local Traffic Generator (LTG) Commands
976//-----------------------------------------------------------------------------
977
978
979        //---------------------------------------------------------------------
980        case CMDID_LTG_CONFIG: {
981#if WLAN_SW_CONFIG_ENABLE_LTG
982            // NODE_LTG_START Packet Format:
983            //   - cmd_args_32[0]      - Flags
984            //                           [0] - Auto-start the LTG flow
985            //   - cmd_args_32[1]      - Schedule type
986            //   ---------
987            //   - _ltg_sched_periodic_params_otw or _ltg_sched_uniform_rand_params_otw
988            //   - ltg_pyld_fixed_t, ltg_pyld_uniform_rand_t, ltg_pyld_all_assoc_fixed_t, or ltg_pyld_ctrl_resp_t
989            //
990            //   - resp_args_32[0]     - CMD_PARAM_SUCCESS
991            //                         - CMD_PARAM_ERROR + CMD_PARAM_LTG_ERROR;
992            //
993
994            // The over-the-wire format for the schedule parameters specifies things in units of microseconds.
995            // For architectural reasons, the framework chooses to represent these values in units of counts
996            // of the scheduler clock. This function is responsible for converting the OTW parameters into ones
997            // the framework can understand.
998            typedef struct _ltg_sched_periodic_params_otw{
999                u32 interval_usec;
1000                u64 duration_usec;
1001            } __attribute__((__packed__)) _ltg_sched_periodic_params_otw;
1002            ASSERT_TYPE_SIZE(_ltg_sched_periodic_params_otw, 12);
1003
1004
1005            // Note: count variables are in units of FAST_TIMER_DUR_US
1006            typedef struct _ltg_sched_uniform_rand_params_otw{
1007                u32 min_interval_usec;
1008                u32 max_interval_usec;
1009                u64 duration_usec;
1010            } __attribute__((__packed__)) _ltg_sched_uniform_rand_params_otw;
1011            ASSERT_TYPE_SIZE(_ltg_sched_uniform_rand_params_otw, 16);
1012
1013            u8* ltg_payload_cmd;
1014            u8* ltg_sched_cmd;
1015
1016            int ltg_payload_size;
1017            int ltg_sched_size;
1018
1019            u8* ltg_payload = NULL;
1020
1021            // Since there are only two schedules, we'll skip a round of malloc/free by reserving space for
1022            //  the larger of the two schedules in the stack.
1023            u8 ltg_sched_arr[WLAN_MAX(sizeof(ltg_sched_periodic_params_t), sizeof(ltg_sched_uniform_rand_params_t))];
1024            u8* ltg_sched = &(ltg_sched_arr[0]);
1025
1026            u32 status = CMD_PARAM_SUCCESS;
1027            u32 id = LTG_ID_INVALID;
1028
1029            u32 flags = Xil_Ntohl(cmd_args_32[0]);
1030            u32 schedule_type = Xil_Ntohl(cmd_args_32[1]);
1031
1032            // Lay struct stencils on top of command payload
1033            // and check validity of parameters.
1034
1035            ltg_sched_cmd = (u8*)(&cmd_args_32[cmd_hdr->num_u32_args]);
1036
1037            switch(schedule_type){
1038                case LTG_SCHED_TYPE_PERIODIC:
1039                    ltg_sched_size = sizeof(_ltg_sched_periodic_params_otw);
1040                    ((ltg_sched_periodic_params_t*)ltg_sched)->duration_count = \
1041                            (((_ltg_sched_periodic_params_otw*)ltg_sched_cmd)->duration_usec / platform_high_dev_info.timer_dur_us);
1042                    ((ltg_sched_periodic_params_t*)ltg_sched)->interval_count = \
1043                            (((_ltg_sched_periodic_params_otw*)ltg_sched_cmd)->interval_usec / platform_high_dev_info.timer_dur_us);
1044                break;
1045                case LTG_SCHED_TYPE_UNIFORM_RAND:
1046                    ltg_sched_size = sizeof(_ltg_sched_uniform_rand_params_otw);
1047                    ((ltg_sched_uniform_rand_params_t*)ltg_sched)->duration_count = \
1048                            (((_ltg_sched_uniform_rand_params_otw*)ltg_sched_cmd)->duration_usec / platform_high_dev_info.timer_dur_us);
1049                    ((ltg_sched_uniform_rand_params_t*)ltg_sched)->max_interval_count = \
1050                            (((_ltg_sched_uniform_rand_params_otw*)ltg_sched_cmd)->max_interval_usec / platform_high_dev_info.timer_dur_us);
1051                    ((ltg_sched_uniform_rand_params_t*)ltg_sched)->min_interval_count = \
1052                            (((_ltg_sched_uniform_rand_params_otw*)ltg_sched_cmd)->min_interval_usec / platform_high_dev_info.timer_dur_us);
1053                break;
1054                default:
1055                    ltg_sched_size = -1;
1056                break;
1057            } // switch(schedule_type)
1058
1059            if(ltg_sched_size > 0){
1060                ltg_payload_cmd = ltg_sched_cmd + ltg_sched_size;
1061
1062                switch(((ltg_pyld_hdr_t*)ltg_payload_cmd)->type){
1063                    case LTG_PYLD_TYPE_FIXED:
1064                        ltg_payload_size = sizeof(ltg_pyld_fixed_t);
1065                    break;
1066                    case LTG_PYLD_TYPE_UNIFORM_RAND:
1067                        ltg_payload_size = sizeof(ltg_pyld_uniform_rand_t);
1068                    break;
1069                    case LTG_PYLD_TYPE_ALL_ASSOC_FIXED:
1070                        ltg_payload_size = sizeof(ltg_pyld_all_assoc_fixed_t);
1071                    break;
1072                    case LTG_PYLD_TYPE_CTRL_RESP:
1073                        ltg_payload_size = sizeof(ltg_pyld_ctrl_resp_t);
1074
1075                    break;
1076                    default:
1077                        ltg_payload_size = -1;
1078                    break;
1079                } // switch(((ltg_pyld_hdr_t*)ltg_payload_cmd)->type)
1080            } // if(ltg_sched_size > 0)
1081
1082
1083            if((ltg_sched_size > 0) && (ltg_payload_size > 0)){
1084                // We know we have both a valid LTG schedule and payload type, so we can continue processing.
1085                // The bytes in the command payload are transient -- after we leave this context they will be gone.
1086                // The framework will make its own copy of schedule parameters, but we need to make sure that
1087                // the payload parameters survive the duration of the LTG. So, we need to copy them into the heap.
1088
1089                ltg_payload = wlan_mac_high_malloc(ltg_payload_size);
1090                if(ltg_payload) {
1091                    memcpy(ltg_payload, ltg_payload_cmd, ltg_payload_size);
1092
1093                    // Configure the LTG
1094                    id = ltg_sched_create(schedule_type, ltg_sched, ltg_payload, &_ltg_cleanup);
1095
1096                    if(id != LTG_ID_INVALID){
1097                        wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_ltg, "Configured %d\n", id);
1098
1099                        if (flags & CMD_PARAM_LTG_CONFIG_FLAG_AUTOSTART) {
1100                            wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_ltg, "Starting %d\n", id);
1101                            ltg_sched_start( id );
1102                        }
1103                    } else {
1104                        status = CMD_PARAM_ERROR + CMD_PARAM_LTG_ERROR;
1105                        wlan_exp_printf(WLAN_EXP_PRINT_ERROR, print_type_ltg, "Could not create LTG\n");
1106                        wlan_mac_high_free(ltg_payload);
1107                    }
1108                } else {
1109                    status = CMD_PARAM_ERROR + CMD_PARAM_LTG_ERROR;
1110                    wlan_exp_printf(WLAN_EXP_PRINT_ERROR, print_type_ltg, "Could not allocate memory for CMDID_LTG_CONFIG\n");
1111                } // if((ltg_payload != NULL) && (ltg_sched != NULL))
1112            } else {
1113                status = CMD_PARAM_ERROR + CMD_PARAM_LTG_ERROR;
1114                wlan_exp_printf(WLAN_EXP_PRINT_ERROR, print_type_ltg, "Invalid LTG schedule or payload type\n");
1115            } //  if((ltg_sched_size > 0) && (ltg_payload_size > 0))
1116
1117            // Send response
1118            wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, status);
1119            wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, id);
1120#endif //WLAN_SW_CONFIG_ENABLE_LTG
1121        }
1122        break;
1123
1124
1125        //---------------------------------------------------------------------
1126        case CMDID_LTG_START: {
1127#if WLAN_SW_CONFIG_ENABLE_LTG
1128            // NODE_LTG_START Packet Format:
1129            //   - cmd_args_32[0]      - LTG ID
1130            //
1131            //   - resp_args_32[0]     - CMD_PARAM_SUCCESS
1132            //                         - CMD_PARAM_ERROR + CMD_PARAM_LTG_ERROR;
1133            //
1134            u32 status = CMD_PARAM_SUCCESS;
1135            u32 id = Xil_Ntohl(cmd_args_32[0]);
1136            int ltg_status = ltg_sched_start(id);
1137
1138            if (ltg_status == 0) {
1139                if (id != CMD_PARAM_LTG_ALL_LTGS){
1140                    wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_ltg, "Starting %d\n", id);
1141                } else {
1142                    wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_ltg, "Starting all LTGs\n");
1143                }
1144            } else {
1145                if (id != CMD_PARAM_LTG_ALL_LTGS){
1146                    wlan_exp_printf(WLAN_EXP_PRINT_ERROR, print_type_ltg, "Failed to start %d\n", id);
1147                } else {
1148                    wlan_exp_printf(WLAN_EXP_PRINT_ERROR, print_type_ltg, "Failed to start all LTGs\n");
1149                }
1150                status = CMD_PARAM_ERROR + CMD_PARAM_LTG_ERROR;
1151            }
1152
1153            // Send response of current rate
1154            wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, status);
1155#endif
1156        }
1157        break;
1158
1159
1160        //---------------------------------------------------------------------
1161        case CMDID_LTG_STOP: {
1162#if WLAN_SW_CONFIG_ENABLE_LTG
1163            // NODE_LTG_STOP Packet Format:
1164            //   - cmd_args_32[0]      - LTG ID
1165            //
1166            //   - resp_args_32[0]     - CMD_PARAM_SUCCESS
1167            //                         - CMD_PARAM_ERROR + CMD_PARAM_LTG_ERROR;
1168            //
1169            u32 status = CMD_PARAM_SUCCESS;
1170            u32 id = Xil_Ntohl(cmd_args_32[0]);
1171            int ltg_status = ltg_sched_stop(id);
1172
1173            if (ltg_status == 0) {
1174                if (id != CMD_PARAM_LTG_ALL_LTGS){
1175                    wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_ltg, "Stopping %d\n", id);
1176                } else {
1177                    wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_ltg, "Stopping all LTGs\n");
1178                }
1179            } else {
1180                if (id != CMD_PARAM_LTG_ALL_LTGS){
1181                    wlan_exp_printf(WLAN_EXP_PRINT_ERROR, print_type_ltg, "Failed to stop %d\n", id);
1182                } else {
1183                    wlan_exp_printf(WLAN_EXP_PRINT_ERROR, print_type_ltg, "Failed to stop all LTGs\n");
1184                }
1185                status = CMD_PARAM_ERROR + CMD_PARAM_LTG_ERROR;
1186            }
1187
1188            // Send response of current rate
1189            wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, status);
1190#endif
1191        }
1192        break;
1193
1194
1195        //---------------------------------------------------------------------
1196        case CMDID_LTG_REMOVE: {
1197#if WLAN_SW_CONFIG_ENABLE_LTG
1198            // NODE_LTG_REMOVE Packet Format:
1199            //   - cmd_args_32[0]      - LTG ID
1200            //
1201            //   - resp_args_32[0]     - CMD_PARAM_SUCCESS
1202            //                         - CMD_PARAM_ERROR + CMD_PARAM_LTG_ERROR;
1203            //
1204            u32 status = CMD_PARAM_SUCCESS;
1205            u32 id = Xil_Ntohl(cmd_args_32[0]);
1206            int ltg_status = ltg_sched_remove(id);
1207
1208            if (ltg_status == 0) {
1209                if (id != CMD_PARAM_LTG_ALL_LTGS){
1210                    wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_ltg, "Removing %d\n", id);
1211                } else {
1212                    wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_ltg, "Removing all LTGs\n");
1213                }
1214            } else {
1215                if (id != CMD_PARAM_LTG_ALL_LTGS){
1216                    wlan_exp_printf(WLAN_EXP_PRINT_ERROR, print_type_ltg, "Failed to remove %d\n", id);
1217                } else {
1218                    wlan_exp_printf(WLAN_EXP_PRINT_ERROR, print_type_ltg, "Failed to remove all LTGs\n");
1219                }
1220                status = CMD_PARAM_ERROR + CMD_PARAM_LTG_ERROR;
1221            }
1222
1223            // Send response of status
1224            wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, status);
1225#endif //WLAN_SW_CONFIG_ENABLE_LTG
1226        }
1227        break;
1228
1229
1230        //---------------------------------------------------------------------
1231        case CMDID_LTG_STATUS: {
1232#if WLAN_SW_CONFIG_ENABLE_LTG
1233            // NODE_LTG_STATUS Packet Format:
1234            //   - cmd_args_32[0]      - LTG ID
1235            //
1236            //   - resp_args_32[0]     - CMD_PARAM_SUCCESS
1237            //                         - CMD_PARAM_ERROR + CMD_PARAM_LTG_ERROR;
1238            //   - resp_args_32[1]     - CMD_PARAM_LTG_RUNNING
1239            //                         - CMD_PARAM_LTG_STOPPED
1240            //   - resp_args_32[3:2]   - Last start timestamp
1241            //   - resp_args_32[5:4]   - Last stop timestamp
1242            //
1243            u32 i;
1244            u32* state;
1245            dl_entry* curr_tg_dl_entry;
1246            u32 status = CMD_PARAM_SUCCESS;
1247            u32 id = Xil_Ntohl(cmd_args_32[0]);
1248            u32 max_args = sizeof(ltg_sched_state_hdr_t) / 4;      // Maximum number of return args
1249
1250            curr_tg_dl_entry = ltg_sched_find_tg_schedule(id);
1251
1252            if(curr_tg_dl_entry != NULL){
1253                state  = (u32 *)((tg_schedule*)(curr_tg_dl_entry->data))->state;
1254            } else {
1255                status = CMD_PARAM_ERROR + CMD_PARAM_LTG_ERROR;
1256            }
1257
1258            // Send response of status
1259            wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, status);
1260
1261            if(curr_tg_dl_entry != NULL){
1262                for (i = 0; i < max_args; i++) {
1263                    wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, state[i]);
1264                }
1265            } else {
1266                for (i = 0; i < max_args; i++) {
1267                    wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, 0xFFFFFFFF);
1268                }
1269            }
1270#endif //WLAN_SW_CONFIG_ENABLE_LTG
1271        }
1272        break;
1273
1274
1275//-----------------------------------------------------------------------------
1276// Node Commands
1277//-----------------------------------------------------------------------------
1278
1279        //---------------------------------------------------------------------
1280       case CMDID_NODE_CHANNEL: {
1281           //   - cmd_args_32[0]      - Command
1282           //   - cmd_args_32[1]      - Channel
1283           //
1284           u32 status = CMD_PARAM_SUCCESS;
1285           u32 msg_cmd = Xil_Ntohl(cmd_args_32[0]);
1286           u32 channel = Xil_Ntohl(cmd_args_32[1]);
1287
1288           if (msg_cmd == CMD_PARAM_WRITE_VAL) {
1289               // Set the Channel
1290               if (wlan_verify_channel(channel) == 0){
1291
1292                   wlan_mac_high_set_radio_channel(channel);
1293
1294                   wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_node, "Set Channel = %d\n", channel);
1295
1296               } else {
1297                   status  = CMD_PARAM_ERROR;
1298                   wlan_exp_printf(WLAN_EXP_PRINT_ERROR, print_type_node,
1299                                   "Channel %d is not supported by the node.\n", channel);
1300               }
1301           }
1302
1303           // Send response
1304           wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, status);
1305           wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, low_param_channel);
1306       }
1307       break;
1308
1309
1310        //---------------------------------------------------------------------
1311        // CMDID_NODE_RESET_STATE implemented in child classes
1312        //
1313
1314
1315        //---------------------------------------------------------------------
1316        case CMDID_NODE_CONFIGURE: {
1317            // CMDID_NODE_CONFIGURE Packet Format:
1318            //   - cmd_args_32[0]  - Flags
1319            //                     [0] - NODE_CONFIG_FLAG_DSSS_ENABLE
1320            //                     [1] - NODE_CONFIG_FLAG_
1321            //   - cmd_args_32[1]  - Flag mask
1322            //   - cmd_args_32[2]  - WLAN Exp debug level
1323            //                     [31]  - Set debug level
1324            //                     [7:0] - Debug level
1325            //
1326            u32 status = CMD_PARAM_SUCCESS;
1327            u32 flags = Xil_Ntohl(cmd_args_32[0]);
1328            u32 mask = Xil_Ntohl(cmd_args_32[1]);
1329            u32 debug_level = Xil_Ntohl(cmd_args_32[2]);
1330
1331            wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_node, "Configure flags = 0x%08x  mask = 0x%08x\n", flags, mask);
1332
1333            // Set DSS Enable / Disable
1334            if (mask & CMD_PARAM_NODE_CONFIG_FLAG_DSSS_ENABLE) {
1335                if (flags & CMD_PARAM_NODE_CONFIG_FLAG_DSSS_ENABLE) {
1336                    wlan_mac_high_set_dsss(0x1);
1337                    wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_node, "Enabled DSSS\n");
1338                } else {
1339                    wlan_mac_high_set_dsss(0x0);
1340                    wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_node, "Disabled DSSS\n");
1341                }
1342            }
1343
1344            // Set MAC time update from beacon Enable / Disable
1345            if (mask & CMD_PARAM_NODE_CONFIG_FLAG_BEACON_TIME_UPDATE) {
1346                if (flags & CMD_PARAM_NODE_CONFIG_FLAG_BEACON_TIME_UPDATE) {
1347                    wlan_exp_beacon_ts_update_mode_callback(1);
1348                    wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_node, "Enable MAC time update from beacons\n");
1349                } else {
1350                    wlan_exp_beacon_ts_update_mode_callback(0);
1351                    wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_node, "Disabled MAC time update from beacons\n");
1352                }
1353            }
1354
1355            // Set debug print level
1356            if (debug_level & CMD_PARAM_NODE_CONFIG_SET_WLAN_EXP_PRINT_LEVEL) {
1357                wlan_exp_set_print_level(debug_level & 0xFF);
1358            }
1359
1360#if WLAN_SW_CONFIG_ENABLE_ETH_BRIDGE
1361            // Set Eth A portal behavior
1362            if (mask & CMD_PARAM_NODE_CONFIG_FLAG_ETH_PORTAL) {
1363                if (flags & CMD_PARAM_NODE_CONFIG_FLAG_ETH_PORTAL) {
1364                    wlan_eth_portal_en(1);
1365                    wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_node, "Enable ETH A Portal\n");
1366                } else {
1367                    wlan_eth_portal_en(0);
1368                    wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_node, "Disable ETH A Portal\n");
1369                }
1370
1371            }
1372#endif
1373
1374            // Send response of status
1375            wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, status);
1376        }
1377        break;
1378
1379        //---------------------------------------------------------------------
1380        case CMDID_NODE_TIME: {
1381            // Set / Get node time
1382            //
1383            // Message format:
1384            //     cmd_args_32[0]   Command:
1385            //                      - Write                (NODE_WRITE_VAL)
1386            //                      - Read                 (NODE_READ_VAL)
1387            //                      - Add to log           (NODE_TIME_ADD_TO_LOG_VAL)
1388            //                      - Add to log on change (NODE_TIME_ADD_ON_CHANGE)
1389            //     cmd_args_32[1]   Time ID
1390            //     cmd_args_32[2]   New MAC Time in microseconds - lower 32 bits (or NODE_TIME_RSVD_VAL)
1391            //     cmd_args_32[3]   New MAC Time in microseconds - upper 32 bits (or NODE_TIME_RSVD_VAL)
1392            //     cmd_args_32[4]   Host Time in microseconds    - lower 32 bits (or NODE_TIME_RSVD_VAL)
1393            //     cmd_args_32[5]   Host Time in microseconds    - upper 32 bits (or NODE_TIME_RSVD_VAL)
1394            //
1395            // Response format:
1396            //     resp_args_32[0]  Status
1397            //     resp_args_32[1]  MAC Time on node in microseconds    - lower 32 bits
1398            //     resp_args_32[2]  MAC Time on node in microseconds    - upper 32 bits
1399            //     resp_args_32[3]  System Time on node in microseconds - lower 32 bits
1400            //     resp_args_32[4]  System Time on node in microseconds - upper 32 bits
1401            //
1402            u32 temp_lo, temp_hi;
1403            u32 status = CMD_PARAM_SUCCESS;
1404            u32 msg_cmd = Xil_Ntohl(cmd_args_32[0]);
1405#if WLAN_SW_CONFIG_ENABLE_LOGGING
1406            u32 id = Xil_Ntohl(cmd_args_32[1]);
1407            u64 host_timestamp;
1408#endif //WLAN_SW_CONFIG_ENABLE_LOGGING
1409
1410            u64 new_mac_time;
1411            u64 mac_timestamp = get_mac_time_usec();
1412            u64 system_timestamp = get_system_time_usec();
1413
1414            switch (msg_cmd) {
1415                case CMD_PARAM_WRITE_VAL:
1416                case CMD_PARAM_NODE_TIME_ADD_TO_LOG_VAL:
1417                    // Get the new time
1418                    temp_lo      = Xil_Ntohl(cmd_args_32[2]);
1419                    temp_hi      = Xil_Ntohl(cmd_args_32[3]);
1420                    new_mac_time = (((u64)temp_hi) << 32) + ((u64)temp_lo);
1421
1422                    // If this is a write, then update the time on the node
1423                    if (msg_cmd == CMD_PARAM_WRITE_VAL){
1424                        set_mac_time_usec(new_mac_time);
1425                        wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_node, "Set time  = 0x%08x 0x%08x\n", temp_hi, temp_lo);
1426                    }
1427
1428                    // Get the Host time
1429                    temp_lo        = Xil_Ntohl(cmd_args_32[4]);
1430                    temp_hi        = Xil_Ntohl(cmd_args_32[5]);
1431
1432                    wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_node, "Host time = 0x%08x 0x%08x\n", temp_hi, temp_lo);
1433#if WLAN_SW_CONFIG_ENABLE_LOGGING
1434                    host_timestamp = (((u64)temp_hi) << 32) + ((u64)temp_lo);
1435                    // Add a time info log entry
1436                    if (msg_cmd == CMD_PARAM_WRITE_VAL) {
1437                        add_time_info_entry(mac_timestamp, new_mac_time, system_timestamp, host_timestamp, TIME_INFO_ENTRY_WLAN_EXP_SET_TIME, id, WLAN_EXP_TRUE);
1438                    } else {
1439                        add_time_info_entry(mac_timestamp, new_mac_time, system_timestamp, host_timestamp, TIME_INFO_ENTRY_WLAN_EXP_ADD_LOG, id, WLAN_EXP_TRUE);
1440                    }
1441#endif //WLAN_SW_CONFIG_ENABLE_LOGGING
1442
1443                    // If this was a write, then update the time value so we can return it to the host
1444                    //   This is done after the log entry to the fields are correct in the entry.
1445                    if (msg_cmd == CMD_PARAM_WRITE_VAL){
1446                        mac_timestamp = new_mac_time;
1447                    }
1448                break;
1449
1450                case CMD_PARAM_READ_VAL:
1451                break;
1452
1453                default:
1454                    wlan_exp_printf(WLAN_EXP_PRINT_ERROR, print_type_node, "Unknown command for 0x%6x: %d\n", cmd_id, msg_cmd);
1455                    status = CMD_PARAM_ERROR;
1456                break;
1457            }
1458
1459            // Send response
1460            wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, status);
1461
1462            // Add the MAC time to the response
1463            temp_lo = mac_timestamp & 0xFFFFFFFF;
1464            temp_hi = (mac_timestamp >> 32) & 0xFFFFFFFF;
1465
1466            wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, temp_lo);
1467            wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, temp_hi);
1468
1469            // Add the System time to the response
1470            temp_lo = system_timestamp & 0xFFFFFFFF;
1471            temp_hi = (system_timestamp >> 32) & 0xFFFFFFFF;
1472
1473            wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, temp_lo);
1474            wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, temp_hi);
1475
1476        }
1477        break;
1478
1479
1480        //---------------------------------------------------------------------
1481        case CMDID_NODE_LOW_TO_HIGH_FILTER: {
1482            // Set node MAC low to high filter
1483            //
1484            // Message format:
1485            //     cmd_args_32[0]   Command
1486            //     cmd_args_32[1]   RX Filter
1487            //
1488            // Response format:
1489            //     resp_args_32[0]  Status
1490            //
1491            u32 status = CMD_PARAM_SUCCESS;
1492            u32 msg_cmd = Xil_Ntohl(cmd_args_32[0]);
1493            u32 filter_mode = Xil_Ntohl(cmd_args_32[1]);
1494
1495            switch (msg_cmd) {
1496                case CMD_PARAM_WRITE_VAL:
1497                    wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_node, "Set RX filter = 0x%08x\n", filter_mode);
1498                    wlan_mac_high_set_rx_filter_mode(filter_mode);
1499                break;
1500
1501                default:
1502                    wlan_exp_printf(WLAN_EXP_PRINT_ERROR, print_type_node, "Unknown command for 0x%6x: %d\n", cmd_id, msg_cmd);
1503                    status = CMD_PARAM_ERROR;
1504                break;
1505            }
1506
1507            // Send response
1508            wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, status);
1509        }
1510        break;
1511
1512
1513        //---------------------------------------------------------------------
1514        case CMDID_NODE_RANDOM_SEED: {
1515            // Set the random seed for the random number generator for cpu high / low
1516            //
1517            // Message format:
1518            //     cmd_args_32[0]   Command (only writes are supported
1519            //     cmd_args_32[1]   CPU High Seed Valid
1520            //     cmd_args_32[2]   CPU High Seed
1521            //     cmd_args_32[3]   CPU Low  Seed Valid
1522            //     cmd_args_32[4]   CPU Low  Seed
1523            //
1524            // Response format:
1525            //     resp_args_32[0]  Status
1526            //
1527            u32 seed;
1528            u32 seed_valid;
1529            u32 status = CMD_PARAM_SUCCESS;
1530            u32 msg_cmd = Xil_Ntohl(cmd_args_32[0]);
1531
1532            switch (msg_cmd) {
1533                case CMD_PARAM_WRITE_VAL:
1534                    // Process the seed for CPU high
1535                    seed_valid = Xil_Ntohl(cmd_args_32[1]);
1536                    seed       = Xil_Ntohl(cmd_args_32[2]);
1537                    if (seed_valid == CMD_PARAM_RANDOM_SEED_VALID) {
1538                        wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_node, "Set CPU High random seed = 0x%08x\n", seed);
1539                        srand(seed);
1540                    }
1541
1542                    // Process the seed for CPU low
1543                    seed_valid = Xil_Ntohl(cmd_args_32[3]);
1544                    seed       = Xil_Ntohl(cmd_args_32[4]);
1545                    if (seed_valid == CMD_PARAM_RANDOM_SEED_VALID) {
1546                        wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_node, "Set CPU Low  random seed = 0x%08x\n", seed);
1547                        wlan_mac_high_set_srand(seed);
1548                    }
1549                break;
1550
1551                default:
1552                    wlan_exp_printf(WLAN_EXP_PRINT_ERROR, print_type_node, "Unknown command for 0x%6x: %d\n", cmd_id, msg_cmd);
1553                    status = CMD_PARAM_ERROR;
1554                break;
1555            }
1556
1557            // Send response
1558            wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, status);
1559        }
1560        break;
1561
1562
1563        //---------------------------------------------------------------------
1564        case CMDID_NODE_LOW_PARAM: {
1565            // Set node MAC low to high filter
1566            //
1567            // Message format:
1568            //     cmd_args_32[0]    Command
1569            //     cmd_args_32[1]    Size in words of LOW_PARAM_MESSAGE
1570            //     cmd_args_32[2]    LOW_PARAM_MESSAGE
1571            //                       [0]   PARAM_ID
1572            //                         [1:N] ARGS
1573            //
1574            // Response format:
1575            //     resp_args_32[0]    Status
1576            //
1577            u32 i;
1578            u32 id;
1579            u32 status = CMD_PARAM_SUCCESS;
1580            u32 msg_cmd = Xil_Ntohl(cmd_args_32[0]);
1581            u32 size = Xil_Ntohl(cmd_args_32[1]);
1582
1583            // Byte swap all the payload words for the LOW_PARAM_MESSAGE
1584            for (i = 2; i < (size + 2); i++) {
1585                cmd_args_32[i] = Xil_Ntohl(cmd_args_32[i]);
1586            }
1587
1588            id      = cmd_args_32[2];        // Already byte swapped in for loop above
1589
1590            switch (msg_cmd) {
1591                case CMD_PARAM_WRITE_VAL:
1592                    wlan_mac_high_write_low_param(size, &(cmd_args_32[2]));
1593                break;
1594
1595                case CMD_PARAM_READ_VAL:
1596                    wlan_exp_printf(WLAN_EXP_PRINT_ERROR, print_type_node, "Parameter read not allowed.\n");
1597                    status = CMD_PARAM_ERROR + id;
1598                break;
1599
1600                default:
1601                    wlan_exp_printf(WLAN_EXP_PRINT_ERROR, print_type_node, "Unknown command for 0x%6x: %d\n", cmd_id, msg_cmd);
1602                    status = CMD_PARAM_ERROR + id;
1603                break;
1604            }
1605
1606            // Send default response
1607            wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, status);
1608        }
1609        break;
1610
1611
1612        //---------------------------------------------------------------------
1613        case CMDID_NODE_TX_POWER: {
1614            int power;
1615            u8 mac_addr[MAC_ADDR_LEN];
1616            u32 status = CMD_PARAM_SUCCESS;
1617
1618            //Extract arguments
1619            u32 msg_cmd = Xil_Ntohl(cmd_args_32[0]);
1620            u32 frame_type = Xil_Ntohl(cmd_args_32[1]);
1621            u32 update_default_unicast = Xil_Ntohl(cmd_args_32[2]);
1622            u32 update_default_multicast = Xil_Ntohl(cmd_args_32[3]);
1623            u32 power_xmit = Xil_Ntohl(cmd_args_32[4]);
1624            u32 addr_sel = Xil_Ntohl(cmd_args_32[5]);
1625
1626            int iter;
1627            dl_list* station_info_list;
1628            station_info_entry_t* station_info_entry;
1629            station_info_t* station_info;
1630            tx_params_t     tx_params;
1631
1632            // Shift power value from transmission to get the power
1633            power = power_xmit + platform_common_dev_info.tx_power_min_dbm;
1634
1635            // Adjust the power so that it falls in an acceptable range
1636            if(power < platform_common_dev_info.tx_power_min_dbm){ power = platform_common_dev_info.tx_power_min_dbm; }
1637            if(power > platform_common_dev_info.tx_power_max_dbm){ power = platform_common_dev_info.tx_power_max_dbm; }
1638
1639            // Process the command
1640            if( msg_cmd == CMD_PARAM_WRITE_VAL ){
1641                if( frame_type & CMD_PARAM_TXPARAM_MASK_CTRL ){
1642                    wlan_mac_high_set_tx_ctrl_power(power);
1643                }
1644                // 1. Update default values if needed
1645                if(update_default_unicast){
1646                    if(frame_type & CMD_PARAM_TXPARAM_MASK_DATA){
1647                        tx_params = wlan_mac_get_default_tx_params(unicast_data);
1648                        tx_params.phy.power = power;
1649                        wlan_mac_set_default_tx_params(unicast_data, &tx_params);
1650                    }
1651                    if(frame_type & CMD_PARAM_TXPARAM_MASK_MGMT){
1652                        tx_params = wlan_mac_get_default_tx_params(unicast_mgmt);
1653                        tx_params.phy.power = power;
1654                        wlan_mac_set_default_tx_params(unicast_mgmt, &tx_params);
1655                    }
1656                }
1657                if(update_default_multicast){
1658                    if(frame_type & CMD_PARAM_TXPARAM_MASK_DATA){
1659                        tx_params = wlan_mac_get_default_tx_params(mcast_data);
1660                        tx_params.phy.power = power;
1661                        wlan_mac_set_default_tx_params(mcast_data, &tx_params);
1662                    }
1663                    if(frame_type & CMD_PARAM_TXPARAM_MASK_MGMT){
1664                        tx_params = wlan_mac_get_default_tx_params(mcast_mgmt);
1665                        tx_params.phy.power = power;
1666                        wlan_mac_set_default_tx_params(mcast_mgmt, &tx_params);
1667                    }
1668                }
1669                // 2. Update station_info_t value depending on addr_sel
1670                switch(addr_sel){
1671                    default:
1672                        status = CMD_PARAM_ERROR;
1673                    break;
1674                    case CMD_PARAM_TXPARAM_ADDR_NONE:
1675                    break;
1676                    case CMD_PARAM_TXPARAM_ADDR_ALL:
1677                    case CMD_PARAM_TXPARAM_ADDR_ALL_UNICAST:
1678                    case CMD_PARAM_TXPARAM_ADDR_ALL_MULTICAST:
1679                        station_info_list  = station_info_get_list();
1680                        station_info_entry = (station_info_entry_t*)(station_info_list->first);
1681                        iter = (station_info_list->length)+1;
1682                        while(station_info_entry && ((iter--) > 0)){
1683                            station_info = station_info_entry->data;
1684                            if( (!wlan_addr_mcast(station_info->addr) && ((addr_sel == CMD_PARAM_TXPARAM_ADDR_ALL_UNICAST) || (addr_sel == CMD_PARAM_TXPARAM_ADDR_ALL))) ||
1685                                (wlan_addr_mcast(station_info->addr)  && ((addr_sel == CMD_PARAM_TXPARAM_ADDR_ALL_MULTICAST) || (addr_sel == CMD_PARAM_TXPARAM_ADDR_ALL)))  ){
1686
1687                                if(frame_type & CMD_PARAM_TXPARAM_MASK_DATA){
1688                                    station_info->tx_params_data.phy.power = power;
1689                                }
1690                                if(frame_type & CMD_PARAM_TXPARAM_MASK_MGMT){
1691                                    station_info->tx_params_mgmt.phy.power = power;
1692                                }
1693                            }
1694                            station_info_entry = (station_info_entry_t*)dl_entry_next((dl_entry*)station_info_entry);
1695                        }
1696                    break;
1697                    case CMD_PARAM_TXPARAM_ADDR_SINGLE:
1698                        // Get MAC Address
1699                        wlan_exp_get_mac_addr(&((u32 *)cmd_args_32)[6], &mac_addr[0]);
1700                        station_info = station_info_create(&mac_addr[0]);
1701                        if(station_info){
1702                            if(frame_type & CMD_PARAM_TXPARAM_MASK_DATA){
1703                                station_info->tx_params_data.phy.power = power;
1704                            }
1705                            if(frame_type & CMD_PARAM_TXPARAM_MASK_MGMT){
1706                                station_info->tx_params_mgmt.phy.power = power;
1707                            }
1708                        }
1709                    break;
1710                }
1711
1712            } else {
1713                // We do not support CMD_PARAM_READ_VAL for Tx parameters
1714                status = CMD_PARAM_ERROR;
1715            }
1716
1717            // Send response
1718            wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, status);
1719        }
1720        break;
1721
1722
1723        //---------------------------------------------------------------------
1724        case CMDID_NODE_TX_RATE: {
1725
1726            u8 mac_addr[MAC_ADDR_LEN];
1727            u32 status = CMD_PARAM_SUCCESS;
1728
1729            //Extract arguments
1730            u32 msg_cmd = Xil_Ntohl(cmd_args_32[0]);
1731            u32 frame_type = Xil_Ntohl(cmd_args_32[1]);
1732            u32 update_default_unicast = Xil_Ntohl(cmd_args_32[2]);
1733            u32 update_default_multicast = Xil_Ntohl(cmd_args_32[3]);
1734            u32 mcs = Xil_Ntohl(cmd_args_32[4]) & 0xFF;
1735            u32 phy_mode = Xil_Ntohl(cmd_args_32[5]) & 0xFF;
1736            u32 addr_sel = Xil_Ntohl(cmd_args_32[6]);
1737
1738            int iter;
1739            dl_list* station_info_list;
1740            station_info_entry_t* station_info_entry;
1741            station_info_t* station_info;
1742            tx_params_t     tx_params;
1743
1744            // Force invalid mcs / phy_mode values to sane defaults
1745            if (mcs > 7) {
1746                mcs = 7;
1747            }
1748
1749            if ((phy_mode & (PHY_MODE_NONHT | PHY_MODE_HTMF)) == 0) {
1750                phy_mode = PHY_MODE_NONHT;
1751            }
1752
1753            // Process the command
1754            if( msg_cmd == CMD_PARAM_WRITE_VAL ){
1755                if( frame_type & CMD_PARAM_TXPARAM_MASK_CTRL ){
1756                    //We do not support setting the Tx antenna mode for control packets.
1757                    //CPU_LOW will choose what antenna is used for Tx for these packets.
1758                    status = CMD_PARAM_ERROR;
1759                }
1760                // 1. Update default values if needed
1761                if(update_default_unicast){
1762                    if(frame_type & CMD_PARAM_TXPARAM_MASK_DATA){
1763                        tx_params = wlan_mac_get_default_tx_params(unicast_data);
1764                        tx_params.phy.mcs = mcs;
1765                        tx_params.phy.phy_mode = phy_mode;
1766                        wlan_mac_set_default_tx_params(unicast_data, &tx_params);
1767                    }
1768                    if(frame_type & CMD_PARAM_TXPARAM_MASK_MGMT){
1769                        tx_params = wlan_mac_get_default_tx_params(unicast_mgmt);
1770                        tx_params.phy.mcs = mcs;
1771                        tx_params.phy.phy_mode = phy_mode;
1772                        wlan_mac_set_default_tx_params(unicast_mgmt, &tx_params);
1773                    }
1774                }
1775                if(update_default_multicast){
1776                    if(frame_type & CMD_PARAM_TXPARAM_MASK_DATA){
1777                        tx_params = wlan_mac_get_default_tx_params(mcast_data);
1778                        tx_params.phy.mcs = mcs;
1779                        tx_params.phy.phy_mode = phy_mode;
1780                        wlan_mac_set_default_tx_params(mcast_data, &tx_params);
1781                    }
1782                    if(frame_type & CMD_PARAM_TXPARAM_MASK_MGMT){
1783                        tx_params = wlan_mac_get_default_tx_params(mcast_mgmt);
1784                        tx_params.phy.mcs = mcs;
1785                        tx_params.phy.phy_mode = phy_mode;
1786                        wlan_mac_set_default_tx_params(mcast_mgmt, &tx_params);
1787                    }
1788                }
1789                // 2. Update station_info_t value depending on addr_sel
1790                switch(addr_sel){
1791                    default:
1792                        status = CMD_PARAM_ERROR;
1793                    break;
1794                    case CMD_PARAM_TXPARAM_ADDR_NONE:
1795                    break;
1796                    case CMD_PARAM_TXPARAM_ADDR_ALL:
1797                    case CMD_PARAM_TXPARAM_ADDR_ALL_UNICAST:
1798                    case CMD_PARAM_TXPARAM_ADDR_ALL_MULTICAST:
1799                        station_info_list  = station_info_get_list();
1800                        station_info_entry = (station_info_entry_t*)(station_info_list->first);
1801                        iter = (station_info_list->length)+1;
1802                        while(station_info_entry && ((iter--) > 0)){
1803                            station_info = station_info_entry->data;
1804                            if( (!wlan_addr_mcast(station_info->addr) && ((addr_sel == CMD_PARAM_TXPARAM_ADDR_ALL_UNICAST) || (addr_sel == CMD_PARAM_TXPARAM_ADDR_ALL))) ||
1805                                (wlan_addr_mcast(station_info->addr)  && ((addr_sel == CMD_PARAM_TXPARAM_ADDR_ALL_MULTICAST) || (addr_sel == CMD_PARAM_TXPARAM_ADDR_ALL)))  ){
1806
1807                                if(frame_type & CMD_PARAM_TXPARAM_MASK_DATA){
1808                                    station_info->tx_params_data.phy.mcs = mcs;
1809                                    station_info->tx_params_data.phy.phy_mode = phy_mode;
1810                                }
1811                                if(frame_type & CMD_PARAM_TXPARAM_MASK_MGMT){
1812                                    station_info->tx_params_mgmt.phy.mcs = mcs;
1813                                    station_info->tx_params_mgmt.phy.phy_mode = phy_mode;
1814                                }
1815                            }
1816                            station_info_entry = (station_info_entry_t*)dl_entry_next((dl_entry*)station_info_entry);
1817                        }
1818                    break;
1819                    case CMD_PARAM_TXPARAM_ADDR_SINGLE:
1820                        // Get MAC Address
1821                        wlan_exp_get_mac_addr(&((u32 *)cmd_args_32)[7], &mac_addr[0]);
1822                        station_info = station_info_create(&mac_addr[0]);
1823                        if(station_info){
1824                            if(frame_type & CMD_PARAM_TXPARAM_MASK_DATA){
1825                                station_info->tx_params_data.phy.mcs = mcs;
1826                                station_info->tx_params_data.phy.phy_mode = phy_mode;
1827                            }
1828                            if(frame_type & CMD_PARAM_TXPARAM_MASK_MGMT){
1829                                station_info->tx_params_mgmt.phy.mcs = mcs;
1830                                station_info->tx_params_mgmt.phy.phy_mode = phy_mode;
1831                            }
1832                        }
1833                    break;
1834                }
1835
1836            } else {
1837                // We do not support CMD_PARAM_READ_VAL for Tx parameters
1838                status = CMD_PARAM_ERROR;
1839            }
1840
1841            // Send response
1842            wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, status);
1843        }
1844        break;
1845
1846
1847        //---------------------------------------------------------------------
1848        case CMDID_NODE_TX_ANT_MODE: {
1849            u8 mac_addr[MAC_ADDR_LEN];
1850            u32 status = CMD_PARAM_SUCCESS;
1851
1852            //Extract arguments
1853            u32 msg_cmd = Xil_Ntohl(cmd_args_32[0]);
1854            u32 frame_type = Xil_Ntohl(cmd_args_32[1]);
1855            u32 update_default_unicast = Xil_Ntohl(cmd_args_32[2]);
1856            u32 update_default_multicast = Xil_Ntohl(cmd_args_32[3]);
1857            u32 ant_mode = Xil_Ntohl(cmd_args_32[4]);
1858            u32 addr_sel = Xil_Ntohl(cmd_args_32[5]);
1859
1860            int iter;
1861            dl_list* station_info_list;
1862            station_info_entry_t* station_info_entry;
1863            station_info_t* station_info;
1864            tx_params_t tx_params;
1865
1866            // Need to convert antenna mode from:   Python       C
1867            //     - TX_ANTMODE_SISO_ANTA:            0x0   to  0x10
1868            //     - TX_ANTMODE_SISO_ANTB:            0x1   to  0x20
1869            //     - TX_ANTMODE_SISO_ANTC:            0x2   to  0x30
1870            //     - TX_ANTMODE_SISO_ANTD:            0x3   to  0x40
1871            //
1872            // Formula:  y = (x + 1) << 4;
1873            //
1874            ant_mode = (ant_mode + 1) << 4;
1875
1876            // Process the command
1877            if( msg_cmd == CMD_PARAM_WRITE_VAL ){
1878                if( frame_type & CMD_PARAM_TXPARAM_MASK_CTRL ){
1879                    //We do not support setting the Tx antenna mode for control packets.
1880                    //CPU_LOW will choose what antenna is used for Tx for these packets.
1881                    status = CMD_PARAM_ERROR;
1882                }
1883                // 1. Update default values if needed
1884                if(update_default_unicast){
1885                    if(frame_type & CMD_PARAM_TXPARAM_MASK_DATA){
1886                        tx_params = wlan_mac_get_default_tx_params(unicast_data);
1887                        tx_params.phy.antenna_mode = ant_mode;
1888                        wlan_mac_set_default_tx_params(unicast_data, &tx_params);
1889                    }
1890                    if(frame_type & CMD_PARAM_TXPARAM_MASK_MGMT){
1891                        tx_params = wlan_mac_get_default_tx_params(unicast_mgmt);
1892                        tx_params.phy.antenna_mode = ant_mode;
1893                        wlan_mac_set_default_tx_params(unicast_mgmt, &tx_params);
1894                    }
1895                }
1896                if(update_default_multicast){
1897                    if(frame_type & CMD_PARAM_TXPARAM_MASK_DATA){
1898                        tx_params = wlan_mac_get_default_tx_params(mcast_data);
1899                        tx_params.phy.antenna_mode = ant_mode;
1900                        wlan_mac_set_default_tx_params(mcast_data, &tx_params);
1901                    }
1902                    if(frame_type & CMD_PARAM_TXPARAM_MASK_MGMT){
1903                        tx_params = wlan_mac_get_default_tx_params(mcast_mgmt);
1904                        tx_params.phy.antenna_mode = ant_mode;
1905                        wlan_mac_set_default_tx_params(mcast_mgmt, &tx_params);
1906                    }
1907                }
1908                // 2. Update station_info_t value depending on addr_sel
1909                switch(addr_sel){
1910                    default:
1911                        status = CMD_PARAM_ERROR;
1912                    break;
1913                    case CMD_PARAM_TXPARAM_ADDR_NONE:
1914                    break;
1915                    case CMD_PARAM_TXPARAM_ADDR_ALL:
1916                    case CMD_PARAM_TXPARAM_ADDR_ALL_UNICAST:
1917                    case CMD_PARAM_TXPARAM_ADDR_ALL_MULTICAST:
1918                        station_info_list  = station_info_get_list();
1919                        station_info_entry = (station_info_entry_t*)(station_info_list->first);
1920                        iter = (station_info_list->length)+1;
1921                        while(station_info_entry && ((iter--) > 0)){
1922                            station_info = station_info_entry->data;
1923                            if( (!wlan_addr_mcast(station_info->addr) && ((addr_sel == CMD_PARAM_TXPARAM_ADDR_ALL_UNICAST) || (addr_sel == CMD_PARAM_TXPARAM_ADDR_ALL))) ||
1924                                (wlan_addr_mcast(station_info->addr)  && ((addr_sel == CMD_PARAM_TXPARAM_ADDR_ALL_MULTICAST) || (addr_sel == CMD_PARAM_TXPARAM_ADDR_ALL)))  ){
1925
1926                                if(frame_type & CMD_PARAM_TXPARAM_MASK_DATA){
1927                                    station_info->tx_params_data.phy.antenna_mode = ant_mode;
1928                                }
1929                                if(frame_type & CMD_PARAM_TXPARAM_MASK_MGMT){
1930                                    station_info->tx_params_mgmt.phy.antenna_mode = ant_mode;
1931                                }
1932                            }
1933                            station_info_entry = (station_info_entry_t*)dl_entry_next((dl_entry*)station_info_entry);
1934                        }
1935                    break;
1936                    case CMD_PARAM_TXPARAM_ADDR_SINGLE:
1937                        // Get MAC Address
1938                        wlan_exp_get_mac_addr(&((u32 *)cmd_args_32)[6], &mac_addr[0]);
1939                        station_info = station_info_create(&mac_addr[0]);
1940                        if(station_info){
1941                            if(frame_type & CMD_PARAM_TXPARAM_MASK_DATA){
1942                                station_info->tx_params_data.phy.antenna_mode = ant_mode;
1943                            }
1944                            if(frame_type & CMD_PARAM_TXPARAM_MASK_MGMT){
1945                                station_info->tx_params_mgmt.phy.antenna_mode = ant_mode;
1946                            }
1947                        }
1948                    break;
1949                }
1950
1951            } else {
1952                // We do not support CMD_PARAM_READ_VAL for Tx parameters
1953                status = CMD_PARAM_ERROR;
1954            }
1955
1956            // Send response
1957            wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, status);
1958        }
1959        break;
1960
1961        //---------------------------------------------------------------------
1962        case CMDID_NODE_RX_ANT_MODE: {
1963            // NODE_RX_ANT_MODE Packet Format:
1964            //   - cmd_args_32[0]      - Command
1965            //   - cmd_args_32[1]      - Antenna Mode
1966            //
1967            // NOTE:  This method assumes that the Antenna mode received is valid.
1968            // The checking will be done on either the host, in CPU Low or both.
1969            //
1970            u32 status = CMD_PARAM_SUCCESS;
1971            u32 msg_cmd = Xil_Ntohl(cmd_args_32[0]);
1972            u32 ant_mode = Xil_Ntohl(cmd_args_32[1]);
1973
1974            switch (msg_cmd) {
1975                case CMD_PARAM_WRITE_VAL:
1976                    wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_node, "Set RX antenna mode = %d\n", ant_mode);
1977                    wlan_mac_high_set_rx_ant_mode(ant_mode);
1978                break;
1979
1980                case CMD_PARAM_READ_VAL:
1981                    ant_mode = low_param_rx_ant_mode;
1982                break;
1983
1984                default:
1985                    wlan_exp_printf(WLAN_EXP_PRINT_ERROR, print_type_node, "Unknown command for 0x%6x: %d\n", cmd_id, msg_cmd);
1986                    status = CMD_PARAM_ERROR;
1987                break;
1988            }
1989
1990            // Send response
1991            wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, status);
1992            wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, ant_mode);
1993         }
1994        break;
1995
1996
1997//-----------------------------------------------------------------------------
1998// Scan Commands
1999//-----------------------------------------------------------------------------
2000
2001
2002        //---------------------------------------------------------------------
2003        case CMDID_NODE_SCAN_PARAM: {
2004            // Set the active scan parameters
2005            //
2006            // Message format:
2007            //     cmd_args_32[0]    Command:
2008            //                           - Write       (NODE_WRITE_VAL)
2009            //     cmd_args_32[1]    Time per channel (in microseconds)
2010            //                         (or CMD_PARAM_NODE_TIME_RSVD_VAL if not setting the parameter)
2011            //     cmd_args_32[2]    Number of probe request Tx per channel
2012            //                         (or CMD_PARAM_RSVD if not setting the parameter)
2013            //     cmd_args_32[3]    Length of channel list
2014            //                         (or CMD_PARAM_RSVD if not setting channel list)
2015            //     cmd_args_32[4:N]  Channel
2016            //     cmd_args_32[N+1]  Length of SSID
2017            //                         (or CMD_PARAM_RSVD if not setting SSID)
2018            //     cmd_args_32[N+2]  SSID
2019            //
2020            // Response format:
2021            //     resp_args_32[0]   Status
2022            //
2023            u32 i;
2024            volatile scan_parameters_t* scan_params;
2025            u32 time_per_channel;
2026            u32 num_probe_tx;
2027            u32 channel_list_len;
2028            u8* channel_list;
2029            u32 is_scanning;
2030            u32 ssid_len;
2031            char* ssid;
2032            u32 update_probe_interval = 0;
2033            u32 curr_num_probe_tx = 0;
2034            u32 status = CMD_PARAM_SUCCESS;
2035            u32 msg_cmd = Xil_Ntohl(cmd_args_32[0]);
2036
2037            switch (msg_cmd) {
2038                case CMD_PARAM_WRITE_VAL:
2039                    wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_node, "Set Scan Parameters\n");
2040
2041                    // Check if node is currently in a scan
2042                    is_scanning = wlan_mac_scan_is_scanning();
2043
2044                    // Stop the current scan to update the scan parameters
2045                    //     - Because the underlying channel list can be updated, the scan is stopped
2046                    //       vs being paused.  This will reduce any corner cases.
2047                    if (is_scanning) {
2048                        wlan_mac_scan_stop();
2049                    }
2050
2051                    // Get current scan parameters
2052                    scan_params = wlan_mac_scan_get_parameters();
2053
2054                    // Set the time per channel
2055                    time_per_channel   = Xil_Ntohl(cmd_args_32[1]);
2056
2057                    if (time_per_channel != CMD_PARAM_NODE_TIME_RSVD_VAL) {
2058                        // Compute current num_probe_tx
2059                        if (scan_params->probe_tx_interval_usec == 0) {
2060                            curr_num_probe_tx = 0;
2061                        } else {
2062                            curr_num_probe_tx = scan_params->time_per_channel_usec / scan_params->probe_tx_interval_usec;
2063                        }
2064
2065                        wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_node, "  Time per channel   = %d us\n", time_per_channel);
2066                        scan_params->time_per_channel_usec = time_per_channel;
2067                        update_probe_interval = 1;
2068                    }
2069
2070                    // Set Probe request interval
2071                    num_probe_tx = Xil_Ntohl(cmd_args_32[2]);
2072
2073                    if (num_probe_tx != CMD_PARAM_RSVD) {
2074                        wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_node, "  Num Probe Req      = %d \n", num_probe_tx);
2075                        curr_num_probe_tx = num_probe_tx;
2076                        update_probe_interval = 1;
2077                    }
2078
2079                    // Set the probe_tx_interval
2080                    if (update_probe_interval) {
2081                        if (curr_num_probe_tx == 0) {
2082                            scan_params->probe_tx_interval_usec = 0;
2083                        } else {
2084                            scan_params->probe_tx_interval_usec = scan_params->time_per_channel_usec / curr_num_probe_tx;
2085                        }
2086                        wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_node, "  Probe Req interval = %d us\n", scan_params->probe_tx_interval_usec);
2087                    }
2088
2089
2090                    // Set the scan channels
2091                    channel_list_len = Xil_Ntohl(cmd_args_32[3]);
2092
2093                    if (channel_list_len != CMD_PARAM_RSVD){
2094                        // Free the current channel list in the scan parameters
2095                        wlan_mac_high_free(scan_params->channel_vec);
2096
2097                        // Update new channel list
2098                        channel_list = wlan_mac_high_malloc(channel_list_len);
2099
2100                        for (i = 0; i < channel_list_len; i++) {
2101                            channel_list[i] = Xil_Ntohl(cmd_args_32[4 + i]);
2102                        }
2103
2104                        // Set scan parameters
2105                        scan_params->channel_vec_len = channel_list_len;
2106                        scan_params->channel_vec     = channel_list;
2107
2108                        // Print information about the new channels
2109                        wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_node, "  Channels = ");
2110                        for (i = 0; i < channel_list_len; i++) {
2111                            wlan_exp_printf(WLAN_EXP_PRINT_INFO, NULL, "%d ",channel_list[i]);
2112                        }
2113                        wlan_exp_printf(WLAN_EXP_PRINT_INFO, NULL, "\n");
2114                    } else {
2115                        // No channel list to process
2116                        channel_list_len = 0;
2117                    }
2118
2119                    // Set the SSID
2120                    ssid_len = Xil_Ntohl(cmd_args_32[4 + channel_list_len]);
2121
2122                    if (ssid_len != CMD_PARAM_RSVD){
2123                        // Get pointer to new SSID
2124                        ssid = (char *) &cmd_args_32[5 + channel_list_len];
2125
2126                        // Free the current ssid in the scan parameters
2127                        wlan_mac_high_free(scan_params->ssid);
2128
2129                        // Update new ssid
2130                        scan_params->ssid = strndup(ssid, SSID_LEN_MAX);
2131
2132                        // Print information about the new channels
2133                        wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_node, "  SSID = %s\n", scan_params->ssid);
2134                    }
2135
2136                    // If the node was scanning, re-start the scan
2137                    if (is_scanning) {
2138                        wlan_mac_scan_start();
2139                    }
2140                break;
2141
2142                default:
2143                    wlan_exp_printf(WLAN_EXP_PRINT_ERROR, print_type_node, "Unknown command for 0x%6x: %d\n", cmd_id, msg_cmd);
2144                    status = CMD_PARAM_ERROR;
2145                break;
2146            }
2147
2148            // Send response of status
2149            wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, status);
2150        }
2151        break;
2152
2153
2154        //---------------------------------------------------------------------
2155        case CMDID_NODE_SCAN: {
2156            // Enable / Disable active scan
2157            //
2158            //   Scans initiated by WLAN Exp will use the current scan parameters.  To
2159            // update the scan parameters use the CMDID_NODE_SCAN_PARAM command.
2160            //
2161            // Message format:
2162            //     cmd_args_32[0]   Enable / Disable scan
2163            //                          - CMD_PARAM_NODE_SCAN_ENABLE  - Enable scan
2164            //                          - CMD_PARAM_NODE_SCAN_DISABLE - Disable scan
2165            //                          - CMD_PARAM_RSVD              - Do nothing
2166            //
2167            // Response format:
2168            //     resp_args_32[0]  Status
2169            //     resp_args_32[1]  Is Scanning?
2170            //
2171            u32 status = CMD_PARAM_SUCCESS;
2172            u32 enable = Xil_Ntohl(cmd_args_32[0]);
2173            network_info_t* active_network_info = ((network_info_t*)wlan_exp_active_network_info_getter_callback());
2174
2175            switch (enable) {
2176                case CMD_PARAM_NODE_SCAN_ENABLE:
2177                    // Enable scan
2178                    if (active_network_info == NULL) {
2179                        wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_node, "Scan enabled.\n");
2180                        wlan_mac_scan_start();
2181                    } else {
2182                        // "my_bss_info" must be NULL to start a scan
2183                        //     - This will avoid any corner cases with scanning
2184                        status = CMD_PARAM_ERROR;
2185                    }
2186                break;
2187
2188                case CMD_PARAM_NODE_SCAN_DISABLE:
2189                    // Disable scan
2190                    wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_node, "Scan disabled.\n");
2191                    wlan_mac_scan_stop();
2192                break;
2193            }
2194
2195            // Send response of status
2196            wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, status);
2197            wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, wlan_mac_scan_is_scanning());
2198        }
2199        break;
2200
2201
2202//-----------------------------------------------------------------------------
2203// Association Commands
2204//-----------------------------------------------------------------------------
2205
2206
2207        //---------------------------------------------------------------------
2208        case CMDID_NODE_CONFIG_BSS: {
2209            // Configure the BSS
2210            //
2211            // Message format:
2212            //     < no u32 arguments >
2213            //     ------
2214            //     _wlan_exp_bss_config_update_t
2215            //
2216            // Response format:
2217            //     resp_args_32[0]     - Status
2218            //
2219
2220            typedef struct __attribute__((__packed__)){
2221                u32             update_mask;
2222                bss_config_t    bss_config;
2223            } _wlan_exp_bss_config_update_t;
2224            ASSERT_TYPE_SIZE(_wlan_exp_bss_config_update_t, 52);
2225
2226            u32 status = CMD_PARAM_SUCCESS;
2227
2228            // CONFIG_BSS message has raw bss_config_update struct immediately after command arguments
2229            //  Current CONFIG_BSS command always has zero arguments
2230            _wlan_exp_bss_config_update_t* wlan_exp_bss_config_update;
2231
2232            if(cmd_hdr->num_u32_args == 0) {
2233                wlan_exp_bss_config_update = (_wlan_exp_bss_config_update_t*)(&cmd_args_32[cmd_hdr->num_u32_args]);
2234
2235                // Each MAC implementation is responsible for the implementation of this command.
2236                status = wlan_exp_process_config_bss_callback(&(wlan_exp_bss_config_update->bss_config), wlan_exp_bss_config_update->update_mask);
2237            } else {
2238                xil_printf("ERROR: CMDID_NODE_CONFIG_BSS received with nonzero (%d) command args - leaving BSS config unchanged\n", cmd_hdr->num_u32_args);
2239                status = CMD_PARAM_ERROR;
2240            }
2241
2242            // If there was an error, add CMD_PARAM_ERROR bits on return value
2243            if (status != CMD_PARAM_SUCCESS) {
2244                status |= CMD_PARAM_ERROR;
2245            }
2246
2247            // Send response
2248            wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, status);
2249        }
2250        break;
2251
2252
2253        //---------------------------------------------------------------------
2254        // Case NODE_DISASSOCIATE      is implemented in the child classes
2255
2256
2257        //---------------------------------------------------------------------
2258        case CMDID_NODE_GET_BSS_MEMBERS: {
2259            // NODE_GET_STATION_INFO Packet Format:
2260            //   - cmd_args_32[0]   - start_address of transfer     //TODO: Unusued and should be removed from OTW format
2261            //   - cmd_args_32[1]   - size of transfer (in bytes)   //TODO: Unusued and should be removed from OTW format
2262            //   - cmd_args_32[2:3] - MAC Address (All 0x00 means all entries)
2263            //
2264            // Always returns a valid WLAN Exp Buffer (either 1 or more packets)
2265            //   - bytes_remaining - uint32  - Number of bytes remaining in the transfer
2266            //   - start_byte      - uint32  - Byte index of the first byte in this packet
2267            //   - size            - uint32  - Number of payload bytes in this packet
2268            //   - byte[]          - uint8[] - Array of payload bytes
2269            //
2270
2271            u8 mac_addr[MAC_ADDR_LEN];
2272
2273            // If unchanged, (start_entry == NULL, num_entries = 0)
2274            //  will result in a transport-level response that serves as an
2275            //  acknowledgment.
2276            dl_entry* start_entry = NULL;
2277            u32 num_entries = 0;
2278
2279            dl_list* member_list = NULL;
2280
2281            // Convert the u32-packed MAC address into a 6-byte array
2282            wlan_exp_get_mac_addr(&(cmd_args_32)[2], mac_addr);
2283
2284            // These lists are highly mutable and typically small. For these reasons,
2285            //  we disable interrupts while retrieving them and sending them as responses.
2286            interrupt_state_t curr_interrupt_state = wlan_platform_intc_stop();
2287
2288            member_list = get_network_member_list();
2289
2290            if (wlan_addr_eq(mac_addr, zero_addr)) {
2291                // Retrieve all entries
2292                if(member_list){
2293                    start_entry = (member_list)->first;
2294                    num_entries = (member_list)->length;
2295                }
2296            } else {
2297                // Retrieve one entry
2298                if(member_list){
2299                    start_entry = (dl_entry*)station_info_find_by_addr(mac_addr, member_list);
2300                    if(start_entry) num_entries = 1;
2301                }
2302            }
2303
2304            if(start_entry){
2305                resp_sent = _send_list_response( eth_tx_queue_buffer,
2306                                                 start_entry,
2307                                                 num_entries,
2308                                                 0,
2309                                                 sizeof(station_info_t) - sizeof(rate_selection_info_t) );
2310            }
2311
2312            wlan_platform_intc_set_state(curr_interrupt_state);
2313        }
2314        break;
2315
2316        //---------------------------------------------------------------------
2317        case CMDID_NODE_GET_STATION_INFO_LIST: {
2318            // NODE_GET_STATION_INFO Packet Format:
2319            //   - cmd_args_32[0]   - start_address of transfer     //TODO: Unusued and should be removed from OTW format
2320            //   - cmd_args_32[1]   - size of transfer (in bytes)   //TODO: Unusued and should be removed from OTW format
2321            //   - cmd_args_32[2:3] - MAC Address (All 0xFF means all entries)
2322            //
2323            // Always returns a valid WLAN Exp Buffer (either 1 or more packets)
2324            //   - bytes_remaining - uint32  - Number of bytes remaining in the transfer
2325            //   - start_byte      - uint32  - Byte index of the first byte in this packet
2326            //   - size            - uint32  - Number of payload bytes in this packet
2327            //   - byte[]          - uint8[] - Array of payload bytes
2328            //
2329
2330
2331            u8 mac_addr[MAC_ADDR_LEN];
2332
2333            // If unchanged, (start_entry == NULL, num_entries = 0)
2334            //  will result in a transport-level response that serves as an
2335            //  acknowledgment.
2336            dl_entry* start_entry = NULL;
2337            u32 num_entries = 0;
2338
2339            // Convert the u32-packed MAC address into a 6-byte array
2340            wlan_exp_get_mac_addr(&(cmd_args_32)[2], mac_addr);
2341
2342            // These lists are highly mutable and typically small. For these reasons,
2343            //  we disable interrupts while retrieving them and sending them as responses.
2344            interrupt_state_t curr_interrupt_state = wlan_platform_intc_stop();
2345
2346            if (wlan_addr_eq(mac_addr, zero_addr)) {
2347                // Retrieve all entries
2348                start_entry = station_info_get_list()->first;
2349                num_entries = station_info_get_list()->length;
2350            } else {
2351                // Retrieve one entry
2352                start_entry = (dl_entry*)station_info_find_by_addr(mac_addr, NULL);
2353                if(start_entry) num_entries = 1;
2354
2355            }
2356
2357            if(start_entry){
2358                resp_sent = _send_list_response( eth_tx_queue_buffer,
2359                                                 start_entry,
2360                                                 num_entries,
2361                                                 0,
2362                                                 sizeof(station_info_t) - sizeof(rate_selection_info_t) );
2363            }
2364
2365            wlan_platform_intc_set_state(curr_interrupt_state);
2366
2367        }
2368        break;
2369
2370
2371        //---------------------------------------------------------------------
2372        case CMDID_NODE_GET_NETWORK_INFO: {
2373            // NODE_GET_NETWORK_INFO Packet Format:
2374            //   - cmd_args_32[0]   - start_address of transfer
2375            //   - cmd_args_32[1]   - size of transfer (in bytes)
2376            //   - cmd_args_32[2:3] - MAC Address (All 0x00 means all entries)
2377            //
2378            // Always returns a valid WLAN Exp Buffer (either 1 or more packets)
2379            //   - bytes_remaining - uint32  - Number of bytes remaining in the transfer
2380            //   - start_byte      - uint32  - Byte index of the first byte in this packet
2381            //   - size            - uint32  - Number of payload bytes in this packet
2382            //   - byte[]          - uint8[] - Array of payload bytes
2383            //
2384
2385            u8 mac_addr[MAC_ADDR_LEN];
2386
2387            // If unchanged, (start_entry == NULL, num_entries = 0)
2388            //  will result in a transport-level response that serves as an
2389            //  acknowledgment.
2390            dl_entry* start_entry = NULL;
2391            u32 num_entries = 0;
2392
2393            // Convert the u32-packed MAC address into a 6-byte array
2394            wlan_exp_get_mac_addr(&(cmd_args_32)[2], mac_addr);
2395
2396            // These lists are highly mutable and typically small. For these reasons,
2397            //  we disable interrupts while retrieving them and sending them as responses.
2398            interrupt_state_t curr_interrupt_state = wlan_platform_intc_stop();
2399
2400            // There are a few different retrieval conditions determined by the MAC address argument
2401            // in this command:
2402            // 1) If the MAC Address is zero (00-00-00-00-00-00), we should retrieve the entire list
2403            //    of known network_info_t and return them as response packets.
2404            // 2) If the MAC Address is broadcast (FF-FF-FF-FF-FF-FF) and
2405            //   a) the node currently has an active network, then the network_info_t that describes
2406            //      it should be returned as a response.
2407            //   b) the node currently has no active network, then a blank network_info_t should be
2408            //      returned as a response.
2409            // 3) If the MAC address is any other address, we should search for that address within
2410            //    the list of known network_info_t. If it is found, we will return those network
2411            //    details as a response. If not, we will either return a zeroed network_info_t or
2412            //    blank transport-level response depending on the CMD_PARAM_COUNTS_RETURN_ZEROED_IF_NONE
2413            //    flag in the command arguments.
2414
2415            if (wlan_addr_eq(mac_addr, zero_addr)) {
2416                // For this command, and only this command, zero-valued MAC
2417                // retrieve the active network info.
2418
2419                // Retrieve all entries
2420                start_entry = wlan_mac_high_get_network_info_list()->first;
2421                num_entries = wlan_mac_high_get_network_info_list()->length;
2422
2423            } else if (wlan_addr_eq(mac_addr, bcast_addr)){
2424                network_info_t* active_network_info = ((network_info_t*)wlan_exp_active_network_info_getter_callback());
2425                if(active_network_info){
2426                    start_entry = (dl_entry*)wlan_mac_high_find_network_info_BSSID(active_network_info->bss_config.bssid);
2427                    if(start_entry) num_entries = 1;
2428                }
2429            } else {
2430                start_entry = (dl_entry*)wlan_mac_high_find_network_info_BSSID(mac_addr);
2431                if(start_entry) num_entries = 1;
2432            }
2433
2434            if(start_entry){
2435                resp_sent = _send_list_response( eth_tx_queue_buffer,
2436                                                 start_entry,
2437                                                 num_entries,
2438                                                 0,
2439                                                 sizeof(network_info_t) - sizeof(dl_list) );
2440            }
2441
2442            wlan_platform_intc_set_state(curr_interrupt_state);
2443
2444        }
2445
2446        break;
2447
2448
2449//-----------------------------------------------------------------------------
2450// Queue Commands
2451//-----------------------------------------------------------------------------
2452
2453
2454        //---------------------------------------------------------------------
2455        case CMDID_QUEUE_PURGE_ALL_WIRELESS_TX: {
2456            interrupt_state_t curr_interrupt_state = wlan_platform_intc_stop();
2457            wlan_exp_purge_all_wireless_tx_queue_callback();
2458            wlan_platform_intc_set_state(curr_interrupt_state);
2459        }
2460        break;
2461
2462
2463//-----------------------------------------------------------------------------
2464// Memory Access Commands - For developer use only
2465//-----------------------------------------------------------------------------
2466
2467
2468        //---------------------------------------------------------------------
2469        case CMDID_DEV_MEM_HIGH: {
2470            // FIXME: this definitely needs testing
2471            // Read/write memory in CPU High
2472            //
2473            // Write Message format:
2474            //     cmd_args_32[0]      Command == CMD_PARAM_WRITE_VAL
2475            //     cmd_args_32[1]      Address
2476            //     cmd_args_32[2]      Length (number of u32 words to write)
2477            //     cmd_args_32[3:]     Values to write (integral number of u32 words)
2478            // Response format:
2479            //     resp_args_32[0]     Status
2480            //
2481            // Read Message format:
2482            //     cmd_args_32[0]      Command == CMD_PARAM_READ_VAL
2483            //     cmd_args_32[1]      Address
2484            //     cmd_args_32[2]      Length (number of u32 words to read)
2485            // Response format:
2486            //     resp_args_32[0]     Status
2487            //     resp_args_32[1]     Length (number of u32 values)
2488            //     resp_args_32[2:]    Memory values (length u32 values)
2489            //
2490            u32 mem_idx;
2491            u32 status = CMD_PARAM_SUCCESS;
2492            u32 msg_cmd = Xil_Ntohl(cmd_args_32[0]);
2493            u32 mem_addr = Xil_Ntohl(cmd_args_32[1]);
2494            u32 num_words = Xil_Ntohl(cmd_args_32[2]);
2495            u32 use_default_resp = WLAN_EXP_TRUE;
2496            u32 max_resp_len = wlan_exp_transport_get_max_pkt_words();
2497
2498            switch (msg_cmd) {
2499                case CMD_PARAM_WRITE_VAL:
2500                    wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_node, "Write CPU High Mem\n");
2501                    wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_node, "  Addr: 0x%08x\n", mem_addr);
2502                    wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_node, "  Len:  %d\n", num_words);
2503
2504                    // Don't bother if length is clearly bogus
2505                    if(num_words < max_resp_len) {
2506                        for (mem_idx = 0; mem_idx < num_words; mem_idx++) {
2507                            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]));
2508                            Xil_Out32((mem_addr + mem_idx*sizeof(u32)), Xil_Ntohl(cmd_args_32[3 + mem_idx]));
2509                        }
2510                    } else {
2511                        wlan_exp_printf(WLAN_EXP_PRINT_ERROR, print_type_node, "CMDID_DEV_MEM_HIGH write longer than 1400 bytes\n");
2512                        status = CMD_PARAM_ERROR;
2513                    }
2514                break;
2515
2516                case CMD_PARAM_READ_VAL:
2517                    wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_node, "Read CPU High Mem:\n");
2518                    wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_node, "  Addr: 0x%08x\n", mem_addr);
2519                    wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_node, "  Len:  %d\n", num_words);
2520
2521                    // Add payload to response
2522                    if(num_words < max_resp_len) {
2523
2524                        // Don't set the default response
2525                        use_default_resp = WLAN_EXP_FALSE;
2526
2527                        // Add length argument to response
2528                        wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, status);
2529                        wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, num_words);
2530
2531                        for (mem_idx = 0; mem_idx < num_words; mem_idx++) {
2532                            wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, Xil_In32((u32)((void*)(mem_addr) + mem_idx*sizeof(u32))));
2533                        }
2534                    } else {
2535                        wlan_exp_printf(WLAN_EXP_PRINT_ERROR, print_type_node, "CMDID_DEV_MEM_HIGH read longer than 1400 bytes\n");
2536                        status = CMD_PARAM_ERROR;
2537                    }
2538                break;
2539
2540                default:
2541                    wlan_exp_printf(WLAN_EXP_PRINT_ERROR, print_type_node, "Unknown command for 0x%6x: %d\n", cmd_id, msg_cmd);
2542                    status = CMD_PARAM_ERROR;
2543                break;
2544            }
2545
2546            if (use_default_resp) {
2547                // Send default response
2548                wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, status);
2549            }
2550        }
2551        break;
2552
2553
2554        //---------------------------------------------------------------------
2555        case CMDID_DEV_MEM_LOW: {
2556            // Read/write memory in CPU Low via IPC message
2557            //
2558            // Write Message format:
2559            //     cmd_args_32[0]      Command == CMD_PARAM_WRITE_VAL
2560            //     cmd_args_32[1]      Address
2561            //     cmd_args_32[2]      Length (number of u32 words to write)
2562            //     cmd_args_32[3:]     Values to write (integral number of u32 words)
2563            // Response format:
2564            //     resp_args_32[0]     Status
2565            //
2566            // Read Message format:
2567            //     cmd_args_32[0]      Command == CMD_PARAM_READ_VAL
2568            //     cmd_args_32[1]      Address
2569            //     cmd_args_32[2]      Length (number of u32 words to read)
2570            // Response format:
2571            //     resp_args_32[0]     Status
2572            //     resp_args_32[1]     Length (number of u32 values)
2573            //     resp_args_32[2:]    Memory values (length u32 values)
2574            //
2575            u32 mem_idx;
2576            int mem_status;
2577            u32 status = CMD_PARAM_SUCCESS;
2578            u32 msg_cmd = Xil_Ntohl(cmd_args_32[0]);
2579            u32 mem_addr = Xil_Ntohl(cmd_args_32[1]);
2580            u32 num_words = Xil_Ntohl(cmd_args_32[2]);
2581            u32 use_default_resp = WLAN_EXP_TRUE;
2582            u32 max_resp_len = wlan_exp_transport_get_max_pkt_words();
2583            u32* resp_args_32;
2584
2585            switch (msg_cmd) {
2586                case CMD_PARAM_WRITE_VAL:
2587                    wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_node, "Write CPU Low Mem:\n");
2588                    wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_node, "  Addr: 0x%08x\n", mem_addr);
2589                    wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_node, "  Len:  %d\n", num_words);
2590
2591                    // Don't bother if length is clearly bogus
2592                    if(num_words < max_resp_len) {
2593                        // Endian swap payload here - CPU Low requires payload that is ready to use as-is
2594                        for (mem_idx = 0; mem_idx < num_words+2; mem_idx++) {
2595                            cmd_args_32[1 + mem_idx] = Xil_Ntohl(cmd_args_32[1 + mem_idx]);
2596                        }
2597
2598                        mem_status = wlan_mac_high_write_low_mem(num_words + 2, &(cmd_args_32[1]));
2599
2600                        if (mem_status == -1) {
2601                            wlan_exp_printf(WLAN_EXP_PRINT_ERROR, print_type_node, "CMDID_DEV_MEM_LOW write failed\n");
2602                            status = CMD_PARAM_ERROR;
2603                        }
2604                    } else {
2605                        wlan_exp_printf(WLAN_EXP_PRINT_ERROR, print_type_node, "CMDID_DEV_MEM_LOW write longer than 1400 bytes\n");
2606                        status = CMD_PARAM_ERROR;
2607                    }
2608                break;
2609
2610                case CMD_PARAM_READ_VAL:
2611                    wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_node, "Read CPU Low Mem:\n");
2612                    wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_node, "  Addr: 0x%08x\n", mem_addr);
2613                    wlan_exp_printf(WLAN_EXP_PRINT_INFO, print_type_node, "  Len:  %d\n", num_words);
2614
2615#define _CMDID_DEV_MEM_LOW_NUM_RESP_ARGS 2
2616
2617                    if(num_words < max_resp_len) {
2618                        resp_args_32 = (u32*)(eth_tx_queue_buffer->seg0 + eth_tx_queue_buffer->seg0_len + (_CMDID_DEV_MEM_LOW_NUM_RESP_ARGS*sizeof(u32)));
2619                        mem_status = wlan_mac_high_read_low_mem(num_words, mem_addr, resp_args_32);
2620
2621                        if(mem_status == 0) { //Success
2622                            // Don't set the default response
2623                            use_default_resp = WLAN_EXP_FALSE;
2624
2625                            // Add length argument to response
2626                            wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, status);
2627                            wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, num_words);
2628
2629                            // Endian swap payload returned by CPU Low
2630                            for (mem_idx = 0; mem_idx < num_words; mem_idx++) {
2631                                //The packet payload already contains the data we need, but we'll add it word-by-word
2632                                // in order to get the proper network order and update header values.
2633                                wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, resp_args_32[mem_idx]);
2634                            }
2635                        } else { //failed
2636                            wlan_exp_printf(WLAN_EXP_PRINT_ERROR, print_type_node, "CMDID_DEV_MEM_LOW read failed\n");
2637                            status = CMD_PARAM_ERROR;
2638                        }
2639                    } else {
2640                        wlan_exp_printf(WLAN_EXP_PRINT_ERROR, print_type_node, "CMDID_DEV_MEM_LOW read longer than 1400 bytes\n");
2641                        status = CMD_PARAM_ERROR;
2642                    }
2643                break;
2644
2645                default:
2646                    wlan_exp_printf(WLAN_EXP_PRINT_ERROR, print_type_node, "Unknown command for 0x%6x: %d\n", cmd_id, msg_cmd);
2647                    status = CMD_PARAM_ERROR;
2648                break;
2649            }
2650
2651            if (use_default_resp) {
2652                // Send default response
2653                wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, status);
2654            }
2655        }
2656        break;
2657
2658
2659//-----------------------------------------------------------------------------
2660// Child Commands
2661//-----------------------------------------------------------------------------
2662
2663
2664        //---------------------------------------------------------------------
2665        default: {
2666            u8 cmd_processed;
2667
2668            // Call function in platform code
2669            resp_sent = wlan_platform_wlan_exp_process_node_cmd(cmd_hdr, eth_tx_queue_buffer, &cmd_processed);
2670
2671            if(cmd_processed == 0){
2672                // If platform code did not deal with this command, then
2673                // call standard function in child class to parse parameters implemented there
2674                resp_sent = wlan_exp_process_node_cmd_callback(cmd_hdr, eth_tx_queue_buffer);
2675            }
2676        }
2677        break;
2678    }
2679
2680    return resp_sent;
2681}
2682
2683
2684
2685
2686/*****************************************************************************/
2687/**
2688 * @brief Send a doubly linked list as a response
2689 *
2690 * This function will send one or more response packets to retrieve data from a
2691 * doubly-linked list. Each response packet contains 5 u32 arguments followed by
2692 * raw payload containing the list data.
2693 *
2694 * resp_args_32[0]     Number of bytes remaining, not including the bytes in this packet.
2695 * resp_args_32[1]     Starting byte index of list data in this packet
2696 * resp_args_32[2]     Number of bytes of list payload contained in this packet
2697 * resp_args_32[3]     Retrieval timestamp (least significant bytes)
2698 * resp_arts_32[4]     Retrieval timestamp (most significant bytes)
2699 *
2700 * @param    first_eth_tx_queue_buffer - framework's pre-created first response packet
2701 * @param    start_entry - first entry in the list to be copied
2702 * @param    num_entries - number of entries from the list to send
2703 * @param    offset_per_entry - how far into each entry the copy should begin (to avoid unwanted header fields)
2704 * @param    size_per_entry - how many bytes to send from each entry (allows avoiding unwanted footer fields)
2705 *
2706 * @return   NO_RESP_SENT
2707 *           RESP_SENT
2708 *
2709 *****************************************************************************/
2710u32 _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 ){
2711    u32 resp_sent = 0;
2712    u32 max_bytes_per_pkt;
2713    u32 num_pkts;
2714    u32 total_num_bytes;
2715    u32 pkt_idx;
2716    u32 curr_index;
2717    u32 sent_bytes;
2718    u32 next_index;
2719    u32 transfer_length;
2720    u32 num_bytes;
2721    interrupt_state_t prev_interrupt_state;
2722    dl_entry* tmp_entry;
2723    cmd_resp_hdr_t* curr_cmd_resp_hdr;
2724    dl_entry* curr_entry;
2725    dl_entry* end_entry;
2726    u32 max_num_entries_per_pkt;
2727    eth_tx_queue_buffer_t* curr_eth_tx_queue_buffer;
2728    eth_tx_queue_buffer_t* next_eth_tx_queue_buffer;
2729    u64 retrieval_timestamp;
2730
2731    retrieval_timestamp = get_system_time_usec();
2732
2733#define _LIST_NUM_RESP_ARGS 5
2734
2735    u32 max_resp_len = wlan_exp_transport_get_max_pkt_words();
2736
2737    total_num_bytes = size_per_entry * num_entries;
2738
2739    // Sanity check pointer arguments
2740    if( (first_eth_tx_queue_buffer == NULL) || (start_entry == NULL) || (total_num_bytes == 0) ){
2741        return resp_sent;
2742    }
2743
2744    next_eth_tx_queue_buffer = first_eth_tx_queue_buffer;
2745    curr_entry = start_entry;
2746
2747    // First, we subtract the bytes that must be used for the list retrieval header
2748    max_bytes_per_pkt = ((max_resp_len) * 4) - (_LIST_NUM_RESP_ARGS * sizeof(u32));
2749
2750    // Integer division will properly floor the result so we can determine the largest
2751    // number of full entries that can be packed into a packet.
2752    max_num_entries_per_pkt = max_bytes_per_pkt / size_per_entry;
2753
2754    // Update the maximum number of bytes to reflect an integer number of entries
2755    max_bytes_per_pkt = max_num_entries_per_pkt * size_per_entry;
2756
2757    num_pkts = total_num_bytes/max_bytes_per_pkt;
2758    if((num_pkts * max_bytes_per_pkt) < total_num_bytes) num_pkts++;
2759
2760    // We are going to be copying the header contents of the first response packet to all
2761    //  subsequent response packets. Normally this is filled in at the time of sending,
2762    //  but there's no point in repeating that code for every packet. Instead, we'll fill it
2763    //  in early and skip the operation at the time of sending.
2764    wlan_exp_transport_fill_headers_response(first_eth_tx_queue_buffer);
2765
2766    curr_index = 0;
2767    sent_bytes = 0;
2768
2769    for (pkt_idx = 0; pkt_idx < num_pkts; pkt_idx++) {
2770
2771        curr_eth_tx_queue_buffer = next_eth_tx_queue_buffer;
2772        next_eth_tx_queue_buffer = NULL;
2773
2774        if( pkt_idx != (num_pkts-1) ){
2775
2776            prev_interrupt_state = wlan_platform_intc_stop();
2777            do{
2778                tmp_entry = queue_checkout();
2779                if(tmp_entry == NULL){
2780                    // There are no free queue entries to handle this Tx. We don't have a way
2781                    // of sending less than we are instructed, so we need to block until some
2782                    // are freed up. This is made more complicated by the fact that we just
2783                    // disabled interrupts since we are modifying dl_list. If an interrupt context
2784                    // is going to free up a queue for us to use, we need to allow it to do so.
2785                    // We'll briefly toggle interrupts so we can deal with any ISRs and get
2786                    // back to this context to try again.
2787
2788                    // If this is happening a lot, we need to increase the total number of queue
2789                    // entries or reduce their usage elsewhere. The intent is for this to rarely
2790                    // occur.
2791
2792                    wlan_platform_intc_set_state(INTERRUPTS_ENABLED);
2793                    wlan_usleep(1);
2794                    wlan_platform_intc_stop();
2795                }
2796            } while(tmp_entry == NULL);
2797
2798            wlan_platform_intc_set_state(prev_interrupt_state);
2799
2800            // The queue for outgoing wlan_exp transmissions is limited
2801            // to WLAN_EXP_MAX_QUEUE_LEN packets. If this queue is full,
2802            // subsequent packets will be dropped. This behavior is bad
2803            // for log and list retrieval since we could run into this
2804            // limit when returning a large amount of data. However,
2805            // disabling this limit is also not a good behavior -- the
2806            // intention is that wlan_exp cannot exhause queue entries
2807            // needed for other critical operations. So, instead, we'll
2808            // leave the limit in place and only proceed when we are sure
2809            // that the entry just checked out above will have a place
2810            // to go. Note: we give a little extra padding on
2811            // WLAN_EXP_MAX_QUEUE_LEN in case the wlan_exp transport steals
2812            // spots in the queue out from underneath us (e.g. ARP and ping
2813            // replies)
2814            while( wlan_exp_get_tx_queue_length() > (WLAN_EXP_MAX_QUEUE_LEN-5) ){
2815                wlan_platform_intc_set_state(INTERRUPTS_ENABLED);
2816                wlan_usleep(1);
2817                wlan_platform_intc_set_state(prev_interrupt_state);
2818            }
2819
2820            next_eth_tx_queue_buffer = (eth_tx_queue_buffer_t*)tmp_entry->data;
2821
2822            // For all packets except the last in the array, we will start
2823            // a CDMA copy of wlan_exp_transport_header from the current packet
2824            // into the next. This will implicitly block if for some reason we run
2825            // into the CDMA still running from the previous loop (not likely).
2826
2827            //
2828            wlan_mac_high_cdma_start_transfer(next_eth_tx_queue_buffer->seg0,
2829                                              curr_eth_tx_queue_buffer->seg0,
2830                                              curr_eth_tx_queue_buffer->seg0_len);
2831
2832            // Update the length of the buffer
2833            next_eth_tx_queue_buffer->seg0_len = curr_eth_tx_queue_buffer->seg0_len;
2834            next_eth_tx_queue_buffer->seg1_len = 0;
2835        }
2836
2837        transfer_length = WLAN_MIN( total_num_bytes-sent_bytes,
2838                                    max_bytes_per_pkt );
2839
2840        next_index  = curr_index + transfer_length;
2841
2842        curr_cmd_resp_hdr = (cmd_resp_hdr_t*)(curr_eth_tx_queue_buffer->seg0
2843                                               + curr_eth_tx_queue_buffer->seg0_len
2844                                               - sizeof(cmd_resp_hdr_t));
2845
2846        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)),
2847                                            curr_entry,
2848                                            &end_entry,
2849                                            transfer_length/size_per_entry,
2850                                            offset_per_entry,
2851                                            size_per_entry);
2852
2853        if (num_bytes > 0){
2854            // 2) If the num_bytes was less than what we expected, but still non-zero, this is an edge condition where the list
2855            //    was smaller than anticipated and this is the last packet we need to send.
2856            curr_cmd_resp_hdr->length += num_bytes;
2857            curr_eth_tx_queue_buffer->seg0_len += num_bytes;
2858
2859            wlan_exp_add_u32_resp_arg(curr_eth_tx_queue_buffer, curr_cmd_resp_hdr, total_num_bytes-sent_bytes);
2860            wlan_exp_add_u32_resp_arg(curr_eth_tx_queue_buffer, curr_cmd_resp_hdr, curr_index);
2861            wlan_exp_add_u32_resp_arg(curr_eth_tx_queue_buffer, curr_cmd_resp_hdr, num_bytes);
2862            wlan_exp_add_u32_resp_arg(curr_eth_tx_queue_buffer, curr_cmd_resp_hdr, retrieval_timestamp & 0xFFFFFFFF);
2863            wlan_exp_add_u32_resp_arg(curr_eth_tx_queue_buffer, curr_cmd_resp_hdr, (retrieval_timestamp >> 32) & 0xFFFFFFFF);
2864
2865            // Send the packet as a response
2866            _send_response(curr_cmd_resp_hdr, curr_eth_tx_queue_buffer, 0);
2867            resp_sent = RESP_SENT;
2868        }
2869
2870        if (num_bytes < transfer_length){
2871            // There wasn't enough log data to fill this full packet like we expected. If this isn't the last packet
2872            // we intended to send, we need to free the next packet queue buffer since we aren't going to use it.
2873            if (next_eth_tx_queue_buffer){
2874                wlan_mac_high_cdma_finish_transfer(); // Finish the previous CDMA operation into the next packet queue buffer
2875                queue_checkin(next_eth_tx_queue_buffer->pyld_queue_hdr.dle);
2876            }
2877            break;
2878        }
2879
2880        // Update our current address and bytes remaining
2881        curr_index = next_index;
2882        sent_bytes += transfer_length;
2883
2884        curr_entry = NULL;
2885        if(end_entry) curr_entry = dl_entry_next(end_entry);
2886
2887        if(curr_entry == NULL){
2888            break;
2889        }
2890
2891    }
2892
2893    return resp_sent;
2894}
2895
2896#if WLAN_SW_CONFIG_ENABLE_LOGGING
2897/*****************************************************************************/
2898/**
2899 * @brief Send log data
2900 *
2901 * This function will send one or more response packets to retrieve data from a
2902 * the event log. Each response packet contains 3 u32 arguments followed by
2903 * raw payload containing the log data.
2904 *
2905 * resp_args_32[0]     Number of bytes remaining, not including the bytes in this packet.
2906 * resp_args_32[1]     Starting byte index of log data in this packet
2907 * resp_args_32[2]     Number of bytes of log payload contained in this packet
2908 *
2909 * @param    first_eth_tx_queue_buffer - framework's pre-created first response packet
2910 * @param    start_index - byte index in log where to start the retrieval
2911 * @param    total_num_bytes - number of entries from the list to send
2912 *
2913 * @return   NO_RESP_SENT
2914 *           RESP_SENT
2915 *
2916 *****************************************************************************/
2917u32 _transfer_log_data(eth_tx_queue_buffer_t* first_eth_tx_queue_buffer, u32 start_index, u32 total_num_bytes) {
2918
2919#define LOG_TRANSFER_NUM_PKT_BURST 6
2920
2921    u32 resp_sent = 0;
2922    int num_pkts; // must be signed, for defined behavior with (num_pkts-2) below
2923    u32 curr_index;
2924    u32 next_index;
2925    u32 sent_bytes;
2926    u32 max_bytes_per_pkt;
2927    u32 transfer_length;
2928    int pkt_idx;
2929    u32 num_bytes;
2930    dl_entry* tmp_queue_entry;
2931    cmd_resp_hdr_t* curr_cmd_resp_hdr;
2932    interrupt_state_t prev_interrupt_state;
2933
2934    eth_tx_queue_buffer_t* curr_eth_tx_queue_buffer = NULL;
2935    eth_tx_queue_buffer_t* next_eth_tx_queue_buffer = NULL;
2936    eth_tx_queue_buffer_t* last_pkt_queue_buffer = NULL;
2937    u32 resp_args_offset;
2938    volatile u32* resp_args_32;
2939
2940    #define _LOG_NUM_RESP_ARGS 3
2941
2942    u32 max_resp_len = wlan_exp_transport_get_max_pkt_words();
2943
2944    // Sanity check pointer arguments
2945    if( (first_eth_tx_queue_buffer == NULL) || (total_num_bytes == 0) ){
2946        return resp_sent;
2947    }
2948
2949    // Once we start adding arguments, seg0_len will encompass
2950    // those arguments. Before we do anything else, we'll save
2951    // away this value so we can always find where to place
2952    // response arguments in subsequent packets where seg0_len
2953    // has changed.
2954    resp_args_offset = first_eth_tx_queue_buffer->seg0_len;
2955
2956    // The 0 here is a reminder that any bytes dedicated as a retrieval header
2957    // need to be accounted for as part of the response length.
2958    max_bytes_per_pkt = ((max_resp_len) * 4) - (_LOG_NUM_RESP_ARGS * sizeof(u32));
2959
2960    num_pkts = total_num_bytes/max_bytes_per_pkt;
2961    if((num_pkts * max_bytes_per_pkt) < total_num_bytes) num_pkts++;
2962
2963    // Set the first pointer to the provided argument
2964    next_eth_tx_queue_buffer = first_eth_tx_queue_buffer;
2965
2966    // The log subsystem uses "index" to refer to byte offsets relative to the base of
2967    //  the log data memory block. In this context:
2968    // size: the number of log data bytes requested by the host
2969    // start_index: index of first log data byte requested by the host
2970    // end_index: index of the log data byte immediately after the last log data byte requested by the host
2971    //  (thus the log data byte at end_index will not be transmitted to the host in this context)
2972    curr_index = start_index;
2973    sent_bytes = 0;
2974
2975    // We are going to be copying the header contents of the first response packet to all
2976    //  subsequent response packets. Normally this is filled in at the time of sending,
2977    //  but there's no point in repeating that code for every packet. Instead, we'll fill it
2978    //  in early and skip the operation at the time of sending.
2979    wlan_exp_transport_fill_headers_response(first_eth_tx_queue_buffer);
2980
2981    if(num_pkts > 1) {
2982        // Check out a queue buffer to use a temporary scratch space that can be accessed
2983        // by the CDMA
2984        prev_interrupt_state = wlan_platform_intc_stop();
2985
2986        do{
2987            tmp_queue_entry = queue_checkout();
2988            if(tmp_queue_entry == NULL){
2989
2990                // There are no free queue entries to handle this Tx. We don't have a way
2991                // of sending less than we are instructed, so we need to block until some
2992                // are freed up. This is made more complicated by the fact that we just
2993                // disabled interrupts since we are modifying dl_list. If an interrupt context
2994                // is going to free up a queue for us to use, we need to allow it to do so.
2995                // We'll briefly toggle interrupts so we can deal with any ISRs and get
2996                // back to this context to try again.
2997
2998                // If this is happening a lot, we need to increase the total number of queue
2999                // entries or reduce their usage elsewhere. The intent is for this to rarely
3000                // occur.
3001
3002                wlan_platform_intc_set_state(INTERRUPTS_ENABLED);
3003                wlan_usleep(1);
3004                wlan_platform_intc_stop();
3005            }
3006        } while(tmp_queue_entry == NULL);
3007
3008        wlan_platform_intc_set_state(prev_interrupt_state);
3009
3010        last_pkt_queue_buffer = (eth_tx_queue_buffer_t*)(tmp_queue_entry->data);
3011
3012        // Copy the headers from the first packet into the last packet
3013        //  Headers for any intermediate packets will be copied inside the for loop below
3014        last_pkt_queue_buffer->seg0_len = first_eth_tx_queue_buffer->seg0_len;
3015        last_pkt_queue_buffer->seg1_len = 0;
3016        wlan_mac_high_cdma_start_transfer(last_pkt_queue_buffer->seg0,
3017                                          first_eth_tx_queue_buffer->seg0,
3018                                          first_eth_tx_queue_buffer->seg0_len);
3019    } else {
3020        last_pkt_queue_buffer = NULL;
3021    }
3022
3023
3024    // We are going to temporarily disable the wlan_exp Eth Tx software
3025    //  interrupt in order to minimize the number of context switches
3026    wlan_platform_clear_sw_intr_mask(SW_INTR_ID_WLAN_EXP_ETH_TX);
3027
3028    for (pkt_idx = 0; pkt_idx < num_pkts; pkt_idx++) {
3029
3030        if((num_pkts >= 2) && (pkt_idx == (num_pkts - 1))) {
3031            // The last packet queue buffer was allocated and initialized above this loop
3032            curr_eth_tx_queue_buffer = last_pkt_queue_buffer;
3033        } else {
3034            // next_eth_tx_queue_buffer was initialized above this loop, then updated
3035            //  in previous iterations of this loop. This assignment must be used for all
3036            //  packets except the last packet in a multi-packet response
3037            curr_eth_tx_queue_buffer = next_eth_tx_queue_buffer;
3038        }
3039
3040        // Reset the next_ pointer, will be updated below if this is not the last iteration
3041        next_eth_tx_queue_buffer = NULL;
3042
3043        // Allocate a queue buffer for the next packet, unless the next packet is the last packet
3044        if( (num_pkts >= 3) && (pkt_idx < (num_pkts-2))) {
3045
3046            prev_interrupt_state = wlan_platform_intc_stop();
3047
3048            do{
3049                tmp_queue_entry = queue_checkout();
3050                if(tmp_queue_entry == NULL){
3051
3052                    // There are no free queue entries to handle this Tx. We don't have a way
3053                    // of sending less than we are instructed, so we need to block until some
3054                    // are freed up. This is made more complicated by the fact that we just
3055                    // disabled interrupts since we are modifying dl_list. If an interrupt context
3056                    // is going to free up a queue for us to use, we need to allow it to do so.
3057                    // We'll briefly toggle interrupts so we can deal with any ISRs and get
3058                    // back to this context to try again.
3059
3060                    // If this is happening a lot, we need to increase the total number of queue
3061                    // entries or reduce their usage elsewhere. The intent is for this to rarely
3062                    // occur.
3063
3064                    wlan_platform_intc_set_state(INTERRUPTS_ENABLED);
3065                    wlan_usleep(1);
3066                    wlan_platform_intc_stop();
3067                }
3068            } while(tmp_queue_entry == NULL);
3069
3070            wlan_platform_intc_set_state(prev_interrupt_state);
3071
3072            // The queue for outgoing wlan_exp transmissions is limited
3073            // to WLAN_EXP_MAX_QUEUE_LEN packets. If this queue is full,
3074            // subsequent packets will be dropped. This behavior is bad
3075            // for log and list retrieval since we could run into this
3076            // limit when returning a large amount of data. However,
3077            // disabling this limit is also not a good behavior -- the
3078            // intention is that wlan_exp cannot exhause queue entries
3079            // needed for other critical operations. So, instead, we'll
3080            // leave the limit in place and only proceed when we are sure
3081            // that the entry just checked out above will have a place
3082            // to go. Note: we give a little extra padding on
3083            // WLAN_EXP_MAX_QUEUE_LEN in case the wlan_exp transport steals
3084            // spots in the queue out from underneath us (e.g. ARP and ping
3085            // replies)
3086            while( wlan_exp_get_tx_queue_length() > (WLAN_EXP_MAX_QUEUE_LEN-5) ){
3087                wlan_platform_intc_set_state(INTERRUPTS_ENABLED);
3088                wlan_usleep(1);
3089                wlan_platform_intc_set_state(prev_interrupt_state);
3090            }
3091
3092            next_eth_tx_queue_buffer = (eth_tx_queue_buffer_t*)tmp_queue_entry->data;
3093
3094
3095            // For all packets except the last in the array, we will start
3096            // a CDMA copy of wlan_exp_transport_header from the current packet
3097            // into the next. This will implicitly block if for some reason we run
3098            // into the CDMA still running from the previous loop (not likely).
3099
3100        }
3101
3102        transfer_length = WLAN_MIN( total_num_bytes-sent_bytes,
3103                                    max_bytes_per_pkt );
3104
3105        next_index  = curr_index + transfer_length;
3106
3107        // Set up cmd_resp_hdr_t
3108        curr_cmd_resp_hdr = (cmd_resp_hdr_t*)(curr_eth_tx_queue_buffer->seg0
3109                                               + curr_eth_tx_queue_buffer->seg0_len
3110                                               - sizeof(cmd_resp_hdr_t));
3111
3112        num_bytes = event_log_get_data(curr_index, transfer_length, &(curr_eth_tx_queue_buffer->seg1_addr));
3113
3114        if (num_bytes > 0){
3115            wlan_mac_high_cdma_finish_transfer(); // If the previous iteration of the loop is still copying
3116                                                  // bytes into this current queue buffer, we need to wait
3117                                                  // for it to complete.
3118
3119
3120            curr_eth_tx_queue_buffer->seg1_len = num_bytes;
3121
3122            resp_args_32 = (u32*)(curr_eth_tx_queue_buffer->seg0 + resp_args_offset);
3123
3124            //Arg 0: Number of bytes remaining
3125            resp_args_32[0] = Xil_Htonl(total_num_bytes-sent_bytes);
3126
3127            //Arg 1: Current byte index
3128            resp_args_32[1] = Xil_Htonl(curr_index);
3129
3130            //Arg 2: Number of log bytes in this packet
3131            resp_args_32[2] = Xil_Htonl(num_bytes);
3132
3133            if( (pkt_idx == 0) || (pkt_idx == (num_pkts-1)) ){
3134                // The first and last packets of the transmission are unique in that their headers need to be
3135                // updated prior to being sent.
3136
3137                // Every other packet of a log retrieval will have identical headers to the first, so we can
3138                // avoid the computational overhead of recalculating that data.
3139
3140                curr_cmd_resp_hdr->length += _LOG_NUM_RESP_ARGS*sizeof(u32) + num_bytes;
3141                curr_cmd_resp_hdr->num_u32_args += _LOG_NUM_RESP_ARGS;
3142                curr_eth_tx_queue_buffer->seg0_len += _LOG_NUM_RESP_ARGS*sizeof(u32);
3143
3144                _prepare_response_for_send(curr_cmd_resp_hdr);
3145
3146                wlan_exp_transport_prepare_headers(curr_eth_tx_queue_buffer);
3147            }
3148
3149            if((num_pkts >= 3) && (pkt_idx < (num_pkts-2))) {
3150                // The first and all intermediate packets (packets except the last) have the same Eth/IP/UDP/Transport/Response headers
3151                //  However the packets are submitted to the queue/DMA on each iteration, and packets submitted to hardware must not be
3152                //  accessed until the DMA is finishes. Thus, this loop copies headers from the current packet to the _next_ packet before
3153                //  the current packet is submitted to the queue/DMA.
3154                wlan_mac_high_cdma_start_transfer(next_eth_tx_queue_buffer->seg0,
3155                                                  curr_eth_tx_queue_buffer->seg0,
3156                                                  curr_eth_tx_queue_buffer->seg0_len);
3157
3158                // This CDMA operation must be finished before the first of two things happens:
3159
3160                // 1) curr_eth_tx_queue_buffer is returned to the free pool. Look for the wlan_mac_high_cdma_finish_transfer() call
3161                // in platform code when transmitted packets are freed.
3162                // 2) next_eth_tx_queue_buffer is modified. This is why there is a call to wlan_mac_high_cdma_finish_transfer() earlier
3163                // in this for loop.
3164
3165                // Update the length of the buffer
3166                next_eth_tx_queue_buffer->seg0_len = curr_eth_tx_queue_buffer->seg0_len;
3167                next_eth_tx_queue_buffer->seg1_len = 0;
3168            }
3169
3170            // Send the Ethernet packet
3171            wlan_exp_append_tx(curr_eth_tx_queue_buffer->pyld_queue_hdr.dle);
3172            resp_sent = RESP_SENT;
3173        }
3174
3175        if (num_bytes < transfer_length){
3176            // There wasn't enough log data to fill this full packet like we expected. If this isn't the last packet
3177            // we intended to send, we need to free the next packet queue buffer since we aren't going to use it.
3178            if (next_eth_tx_queue_buffer) {
3179                wlan_mac_high_cdma_finish_transfer(); // Finish the previous CDMA operation into the next packet queue buffer
3180                queue_checkin(next_eth_tx_queue_buffer->pyld_queue_hdr.dle);
3181            }
3182            if (last_pkt_queue_buffer && (last_pkt_queue_buffer != next_eth_tx_queue_buffer)) {
3183                wlan_mac_high_cdma_finish_transfer(); // Finish the previous CDMA operation into the next packet queue buffer
3184                queue_checkin(last_pkt_queue_buffer->pyld_queue_hdr.dle);
3185            }
3186            break;
3187        }
3188
3189        if( ((pkt_idx+1) % LOG_TRANSFER_NUM_PKT_BURST) == 0 ){
3190            // Re-enable dequeueing from the wlan_exp Eth Tx queue
3191            //  This will move the program counter to the software interrupt ISR
3192            //   and other ISRs until the wlan_exp Eth Tx queue is completely
3193            //   empty
3194            wlan_platform_set_sw_intr_mask(SW_INTR_ID_WLAN_EXP_ETH_TX);
3195            // Disable dequeueing from the wlan_exp Eth Tx queue
3196            wlan_platform_clear_sw_intr_mask(SW_INTR_ID_WLAN_EXP_ETH_TX);
3197        }
3198
3199        // Update our current address and bytes remaining
3200        curr_index = next_index;
3201        sent_bytes += transfer_length;
3202    }
3203
3204    // Re-enable dequeueing from the wlan_exp Eth Tx queue
3205    wlan_platform_set_sw_intr_mask(SW_INTR_ID_WLAN_EXP_ETH_TX);
3206
3207    return resp_sent;
3208}
3209#endif //WLAN_SW_CONFIG_ENABLE_LOGGING
3210
3211void wlan_exp_reset_all_callbacks(){
3212    wlan_exp_process_node_cmd_callback = (function_ptr_t) _null_process_cmd_callback;
3213    wlan_exp_purge_all_wireless_tx_queue_callback = (function_ptr_t) wlan_exp_null_callback;
3214    wlan_exp_process_user_cmd_callback = (function_ptr_t) _null_process_cmd_callback;
3215    wlan_exp_beacon_ts_update_mode_callback = (function_ptr_t) wlan_exp_null_callback;
3216    wlan_exp_process_config_bss_callback = (function_ptr_t) wlan_exp_null_callback;
3217    wlan_exp_active_network_info_getter_callback = (function_ptr_t) wlan_exp_null_callback;
3218}
3219
3220void wlan_exp_set_process_node_cmd_callback(void(*callback)()){
3221    wlan_exp_process_node_cmd_callback = (function_ptr_t) callback;
3222}
3223
3224
3225void wlan_exp_set_purge_all_wireless_tx_queue_callback(void(*callback)()){
3226    wlan_exp_purge_all_wireless_tx_queue_callback = (function_ptr_t) callback;
3227}
3228
3229void wlan_exp_set_process_user_cmd_callback(void(*callback)()){
3230    wlan_exp_process_user_cmd_callback = (function_ptr_t) callback;
3231}
3232
3233
3234void wlan_exp_set_beacon_ts_update_mode_callback(void(*callback)()){
3235    wlan_exp_beacon_ts_update_mode_callback = (function_ptr_t) callback;
3236}
3237
3238
3239void wlan_exp_set_process_config_bss_callback(void(*callback)()){
3240    wlan_exp_process_config_bss_callback = (function_ptr_t) callback;
3241}
3242
3243void wlan_exp_set_active_network_info_getter_callback(void(*callback)()){
3244    wlan_exp_active_network_info_getter_callback = (function_ptr_t) callback;
3245}
3246
3247
3248/*****************************************************************************/
3249/**
3250 * This is a helper function to clean up the LTGs owned by WLAN Exp
3251 *
3252 * @param   id               - LTG id
3253 *          callback_arg     - Callback argument for LTG
3254 *
3255 * @return  None
3256 *
3257 *****************************************************************************/
3258void _ltg_cleanup(u32 id, void* callback_arg){
3259    wlan_mac_high_free(callback_arg);
3260}
3261
3262
3263
3264#endif        // End WLAN_SW_CONFIG_ENABLE_WLAN_EXP
Note: See TracBrowser for help on using the repository browser.