source: ReferenceDesigns/w3_802.11/c/wlan_mac_high_ap/wlan_mac_ap.c

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

1.8.0 release wlan-mac-se

File size: 101.1 KB
Line 
1/** @file wlan_mac_ap.c
2 *  @brief Access Point
3 *
4 *  This contains code for the 802.11 Access Point.
5 *
6 *  @copyright Copyright 2013-2019, Mango Communications. All rights reserved.
7 *          Distributed under the Mango Communications Reference Design License
8 *              See LICENSE.txt included in the design archive or
9 *              at http://mangocomm.com/802.11/license
10 *
11 *  This file is part of the Mango 802.11 Reference Design (https://mangocomm.com/802.11)
12 */
13
14// Xilinx SDK includes
15#include "stdlib.h"
16#include "string.h"
17#include "xil_cache.h"
18// 802.11 ref design headers
19#include "wlan_mac_high_sw_config.h"
20#include "wlan_mac_common.h"
21#include "wlan_platform_common.h"
22#include "wlan_platform_high.h"
23
24#include "wlan_mac_high.h"
25#include "wlan_mac_ap.h"
26#include "wlan_mac_addr_filter.h"
27#include "wlan_mac_ltg.h"
28#include "wlan_mac_event_log.h"
29#include "wlan_mac_schedule.h"
30#include "wlan_mac_queue.h"
31#include "wlan_mac_802_11_defs.h"
32#include "wlan_mac_packet_types.h"
33#include "wlan_mac_network_info.h"
34#include "wlan_mac_station_info.h"
35#include "wlan_mac_mgmt_tags.h"
36#include "wlan_mac_eth_util.h"
37#include "wlan_mac_scan.h"
38#include "wlan_mac_pkt_buf_util.h"
39#include "wlan_mac_entries.h"
40#include "wlan_mac_dl_list.h"
41
42#include "wlan_exp.h"
43#include "wlan_exp_node.h"
44#include "wlan_exp_node_ap.h"
45#include "wlan_exp_transport.h"
46
47
48/*************************** Constant Definitions ****************************/
49
50#define WLAN_DEFAULT_BSS_CONFIG_CHANNEL 1
51#define WLAN_DEFAULT_BSS_CONFIG_DTIM_PERIOD 2
52#define WLAN_DEFAULT_BSS_CONFIG_BEACON_INTERVAL 100
53// The WLAN_DEFAULT_BSS_CONFIG_HT_CAPABLE define will set the default
54// unicast TX phy mode to:  1 --> HTMF  or  0 --> NONHT.
55#define WLAN_DEFAULT_BSS_CONFIG_HT_CAPABLE 1
56
57#define WLAN_DEFAULT_TX_PWR 15
58#define WLAN_DEFAULT_TX_ANTENNA TX_ANTMODE_SISO_ANTA
59#define WLAN_DEFAULT_RX_ANTENNA RX_ANTMODE_SISO_ANTA
60
61
62/*********************** Global Variable Definitions *************************/
63
64
65/*************************** Variable Definitions ****************************/
66
67// SSID variables
68static char default_AP_SSID[] = "MANGO-AP";
69
70// "active_network_info" is a pointer to the network_info that describes this AP.
71// Inside this structure is a dl_list of members. This is a list
72// of all stations that are currently associated with this AP. In the
73// 802.11-2012 Section 10.3 parlance, these stations are currently
74// in State 4 (Authenticated, Associated). As part of the association
75// process, we want to track stations as they transition through the
76// 10.3 states. To do this, we'll create a totally separate dl_list of
77// station_info that represent stations in State 2
78// (Authenticated, Unassociated). Only members of this list will be allowed
79// to elevate to State 4 in the active_bss_info.
80network_info_t* active_network_info;
81
82dl_list authenticated_unassociated_stations;
83
84// Tx queue variables;
85u32 max_queue_size;
86volatile u8 pause_data_queue;
87
88// MAC address
89static u8 wlan_mac_addr[MAC_ADDR_LEN];
90
91// Traffic Indication Map (TIM) State
92// These global structs must be protected against externing. Any
93// modifications of these structs should be done via an explicit
94// setter that also updates the beacon template.
95static volatile mgmt_tag_template_t* mgmt_tag_tim_template;
96static volatile u32 mgmt_tag_tim_update_schedule_id;
97
98// Beacon configuration
99static beacon_txrx_config_t gl_beacon_txrx_config;
100
101// Static QIDs
102u16 mcast_qid;
103u16 mgmt_qid;
104
105// DTIM Multicast Buffer
106u8 gl_dtim_mcast_buffer_enable; // Enable buffering of multicast packets until after DTIM transmission
107u8 gl_cpu_low_supports_dtim_mcast; // Flag to indicate if DTIM multicast buffering is supported by the low-level MAC
108
109// Common Platform Device Info
110platform_common_dev_info_t platform_common_dev_info;
111
112/*************************** Functions Prototypes ****************************/
113
114#if WLAN_SW_CONFIG_ENABLE_WLAN_EXP
115int  wlan_exp_process_user_cmd(cmd_resp_hdr_t* cmd_hdr, eth_tx_queue_buffer_t* eth_tx_queue_buffer);
116#endif
117
118
119/******************************** Functions **********************************/
120
121int main(){
122
123    // Call the platform-supplied cpu_init() first to setup any
124    //  processor-specific settings to enable sane execution
125    //  of the platform and framework code below
126    wlan_platform_cpu_high_init();
127
128    u32              update_mask;
129    bss_config_t     bss_config;
130
131    xil_printf("\f");
132    xil_printf("----- Mango 802.11 Reference Design -----\n");
133    xil_printf("----- v1.8.0 ----------------------------\n");
134    xil_printf("----- wlan_mac_ap -----------------------\n");
135
136    xil_printf("Compiled %s %s\n\n", __DATE__, __TIME__);
137
138    // Heap Initialization
139    //    The heap must be initialized before any use of malloc. This explicit
140    //    init handles the case of soft-reset of the MicroBlaze leaving stale
141    //    values in the heap RAM
142    wlan_mac_common_malloc_init();
143
144    //Initialize the MAC framework
145    wlan_mac_high_init();
146
147    // Get the device info
148    platform_common_dev_info = wlan_platform_common_get_dev_info();
149
150    // Before any queue entries are used, calculate the maximum number of
151    // allowed enqueues based on the number that are free
152    max_queue_size = WLAN_MIN( queue_num_free(), MAX_TX_QUEUE_LEN );
153
154    // Open static queues for multicast and management frames
155    //  We will use a single queue for all multicast frames. The occupancy of this
156    //   queue will be reflecting in the TIM tag in beacons, so we must attach a
157    //   function callback to be notified when the queue changes
158    mcast_qid = queue_open((void*)queue_state_change, 0, max_queue_size);
159
160    //  We will use a queue for unicast management frames that are not addressed
161    //   to associated stations (e.g. a unicast probe response to a station
162    //   performing an active scan). Because there is no AID fo an unassociated
163    //   station, we do not need to be notified of occupancy changes for this
164    //   queue. So, we will attach the default null callback in the framework.
165    mgmt_qid  = queue_open((void*)wlan_null_callback, 0, max_queue_size);
166
167    pause_data_queue = 0;
168
169    gl_cpu_low_supports_dtim_mcast = 0;
170
171    //Set a sane default for the TIM tag byte offset
172    gl_beacon_txrx_config.dtim_tag_byte_offset = 0;
173
174    // AP does not currently advertise a BSS
175    configure_bss(NULL, 0);
176
177    // Initialize hex display to "No BSS"
178    wlan_platform_high_userio_disp_status(USERIO_DISP_STATUS_MEMBER_LIST_UPDATE, 0xFF);
179
180    // Set default Tx params
181    // Set sane default Tx params. These will be overwritten by the user application
182    tx_params_t tx_params = { .phy = { .mcs = 3, .phy_mode = PHY_MODE_HTMF, .antenna_mode = WLAN_DEFAULT_TX_ANTENNA, .power = WLAN_DEFAULT_TX_PWR },
183                              .mac = { .flags = 0 } };
184
185    wlan_mac_set_default_tx_params(unicast_data, &tx_params);
186
187    tx_params.phy.mcs = 0;
188    tx_params.phy.phy_mode = PHY_MODE_NONHT;
189
190    wlan_mac_set_default_tx_params(unicast_mgmt, &tx_params);
191    wlan_mac_set_default_tx_params(mcast_data, &tx_params);
192    wlan_mac_set_default_tx_params(mcast_mgmt, &tx_params);
193
194    // Re-apply the defaults to any existing station_info_t structs that this AP
195    // knows about
196    wlan_mac_reapply_default_tx_params();
197
198    // Initialize callbacks
199#if WLAN_SW_CONFIG_ENABLE_ETH_BRIDGE
200    wlan_mac_util_set_eth_rx_callback((void*)ethernet_receive);
201#endif
202    wlan_mac_high_set_mpdu_rx_callback((void*)mpdu_rx_process);
203    wlan_mac_high_set_press_pb_0_callback((void*)button_0_press);
204    wlan_mac_high_set_release_pb_0_callback((void*)button_0_release);
205    wlan_mac_high_set_uart_rx_callback((void*)uart_rx);
206    wlan_mac_high_set_poll_tx_queues_callback((void*)poll_tx_queues);
207    wlan_mac_high_set_mpdu_dequeue_callback((void*)mpdu_dequeue);
208#if WLAN_SW_CONFIG_ENABLE_LTG
209    wlan_mac_ltg_sched_set_callback((void*)ltg_event);
210#endif //WLAN_SW_CONFIG_ENABLE_LTG
211    wlan_mac_scan_set_state_change_callback((void*)process_scan_state_change);
212    wlan_mac_high_set_cpu_low_reboot_callback((void*)handle_cpu_low_reboot);
213    wlan_mac_high_set_tx_queue_state_change_callback((void*)queue_state_change);
214
215#if WLAN_SW_CONFIG_ENABLE_WLAN_EXP
216
217    // NOTE:  To use the WLAN Experiments Framework, it must be initialized after
218    //        CPU low has populated the hw_info structure in the MAC High framework.
219
220    // Initialize WLAN Exp
221    wlan_exp_node_init();
222
223    // Set WLAN Exp callbacks
224    wlan_exp_set_process_node_cmd_callback((void *) process_wlan_exp_app_cmd);
225    wlan_exp_set_purge_all_wireless_tx_queue_callback((void *) purge_all_wireless_tx_queue);
226    wlan_exp_set_process_user_cmd_callback((void *) wlan_exp_process_user_cmd);
227    //   - wlan_exp_set_beacon_ts_update_mode_callback()  currently not supported by the AP
228    wlan_exp_set_process_config_bss_callback((void *) configure_bss);
229    wlan_exp_set_active_network_info_getter_callback((void *) active_network_info_getter);
230
231    // Set CPU_HIGH Type in wlan_exp's node_info struct;
232    wlan_exp_node_set_type_high(APPLICATION_ROLE_AP, __DATE__, __TIME__);
233
234#endif
235
236    memcpy((void*) &(wlan_mac_addr[0]), (void*) get_mac_hw_addr_wlan(), MAC_ADDR_LEN);
237
238    // Set the at-boot MAC Time to 0 usec
239    set_mac_time_usec(0);
240
241    wlan_mac_high_set_radio_channel(WLAN_DEFAULT_BSS_CONFIG_CHANNEL);
242    wlan_mac_high_set_rx_ant_mode(WLAN_DEFAULT_RX_ANTENNA);
243    wlan_mac_high_set_tx_ctrl_power(WLAN_DEFAULT_TX_PWR);
244    wlan_mac_high_set_radio_tx_power(WLAN_DEFAULT_TX_PWR);
245
246    // Initialize TIM management tag that will be postpended to a beacon
247    mgmt_tag_tim_update_schedule_id = SCHEDULE_ID_RESERVED_MAX;
248    mgmt_tag_tim_template = NULL;
249
250    //  Periodic check for timed-out associations
251    wlan_mac_schedule_add_event(SCHEDULE_ID_COARSE, ASSOCIATION_CHECK_INTERVAL_US, SCHEDULE_REPEAT_FOREVER, (void*)remove_inactive_station_infos);
252
253    wlan_platform_high_userio_disp_status(USERIO_DISP_STATUS_APPLICATION_ROLE, APPLICATION_ROLE_AP);
254
255#if WLAN_SW_CONFIG_ENABLE_LOGGING
256    // Reset the event log
257    event_log_reset();
258#endif //WLAN_SW_CONFIG_ENABLE_LOGGING
259
260    // If the DIP switch allows it, set up BSS description
261    if ((wlan_platform_userio_get_state() & USERIO_INPUT_MASK_SW_3) == 0) {
262        memcpy(bss_config.bssid, wlan_mac_addr, MAC_ADDR_LEN);
263        strncpy(bss_config.ssid, default_AP_SSID, SSID_LEN_MAX);
264
265        bss_config.chan_spec.chan_pri  = WLAN_DEFAULT_BSS_CONFIG_CHANNEL;
266        bss_config.chan_spec.chan_type = CHAN_TYPE_BW20;
267        bss_config.ht_capable          = WLAN_DEFAULT_BSS_CONFIG_HT_CAPABLE;
268        bss_config.beacon_interval     = WLAN_DEFAULT_BSS_CONFIG_BEACON_INTERVAL;
269        bss_config.dtim_period         = WLAN_DEFAULT_BSS_CONFIG_DTIM_PERIOD;
270
271        update_mask = (BSS_FIELD_MASK_BSSID              |
272                       BSS_FIELD_MASK_CHAN               |
273                       BSS_FIELD_MASK_SSID               |
274                       BSS_FIELD_MASK_BEACON_INTERVAL    |
275                       BSS_FIELD_MASK_HT_CAPABLE         |
276                       BSS_FIELD_MASK_DTIM_PERIOD);
277        configure_bss(&bss_config, update_mask);
278    }
279
280    gl_dtim_mcast_buffer_enable = 1;
281    wlan_mac_high_enable_mcast_buffering(gl_dtim_mcast_buffer_enable);
282
283    // Print AP information to the terminal
284
285    xil_printf("------------------------\n");
286    xil_printf("WLAN MAC AP boot complete\n");
287
288#ifdef WLAN_USE_UART_MENU
289    xil_printf("\nPress the Esc key in your terminal to access the UART menu\n");
290#endif
291
292    // Finally enable all interrupts to start handling wireless and wired traffic
293    wlan_platform_intc_set_state(INTERRUPTS_ENABLED);
294
295    while(1) {
296        wlan_mac_poll();
297    }
298
299    // Unreachable, but non-void return keeps the compiler happy
300    return WLAN_FAILURE;
301}
302
303
304/*****************************************************************************/
305/**
306 * @brief Handle state change in the network scanner
307 *
308 * This function is part of the scan infrastructure and will be called whenever
309 * the scanner is started, stopped, paused, or resumed. This allows the STA
310 * to revert the channel to a known-good state when the scanner has stopped and
311 * also serves as notification to the project that it should stop dequeueing data
312 * frames since it might be on a different channel than its intended recipient.
313 *
314 * @param   None
315 * @return  None
316 *
317 *****************************************************************************/
318void process_scan_state_change(scan_state_t scan_state){
319
320    // ------------------------------------------------------------------------
321    // Note on scanning:
322    //
323    //   Currently, scanning should only be done with active_bss_info = NULL, ie the
324    // node is not currently in a BSS.  This is to avoid any corner cases.  The
325    // AP needs to do the following things to make scanning safe when active_bss_info
326    // is not NULL:
327    //
328    //     - Pause outgoing data queues
329    //     - Pause beacon transmissions in CPU_LOW
330    //     - Refuse to enqueue probe responses when a probe request is received off channel
331    //     - Pause dequeue of probe responses when off channel
332    //       - Note: Currently, this is difficult because probe responses share a
333    //             queue with probe requests which are needed for active scans
334    //
335    // ------------------------------------------------------------------------
336
337    switch(scan_state){
338        case SCAN_IDLE:
339        case SCAN_PAUSED:
340            pause_data_queue = 0;
341            if(active_network_info != NULL){
342                wlan_mac_high_set_radio_channel(
343                        wlan_mac_high_bss_channel_spec_to_radio_chan(active_network_info->bss_config.chan_spec));
344            }
345        break;
346        case SCAN_RUNNING:
347            pause_data_queue = 1;
348        break;
349    }
350}
351
352/*****************************************************************************/
353/**
354 * @brief Handle queue occupancy change
355 *
356 * Beacons must contain a TIM tag that dedicates one bit per associated station
357 * that indicates whether any downlink traffic is enqueued for that station.
358 * This allows stations to save power by dozing during beacon intervals and wake
359 * up only when they know downlink traffic is ready for them
360 *
361 * This function can be attached to a queue so that is called whenever the queue
362 * transitions from empty to 1 packet or vice versa.
363 *
364 * @param   u32 aid - the framework will call this function with the callback
365 *                    argument provided during queue_open(). This application
366 *                    chooses to let that argument be the AID for that queue
367 * @param   u32 queue_len - 0 if the queue is now empty, 1 if the queue now has
368 *                          a single entry
369 * @return  None
370 *****************************************************************************/
371void queue_state_change(u32 aid, u32 queue_len){
372    //queue_len will take on a value of 0 or 1
373    //and represents the state of the queue after the state
374    //changes.
375
376    if(mgmt_tag_tim_update_schedule_id != SCHEDULE_ID_RESERVED_MAX){
377        //We already have a pending full TIM state re-write scheduled, so we won't bother
378        //with a per-queue change.
379        return;
380    }
381
382    if(mgmt_tag_tim_template == NULL){
383        //The TIM tag is not present in the current beacon template.
384        //We have no choice but to do a full TIM tag update and write.
385        update_tim_tag_all(SCHEDULE_ID_RESERVED_MAX);
386    } else {
387        //There is a TIM tag that is already present. We can update
388        //only the relevant byte that applies to this queue state
389        //change
390        update_tim_tag_aid(aid, queue_len);
391    }
392}
393
394
395
396/*****************************************************************************/
397/**
398 *
399 *****************************************************************************/
400inline void update_tim_tag_aid(u8 aid, u8 bit_val_in){
401
402    // The intention of this function is to modify as little of an existing TIM
403    // tag in the beacon template packet buffer as possible to reduce the amount
404    // of time that CPU could be waiting on the packet buffer to be unlocked.
405    //
406    //Note: AID = 0 is invalid. And input of 0 to this function
407    //indicates that the multicast bit in the tim_control byte should
408    //be modified if DTIM mcast buffering is currently disabled. Otherwise,
409    //CPU_LOW will maintain this bit.
410
411    u32 existing_mgmt_tag_length = 0; // Size of the management tag that is currently in the packet buffer
412    u8 tim_control = 0;
413    u16 tim_byte_idx = 0;
414    u8 tim_bit_idx = 0;
415    u8 bit_val = (bit_val_in & 1);
416    tx_frame_info_t* tx_frame_info = (tx_frame_info_t*)CALC_PKT_BUF_ADDR(platform_common_dev_info.tx_pkt_buf_baseaddr, TX_PKT_BUF_BEACON);
417
418    if(active_network_info == NULL) return;
419    if( ((aid==0) && (gl_dtim_mcast_buffer_enable == 1)) ) return;
420
421    //First, we should determine whether a call to update_tim_tag_all_tag_all is scheduled
422    //for some time in the future. If it is, we can just return immediately and let that
423    //execution clean up any pending TIM state changes.
424    if(mgmt_tag_tim_update_schedule_id != SCHEDULE_ID_RESERVED_MAX){
425        return;
426    }
427
428    if(mgmt_tag_tim_template == NULL){
429        //There currently isn't any TIM tag in the packet buffer, which means
430        //that we need to restore the full state and not toggle a single
431        //bit
432        update_tim_tag_all(SCHEDULE_ID_RESERVED_MAX);
433        return;
434    }
435
436    //There exists a TIM tag in the beacon. We should determine its length
437    existing_mgmt_tag_length    = mgmt_tag_tim_template->header.tag_length;
438    tim_byte_idx                = aid / 8;
439
440    if((tim_byte_idx + 4U) > existing_mgmt_tag_length){
441        //The current byte we intend to modify is larger than the existing tag. In this case,
442        //we fall back on the update_tim_tag_all function since we cannnot simply modify a single
443        //bit.
444        update_tim_tag_all(SCHEDULE_ID_RESERVED_MAX);
445        return;
446    }
447
448    if( ((tx_frame_info->tx_pkt_buf_state != TX_PKT_BUF_READY) && (tx_frame_info->tx_pkt_buf_state != TX_PKT_BUF_HIGH_CTRL) ) || (lock_tx_pkt_buf(TX_PKT_BUF_BEACON) != PKT_BUF_MUTEX_SUCCESS)){
449        //Note: The order of operations in the above if() clause is important. If the tx_pkt_buf_state is not ready.
450        //then we should not even attempt to lock the beacon template packet buffer. This behavior is ensured if
451        //the tx_pkt_buf_state is checked on on the left-hand side of the || because the || operation is a sequence
452        //point in C.
453
454        //CPU_LOW currently has the beacon packet buffer locked, which means that it is actively
455        //transmitting the beacon and it is not safe to modify the contents of the packet. We will
456        //use the scheduler to call update_tim_tag_all() sometime later when it is likely that the
457        //packet buffer is no longer locked.
458        mgmt_tag_tim_update_schedule_id = wlan_mac_schedule_add_event(SCHEDULE_ID_FINE,
459                                                                           (active_network_info->bss_config.beacon_interval * BSS_MICROSECONDS_IN_A_TU) / 4,
460                                                                           1,
461                                                                           (void*)update_tim_tag_all);
462        return;
463    }
464
465    // If we have made it this far into the function, then we know that the TIM tag currently
466    // exists in the beacon template packet buffer, the mgmt_tag_tim_template is non-NULL, and
467    // finally that the TIM tag is long enough that we can simply modify bit(s) that correspond
468    // to the AID argument of the function.
469
470    if(aid == 0){
471        if(bit_val){
472            tim_control |= 0x01; //Raise the multicast bit in the TIM control field
473            mgmt_tag_tim_template->data[2] = tim_control;           //TIM Control (top 7 bits are offset for partial map)
474            mgmt_tag_tim_template->data[3] |= tim_control&1;        //Per 10.2.1.3 in 802.11-2012: AID 0 is treated as
475                                                                    //the multicast buffer state
476        } else {
477            tim_control = 0;
478            mgmt_tag_tim_template->data[2] = tim_control;           //TIM Control (top 7 bits are offset for partial map)
479            mgmt_tag_tim_template->data[3] &= ~(tim_control&1);     //Per 10.2.1.3 in 802.11-2012: AID 0 is treated as
480                                                                    //the multicast buffer state
481        }
482    } else {
483        if(bit_val){
484            mgmt_tag_tim_template->data[3+tim_byte_idx] |= 1<<tim_bit_idx;
485        } else {
486            mgmt_tag_tim_template->data[3+tim_byte_idx] &= ~(1<<tim_bit_idx);
487        }
488    }
489
490    if(unlock_tx_pkt_buf(TX_PKT_BUF_BEACON) != PKT_BUF_MUTEX_SUCCESS){
491        xil_printf("Error: Unable to unlock Beacon packet buffer during update_tim_tag_all\n");
492    }
493    return;
494
495}
496
497
498
499/*****************************************************************************/
500/**
501 *
502 *****************************************************************************/
503void update_tim_tag_all(u32 sched_id){
504
505    tx_frame_info_t* tx_frame_info = (tx_frame_info_t*)CALC_PKT_BUF_ADDR(platform_common_dev_info.tx_pkt_buf_baseaddr, TX_PKT_BUF_BEACON);
506    u32 existing_mgmt_tag_length = 0; // Size of the management tag that is currently in the packet buffer
507    u32 next_mgmt_tag_length = 0; // Size that we will update the management tag to be.
508                                                            // Note: a third size we have to track is present in the global mgmt_tag_tim
509    station_info_entry_t* curr_station_entry;
510    station_info_t* station_info;
511    u8 tim_control;
512    u32 i;
513    u16 tim_byte_idx = 0;
514    u16 tim_next_byte_idx = 0;
515    u8 tim_bit_idx = 0;
516
517    if(active_network_info == NULL) return;
518    if(sched_id == SCHEDULE_ID_RESERVED_MAX){
519        //This function was called manually (not via the scheduler)
520
521        //First, we should determine whether a call to update_tim_tag_all is scheduled
522        //for some time in the future. If it is, we can just return immediately and let that
523        //execution clean up any pending TIM state changes.
524        if(mgmt_tag_tim_update_schedule_id != SCHEDULE_ID_RESERVED_MAX){
525            return;
526        }
527    }
528
529    mgmt_tag_tim_update_schedule_id = SCHEDULE_ID_RESERVED_MAX;
530
531    if( ((tx_frame_info->tx_pkt_buf_state != TX_PKT_BUF_READY) && (tx_frame_info->tx_pkt_buf_state != TX_PKT_BUF_HIGH_CTRL) ) || (lock_tx_pkt_buf(TX_PKT_BUF_BEACON) != PKT_BUF_MUTEX_SUCCESS)){
532        //Note: The order of operations in the above if() clause is important. If the tx_pkt_buf_state is not ready.
533        //then we should not even attempt to lock the beacon template packet buffer. This behavior is ensured if
534        //the tx_pkt_buf_state is checked on on the left-hand side of the || because the || operation is a sequence
535        //point in C.
536
537        //CPU_LOW currently has the beacon packet buffer locked, which means that it is actively
538        //transmitting the beacon and it is not safe to modify the contents of the packet. We will
539        //use the scheduler to call update_tim_tag_all() sometime later when it is likely that the
540        //packet buffer is no longer locked.
541        mgmt_tag_tim_update_schedule_id = wlan_mac_schedule_add_event(SCHEDULE_ID_FINE,
542                                                                           (active_network_info->bss_config.beacon_interval * BSS_MICROSECONDS_IN_A_TU) / 4,
543                                                                           1,
544                                                                           (void*)update_tim_tag_all);
545        return;
546    }
547
548    if(mgmt_tag_tim_template != NULL){
549        //There exists a TIM tag in the beacon. We should determine its length
550        existing_mgmt_tag_length = mgmt_tag_tim_template->header.tag_length;
551    }
552
553    //----------------------------------
554    // 1. We will refresh the full state of the TIM tag based upon queue occupancy
555
556    //We'll start updating the TIM tag from the last associated station.
557    //Since we know that the WLAN MAC High Framework keeps the dl_list of
558    //associated stations in increasing AID order, we can use this final
559    //station's AID to define the size of the TIM tag.
560    curr_station_entry = (station_info_entry_t*)(active_network_info->members.last);
561
562    if(curr_station_entry != NULL){
563        station_info = (station_info_t*)(curr_station_entry->data);
564        next_mgmt_tag_length = 4 + ((station_info->ID) / 8);
565    } else {
566        next_mgmt_tag_length = 4;
567    }
568
569    if(mgmt_tag_tim_template == NULL){
570        //We need to add the tag to the end of the beacon template
571        //and update the length field of the tx_frame_info.
572        mgmt_tag_tim_template = (mgmt_tag_template_t*)((void*)(tx_frame_info)
573                                                +PHY_TX_PKT_BUF_MPDU_OFFSET
574                                                +tx_frame_info->length
575                                                -WLAN_PHY_FCS_NBYTES);
576        gl_beacon_txrx_config.dtim_tag_byte_offset = (u16)((u32)mgmt_tag_tim_template - (u32)tx_frame_info);
577
578        mgmt_tag_tim_template->header.tag_element_id    = MGMT_TAG_TIM;
579        tx_frame_info->length += sizeof(mgmt_tag_header);
580    }
581
582    mgmt_tag_tim_template->header.tag_length        = next_mgmt_tag_length;
583
584    tim_control = 0; //The top 7 bits are an offset for the partial map
585
586    if((gl_dtim_mcast_buffer_enable == 0) && (queue_length(mcast_qid)>0)){
587        //If mcast buffering is disabled, the AP is responsible for maintaining the
588        //mcast bit in the TIM control
589        tim_control |= 0x01; //Raise the multicast bit in the TIM control field
590    }
591
592    curr_station_entry = (station_info_entry_t*)(active_network_info->members.first);
593    while(curr_station_entry != NULL){
594        station_info = (station_info_t*)(curr_station_entry->data);
595
596        if(queue_length(station_info->QID)){
597            tim_next_byte_idx = (station_info->ID) / 8;
598
599            if(tim_next_byte_idx > tim_byte_idx){
600                //We've moved on to a new octet. We should zero everything after the previous octet
601                //up to and including the new octet.
602                for(i = tim_byte_idx+1; i <= tim_next_byte_idx; i++){
603                    mgmt_tag_tim_template->data[3+i] = 0;
604                }
605            }
606
607            tim_bit_idx  = (station_info->ID) % 8;
608            tim_byte_idx = tim_next_byte_idx;
609
610            //Raise the bit for this station in the TIM partial bitmap
611            mgmt_tag_tim_template->data[3+tim_byte_idx] |= 1<<tim_bit_idx;
612        }
613
614        curr_station_entry = dl_entry_next(curr_station_entry);
615    }
616
617    //mgmt_tag_tim_template->data[0] = gl_beacon_txrx_config.dtim_count; //Note: this field is going to be maintained by CPU_LOW, so it doesn't matter
618                                                                         // if we write anything to it.
619    mgmt_tag_tim_template->data[1] = gl_beacon_txrx_config.dtim_period;
620    mgmt_tag_tim_template->data[2] = tim_control;       //TIM Control (top 7 bits are offset for partial map)
621    if(gl_dtim_mcast_buffer_enable == 0){
622        mgmt_tag_tim_template->data[3] |= tim_control&1;    //Per 10.2.1.3 in 802.11-2012: AID 0 is treated as
623                                                            //the multicast buffer state
624    }
625    tx_frame_info->length += (next_mgmt_tag_length - existing_mgmt_tag_length);
626
627    if(unlock_tx_pkt_buf(TX_PKT_BUF_BEACON) != PKT_BUF_MUTEX_SUCCESS){
628        xil_printf("Error: Unable to unlock Beacon packet buffer during update_tim_tag_all\n");
629    }
630    return;
631
632}
633
634/*****************************************************************************/
635/**
636 * @brief Poll Tx queues to select next available packet to transmit
637 *
638 * This function attempts to completely fill any available Tx packet buffers. If
639 * DTIM multicast buffering is enabled, it will attempt to dequeue as many multicast
640 * packets as possible such that PKT_BUF_GROUP_DTIM_MCAST packet buffer group is full
641 * or the multicast queue is empty (whichever comes first). The PKT_BUF_GROUP_GENERAL
642 * packet buffer group will be filled with frames with a nested round-robing policy:
643 *  1) The function will alternate between dequeueing management and data frames in order
644 *     to prioritize time-critical management responses like authentication and assocation
645 *     response frames.
646 *  2) Data frames will be dequeued round-robin for each associated station. If DTIM multicast
647 *     buffering is disabled, the multicast queue will be treated like an associated station in
648 *     this policy.
649 *
650 *****************************************************************************/
651#define NUM_QUEUE_GROUPS 2
652typedef enum queue_group_t{
653    MGMT_QGRP,
654    DATA_QGRP
655} queue_group_t;
656
657void poll_tx_queues(){
658    interrupt_state_t curr_interrupt_state;
659    dl_entry* tx_queue_entry;
660    u32 u_i;
661    s32 s_i;
662
663    int num_pkt_bufs_avail;
664    int poll_loop_cnt;
665
666    // Remember the next group to poll between calls to this function
667    //   This implements the ping-pong poll between the MGMT_QGRP and DATA_QGRP groups
668    static queue_group_t next_queue_group = MGMT_QGRP;
669    queue_group_t curr_queue_group;
670
671    // Remember the last queue polled between calls to this function
672    //   This implements the round-robin poll of queues in the DATA_QGRP group
673    static station_info_entry_t* next_station_info_entry = NULL;
674    station_info_entry_t* curr_station_info_entry;
675
676    station_info_t* curr_station_info;
677
678    // Stop interrupts for all processing below - this avoids many possible race conditions,
679    //  like new packets being enqueued or stations joining/leaving the BSS
680    curr_interrupt_state = wlan_platform_intc_stop();
681
682    // First handle the general packet buffer group
683    num_pkt_bufs_avail = wlan_mac_num_tx_pkt_buf_available(PKT_BUF_GROUP_GENERAL);
684
685    // This loop will (at most) check every queue twice
686    //  This handles the case of a single non-empty queue needing to supply packets
687    //  for both GENERAL packet buffers
688    poll_loop_cnt = 0;
689    while((num_pkt_bufs_avail > 0) && (poll_loop_cnt < (2*NUM_QUEUE_GROUPS))) {
690        poll_loop_cnt++;
691        curr_queue_group = next_queue_group;
692
693        if(curr_queue_group == MGMT_QGRP) {
694            // Poll the management queue on this loop, data queues on next loop
695            next_queue_group = DATA_QGRP;
696            tx_queue_entry = queue_dequeue(mgmt_qid);
697            if(tx_queue_entry) {
698                // Update the packet buffer group
699                ((tx_80211_queue_buffer_t*)(tx_queue_entry->data))->tx_queue_details.pkt_buf_group = PKT_BUF_GROUP_GENERAL;
700                // Successfully dequeued a management packet - transmit and checkin
701                wlan_mac_transmit_wireless(tx_queue_entry);
702                //continue the loop
703                num_pkt_bufs_avail--;
704                continue;
705            }
706        } else {
707            // Poll the data queues on this loop, management queue on next loop
708            next_queue_group = MGMT_QGRP;
709
710            if(pause_data_queue) {
711                // Data queues are paused - skip any dequeue attempts and continue the loop
712                continue;
713            }
714
715            for(u_i = 0; u_i < (active_network_info->members.length + 1); u_i++) {
716                // Resume polling data queues from where we stopped on the previous call
717                curr_station_info_entry = next_station_info_entry;
718
719                // Loop through all associated stations' queues and the broadcast queue
720                if(curr_station_info_entry == NULL) {
721                    next_station_info_entry = (station_info_entry_t*)(active_network_info->members.first);
722
723                    // Only check the multicast queue in this loop when DTIM Multicast Buffering is disabled
724                    if( gl_dtim_mcast_buffer_enable && gl_cpu_low_supports_dtim_mcast && (gl_beacon_txrx_config.beacon_tx_mode != NO_BEACON_TX)) {
725                        // DTIM multicast buffering is enabled - skip the multicast queue
726                        continue;
727                    } else {
728                        tx_queue_entry = queue_dequeue(mcast_qid);
729                        if(tx_queue_entry) {
730                            // Update the packet buffer group
731                            ((tx_80211_queue_buffer_t*)(tx_queue_entry->data))->tx_queue_details.pkt_buf_group = PKT_BUF_GROUP_GENERAL;
732                            // Successfully dequeued a management packet - transmit and checkin
733                            wlan_mac_transmit_wireless(tx_queue_entry);
734                            // Successfully dequeued a multicast packet - end the DATA_QGRP loop
735                            num_pkt_bufs_avail--;
736                            break;
737                        }
738                    }
739
740                } else {
741                    // Check the queue for an associated station
742                    curr_station_info = (station_info_t*)(curr_station_info_entry->data);
743
744                    if( station_info_is_member(&active_network_info->members, curr_station_info)) {
745                        if(curr_station_info_entry == (station_info_entry_t*)(active_network_info->members.last)){
746                            // We've reached the end of the table, so we wrap around to the beginning
747                            next_station_info_entry = NULL;
748                        } else {
749                            next_station_info_entry = dl_entry_next(curr_station_info_entry);
750                        }
751
752                        if((curr_station_info->ps_state & STATION_INFO_PS_STATE_DOZE) == 0) {
753
754                            tx_queue_entry = queue_dequeue(curr_station_info->QID);
755                            if(tx_queue_entry) {
756                                // Update the packet buffer group
757                                ((tx_80211_queue_buffer_t*)(tx_queue_entry->data))->tx_queue_details.pkt_buf_group = PKT_BUF_GROUP_GENERAL;
758                                // Successfully dequeued a management packet - transmit and checkin
759                                wlan_mac_transmit_wireless(tx_queue_entry);
760                                // Successfully dequeued a unicast packet for this station - end the DATA_QGRP loop
761                                num_pkt_bufs_avail--;
762                                break;
763                            }
764                        }
765                    } else {
766                        // This curr_station_info is invalid. Perhaps it was removed from
767                        // the association table before poll_tx_queues was called. We will
768                        // start the round robin checking back at broadcast.
769                        next_station_info_entry = NULL;
770                    } // END if(curr_station_info is BSS member)
771                } // END if(multicast queue or station queue)
772            } // END for loop over association table
773        } // END if(MGMT or DATA queue group)
774    } // END while(buffers available && keep polling)
775
776
777    // Next handle the DTIM Multicast packet buffer group
778    if(gl_dtim_mcast_buffer_enable && gl_cpu_low_supports_dtim_mcast && (gl_beacon_txrx_config.beacon_tx_mode != NO_BEACON_TX)) {
779
780        num_pkt_bufs_avail = wlan_mac_num_tx_pkt_buf_available(PKT_BUF_GROUP_DTIM_MCAST);
781
782        for(s_i=0; s_i<num_pkt_bufs_avail; s_i++) {
783            // Dequeue packets until there are no more packet buffers or no more packets
784            tx_queue_entry = queue_dequeue(mcast_qid);
785            if(tx_queue_entry) {
786                // Update the packet buffer group
787                ((tx_80211_queue_buffer_t*)(tx_queue_entry->data))->tx_queue_details.pkt_buf_group = PKT_BUF_GROUP_DTIM_MCAST;
788                // Successfully dequeued a management packet - transmit and checkin
789                wlan_mac_transmit_wireless(tx_queue_entry);
790            } else {
791                // Queue is empty - end this loop
792                break;
793            }
794        }
795    }
796
797    wlan_platform_intc_set_state(curr_interrupt_state);
798}
799
800
801
802/*****************************************************************************/
803/**
804 * @brief Purges all packets from all Tx queues
805 *
806 * This function discards all currently en-queued packets awaiting transmission and returns all
807 * queue entries to the free pool.
808 *
809 * This function does not discard packets already submitted to the lower-level MAC for transmission
810 *
811 * @param None
812 * @return None
813 *****************************************************************************/
814void purge_all_wireless_tx_queue(){
815    station_info_entry_t* curr_station_info_entry;
816    station_info_t* curr_station_info;
817
818    if(active_network_info == NULL) return;
819
820    int iter = active_network_info->members.length;
821
822    // Purge all data transmit queues
823    wlan_mac_purge_wireless_tx(mcast_qid);
824    wlan_mac_purge_wireless_tx(mgmt_qid);
825    curr_station_info_entry = (station_info_entry_t*)(active_network_info->members.first);
826
827    while( (curr_station_info_entry != NULL) && (iter-- > 0)){
828        curr_station_info = curr_station_info_entry->data;
829        wlan_mac_purge_wireless_tx(curr_station_info->QID);
830        curr_station_info_entry = dl_entry_next(curr_station_info_entry);
831    }
832}
833#if WLAN_SW_CONFIG_ENABLE_LTG
834/*****************************************************************************/
835/**
836 * @brief Callback to handle new Local Traffic Generator event
837 *
838 * This function is called when the LTG scheduler determines a traffic generator should create a new packet. The
839 * behavior of this function depends entirely on the LTG payload parameters.
840 *
841 * The reference implementation defines 3 LTG payload types:
842 *  - LTG_PYLD_TYPE_FIXED: generate 1 fixed-length packet to single destination; callback_arg is pointer to ltg_pyld_fixed struct
843 *  - LTG_PYLD_TYPE_UNIFORM_RAND: generate 1 random-length packet to single destination; callback_arg is pointer to ltg_pyld_uniform_rand_t struct
844 *  - LTG_PYLD_TYPE_ALL_ASSOC_FIXED: generate 1 fixed-length packet to each associated station; callback_arg is pointer to ltg_pyld_all_assoc_fixed_t struct
845 *
846 * @param u32 id
847 *  - Unique ID of the previously created LTG
848 * @param void* callback_arg
849 *  - Callback argument provided at LTG creation time; interpretation depends on LTG type
850 * @return None
851 *****************************************************************************/
852void ltg_event(u32 id, void* callback_arg){
853
854    u32 payload_length;
855    u8* addr_ra;
856    u16 duration;
857    u32 min_ltg_payload_length;
858    station_info_t* station_info = NULL;
859    station_info_entry_t* station_info_entry = NULL;
860    u8 is_multicast;
861    u8 queue_id;
862    dl_entry* tx_queue_entry = NULL;
863    tx_80211_queue_buffer_t* tx_queue_buffer = NULL;
864    u8 continue_loop;
865    u16 flags = TX_80211_QUEUE_BUFFER_FLAGS_FILL_UNIQ_SEQ;
866
867    if(((ltg_pyld_hdr_t*)callback_arg)->type == LTG_PYLD_TYPE_CTRL_RESP){
868
869        tx_queue_entry = queue_checkout();
870        if(tx_queue_entry != NULL){
871            tx_queue_buffer = ((tx_80211_queue_buffer_t*)(tx_queue_entry->data));
872
873            addr_ra = ((ltg_pyld_ctrl_resp_t*)callback_arg)->addr_ra;
874            duration = ((ltg_pyld_ctrl_resp_t*)callback_arg)->duration;
875
876            if(((ltg_pyld_ctrl_resp_t*)callback_arg)->subtype == LTG_PYLD_CTRL_RESP_SUBTYPE_CTS){
877
878                payload_length = wlan_create_cts_frame(tx_queue_buffer->pkt,
879                                                       addr_ra,
880                                                       duration);
881
882                tx_queue_buffer->flags = TX_80211_QUEUE_BUFFER_FLAGS_TYPE_CTS;
883
884            } else { //LTG_PYLD_CTRL_RESP_SUBTYPE_ACK
885                payload_length = wlan_create_ack_frame(tx_queue_buffer->pkt,
886                                                       addr_ra);
887                tx_queue_buffer->flags = TX_80211_QUEUE_BUFFER_FLAGS_TYPE_ACK;
888            }
889
890            // Fill in metadata
891            tx_queue_buffer->flags |= TX_80211_QUEUE_BUFFER_FLAGS_BYPASS_RECOVERY;
892            tx_queue_buffer->length = payload_length;
893            tx_queue_buffer->seg0_len = payload_length;
894            tx_queue_buffer->seg1_len = 0;
895            tx_queue_buffer->seg1_offset = 0;
896
897            // With LTG_PYLD_TYPE_CTRL_RESP, we will transmit to the receive address (addr_ra) regardless of
898            // whether that address is an AP that we are associated to. To do that, we need to make sure that
899            // a station_info_t exists for that address
900            tx_queue_buffer->station_info = station_info_create(addr_ra);
901
902            wlan_mac_enqueue_wireless_tx(mgmt_qid, tx_queue_entry);
903
904        }
905    } else {
906
907        if(active_network_info != NULL){
908            u8* addr_da;
909            switch(((ltg_pyld_hdr_t*)callback_arg)->type){
910                case LTG_PYLD_TYPE_FIXED:
911                    payload_length = ((ltg_pyld_fixed_t*)callback_arg)->length;
912                    addr_da = ((ltg_pyld_fixed_t*)callback_arg)->addr_da;
913
914                    station_info = station_info_create(addr_da);
915
916                    is_multicast = wlan_addr_mcast(addr_da);
917                    if(is_multicast){
918                        queue_id = mcast_qid;
919                    } else {
920                        flags |= TX_80211_QUEUE_BUFFER_FLAGS_FILL_DURATION;
921                        if(station_info_is_member(&active_network_info->members, station_info)){
922                            queue_id = station_info->QID;
923                        } else {
924                            return;
925                        }
926                    }
927                break;
928
929                case LTG_PYLD_TYPE_UNIFORM_RAND:
930                    payload_length = (rand()%(((ltg_pyld_uniform_rand_t*)(callback_arg))->max_length - ((ltg_pyld_uniform_rand_t*)(callback_arg))->min_length))+((ltg_pyld_uniform_rand_t*)(callback_arg))->min_length;
931                    addr_da = ((ltg_pyld_fixed_t*)callback_arg)->addr_da;
932
933                    station_info = station_info_create(addr_da);
934
935                    is_multicast = wlan_addr_mcast(addr_da);
936                    if(is_multicast){
937                        queue_id = mcast_qid;
938                    } else {
939                        flags |= TX_80211_QUEUE_BUFFER_FLAGS_FILL_DURATION;
940                        if(station_info_is_member(&active_network_info->members, station_info)){
941                            queue_id = station_info->QID;
942                        } else {
943                            return;
944                        }
945                    }
946                break;
947
948                case LTG_PYLD_TYPE_ALL_ASSOC_FIXED:
949                    if(active_network_info->members.length > 0){
950                        flags |= TX_80211_QUEUE_BUFFER_FLAGS_FILL_DURATION;
951                        station_info_entry = (station_info_entry_t*)(active_network_info->members.first);
952                        station_info = (station_info_t*)station_info_entry->data;
953                        addr_da = station_info_entry->addr;
954                        queue_id = station_info->QID;
955                        is_multicast = 0;
956                        payload_length = ((ltg_pyld_all_assoc_fixed_t*)callback_arg)->length;
957                    } else {
958                        return;
959                    }
960                break;
961
962                default:
963                    xil_printf("ERROR ltg_event: Unknown LTG Payload Type! (%d)\n", ((ltg_pyld_hdr_t*)callback_arg)->type);
964                    return;
965                break;
966            }
967
968            do{
969                continue_loop = 0;
970
971                if(queue_length(queue_id) < max_queue_size){
972                    // Checkout 1 element from the queue;
973                    tx_queue_entry = queue_checkout();
974                    if(tx_queue_entry != NULL){
975
976                        // Create LTG packet
977                        tx_queue_buffer = ((tx_80211_queue_buffer_t*)(tx_queue_entry->data));
978
979                        min_ltg_payload_length = wlan_create_ltg_frame(tx_queue_buffer->pkt,
980                                                                       addr_da,
981                                                                       wlan_mac_addr,
982                                                                       wlan_mac_addr,
983                                                                       MAC_FRAME_CTRL2_FLAG_FROM_DS,
984                                                                       id);
985
986                        payload_length = WLAN_MAX(payload_length+sizeof(mac_header_80211)+WLAN_PHY_FCS_NBYTES, min_ltg_payload_length);
987
988
989
990                        // Fill in metadata
991                        tx_queue_buffer->flags = flags;
992                        tx_queue_buffer->length = payload_length;
993                        tx_queue_buffer->seg0_len = min_ltg_payload_length;
994                        tx_queue_buffer->seg1_len = 0;
995                        tx_queue_buffer->seg1_offset = 0;
996                        tx_queue_buffer->station_info = station_info;
997
998                        // Submit the new packet to the appropriate queue
999                        wlan_mac_enqueue_wireless_tx(queue_id, tx_queue_entry);
1000
1001                    } else {
1002                        // There aren't any free queue elements right now.
1003                        // As such, there probably isn't any point to continuing this callback.
1004                        // We'll return and try again once it is called the next time.
1005                        return;
1006                    }
1007                }
1008
1009                if(((ltg_pyld_hdr_t*)callback_arg)->type == LTG_PYLD_TYPE_ALL_ASSOC_FIXED){
1010                    station_info_entry = dl_entry_next(station_info_entry);
1011                    if(station_info_entry != NULL){
1012                        station_info = (station_info_t*)station_info_entry->data;
1013                        addr_da = station_info_entry->addr;
1014                        queue_id = station_info->QID;
1015                        is_multicast = 0;
1016                        continue_loop = 1;
1017                    } else {
1018                        continue_loop = 0;
1019                    }
1020                } else {
1021                    continue_loop = 0;
1022                }
1023            } while(continue_loop == 1);
1024        }
1025    }
1026}
1027#endif //WLAN_SW_CONFIG_ENABLE_LTG
1028
1029
1030/*****************************************************************************/
1031/**
1032 * @brief Callback to handle insertion of an Ethernet reception into the corresponding wireless Tx queue
1033 *
1034 * This function is called when a new Ethernet packet is received that must be transmitted via the wireless interface.
1035 * The packet must be encapsulated before it is passed to this function. Ethernet encapsulation is implemented in the mac_high framework.
1036 *
1037 *****************************************************************************/
1038int ethernet_receive(eth_rx_queue_buffer_t* eth_rx_queue_buffer){
1039    tx_80211_queue_buffer_t* tx_queue_buffer;
1040    ethernet_header_t* eth_hdr;
1041    station_info_entry_t* entry;
1042    station_info_t* station_info;
1043
1044    if(active_network_info == NULL) return 0;
1045
1046    eth_hdr = (ethernet_header_t*)eth_rx_queue_buffer->pkt;
1047
1048    if( (eth_hdr->ethertype != ETH_TYPE_ARP) && (eth_hdr->ethertype != ETH_TYPE_IP) ) return 0;
1049
1050    // Determine how to send the packet
1051    if( wlan_addr_mcast(eth_hdr->dest_mac_addr) ) {
1052        // Send the multicast packet
1053        if(queue_length(mcast_qid) < max_queue_size){
1054
1055            //Encapsulate the packet
1056            // Note: the encapsulation function handles filling in the C0/C1 lengths and C1 offset for us
1057            tx_queue_buffer = wlan_eth_encap( eth_rx_queue_buffer, 0 );
1058
1059            tx_queue_buffer->flags = 0;
1060
1061            wlan_create_data_frame_header(tx_queue_buffer->pkt,
1062                                          eth_hdr->dest_mac_addr,
1063                                          wlan_mac_addr,
1064                                          eth_hdr->src_mac_addr,
1065                                          MAC_FRAME_CTRL2_FLAG_FROM_DS);
1066
1067            // Assign a station_info_t struct
1068            //  Notes: (1) if one exists already, it will be adopted.
1069            //         (2) if no heap exists for creating one, NULL is a valid
1070            //             value for the station_info_t*
1071            tx_queue_buffer->station_info = station_info_create(eth_hdr->dest_mac_addr);
1072
1073            // Put the packet in the queue
1074            wlan_mac_enqueue_wireless_tx(mcast_qid, eth_rx_queue_buffer->pyld_queue_hdr.dle);
1075
1076        } else {
1077            // Packet was not successfully enqueued
1078            return 0;
1079        }
1080
1081    } else {
1082        // Check associations
1083        //     Is this packet meant for a station we are associated with?
1084
1085        entry = station_info_find_by_addr(eth_hdr->dest_mac_addr, &active_network_info->members);
1086
1087        if( entry != NULL ) {
1088            station_info = (station_info_t*)(entry->data);
1089
1090            // Send the unicast packet
1091            if(queue_length(station_info->QID) < max_queue_size){
1092
1093                //Encapsulate the packet
1094                // Note: the encapsulation function handles filling in the C0/C1 lengths and C1 offset for us
1095                tx_queue_buffer = wlan_eth_encap( eth_rx_queue_buffer, 0 );
1096
1097                if(tx_queue_buffer){
1098                    // Fill in metadata
1099                    tx_queue_buffer->flags = TX_80211_QUEUE_BUFFER_FLAGS_FILL_DURATION;
1100
1101                    wlan_create_data_frame_header(tx_queue_buffer->pkt,
1102                                           eth_hdr->dest_mac_addr,
1103                                           wlan_mac_addr,
1104                                           eth_hdr->src_mac_addr,
1105                                           MAC_FRAME_CTRL2_FLAG_FROM_DS);
1106
1107                    tx_queue_buffer->station_info = station_info;
1108
1109                    // Put the packet in the queue
1110                    wlan_mac_enqueue_wireless_tx(station_info->QID, tx_queue_buffer->pyld_queue_hdr.dle);
1111                } else {
1112                    return 0;
1113                }
1114
1115            } else {
1116                // Packet was not successfully enqueued
1117                return 0;
1118            }
1119        } else {
1120            // Packet was not successfully enqueued
1121            return 0;
1122        }
1123    }
1124
1125    // Packet successfully enqueued
1126    return 1;
1127}
1128
1129//TODO: Create function to update beacon live fields (e.g. TIM bitmap)
1130// We may need to formalize a beacon ping/pong handshake to avoid any races
1131// created by CPU_HIGH modifying the beacon payload while the PHY is actively
1132// reading bytes out of the packet buffer to create a waveform.
1133
1134
1135
1136/*****************************************************************************/
1137/**
1138 * @brief Check the time since the AP heard from each station
1139 *
1140 * This function will check the timestamp of the last reception from each station and send a
1141 * de-authentication packet to any stations that have timed out.
1142 *
1143 * @param  None
1144 * @return None
1145 *****************************************************************************/
1146void remove_inactive_station_infos() {
1147
1148    u32 aid;
1149    u64 time_since_last_activity;
1150    station_info_t* curr_station_info;
1151    dl_entry* curr_station_info_entry;
1152    dl_entry* next_station_info_entry;
1153    time_hr_min_sec_t time_hr_min_sec;
1154
1155    if(active_network_info == NULL) return;
1156
1157    next_station_info_entry = active_network_info->members.first;
1158
1159    while(next_station_info_entry != NULL) {
1160        curr_station_info_entry = next_station_info_entry;
1161        next_station_info_entry = dl_entry_next(curr_station_info_entry);
1162
1163        curr_station_info = (station_info_t*)(curr_station_info_entry->data);
1164        time_since_last_activity = (get_system_time_usec() - curr_station_info->latest_rx_timestamp);
1165
1166        // De-authenticate the station if we have timed out and we have not disabled this check for the station
1167        if((time_since_last_activity > ASSOCIATION_TIMEOUT_US) && ((curr_station_info->flags & STATION_INFO_FLAG_DISABLE_ASSOC_CHECK) == 0)){
1168
1169            aid = deauthenticate_station( curr_station_info );
1170
1171            if (aid != 0) {
1172                xil_printf("\n\nDisassociation due to inactivity:\n");
1173            }
1174        }
1175    }
1176
1177    next_station_info_entry = authenticated_unassociated_stations.first;
1178
1179    while(next_station_info_entry != NULL) {
1180        curr_station_info_entry = next_station_info_entry;
1181        next_station_info_entry = dl_entry_next(curr_station_info_entry);
1182
1183        curr_station_info = (station_info_t*)(curr_station_info_entry->data);
1184        time_since_last_activity = (get_system_time_usec() - curr_station_info->latest_rx_timestamp);
1185
1186        // De-authenticate the station if we have timed out and we have not disabled this check for the station
1187        if((time_since_last_activity > ASSOCIATION_TIMEOUT_US) && ((curr_station_info->flags & STATION_INFO_FLAG_DISABLE_ASSOC_CHECK) == 0)){
1188
1189            station_info_remove_from_list(&authenticated_unassociated_stations, curr_station_info->addr);
1190
1191            time_hr_min_sec = wlan_mac_time_to_hr_min_sec(get_system_time_usec());
1192
1193            xil_printf("*%dh:%02dm:%02ds* STA %02x:%02x:%02x:%02x:%02x:%02x has disassociated\n",
1194                    time_hr_min_sec.hr, time_hr_min_sec.min, time_hr_min_sec.sec,
1195                    curr_station_info->addr[0], curr_station_info->addr[1], curr_station_info->addr[2],
1196                    curr_station_info->addr[3], curr_station_info->addr[4], curr_station_info->addr[5]);
1197
1198            // Remove the "keep" flag for this station_info so the framework can cleanup later.
1199            curr_station_info->flags &= ~STATION_INFO_FLAG_KEEP;
1200        }
1201    }
1202}
1203
1204
1205
1206/*****************************************************************************/
1207/**
1208 * @brief Process received MPDUs
1209 *
1210 * This callback function will process all the received MPDUs.
1211 *
1212 * This function must implement the state machine that will allow a station to join the AP.
1213 *
1214 * @param  void* pkt_buf_addr
1215 *     - Packet buffer address;  Contains the contents of the MPDU as well as other packet information from CPU low
1216 * @param  station_info_t * station_info
1217 *     - Pointer to metadata about the station from which this frame was received
1218 * @param  rx_common_entry* rx_event_log_entry
1219 *     - Pointer to the log entry created for this reception by the MAC High Framework
1220 * @return u32 flags
1221 *
1222 *****************************************************************************/
1223u32 mpdu_rx_process(void* pkt_buf_addr, station_info_t* station_info, rx_common_entry* rx_event_log_entry) {
1224
1225    rx_frame_info_t* rx_frame_info = (rx_frame_info_t*)pkt_buf_addr;
1226    u8* rx_mac_payload = (u8*)pkt_buf_addr + PHY_RX_PKT_BUF_MPDU_OFFSET;
1227    u8* mac_payload_ptr_u8 = rx_mac_payload; // Make a copy of rx_mac_payload that can be modified while traversing through tagged parameters.
1228
1229    mac_header_80211* rx_80211_header = (mac_header_80211*)(rx_mac_payload);
1230    mac_header_80211* tx_80211_header;
1231
1232    u8 send_response = 0;
1233    u16 tx_length;
1234    u16 rx_seq;
1235    dl_entry* tx_queue_entry;
1236    tx_80211_queue_buffer_t* tx_queue_buffer;
1237    char ssid[SSID_LEN_MAX];
1238    u8 ssid_length = 0;
1239    u8 sta_is_ht_capable = 0;
1240    u8 sta_is_associated = 0;
1241    u8 sta_is_authenticated = 0;
1242
1243    station_info_entry_t* associated_station_entry = NULL;
1244    station_info_t* associated_station = NULL;
1245    station_info_t* auth_unassoc_station_info = NULL;
1246
1247    u8 unicast_to_me;
1248    u8 to_multicast;
1249    u8 eth_send;
1250    u8 allow_auth = 0;
1251
1252    time_hr_min_sec_t time_hr_min_sec;
1253
1254    u16 rx_length = rx_frame_info->phy_details.length;
1255    u32 return_val = 0;
1256
1257    // If this function was passed a CTRL frame (e.g., CTS, ACK), then we should just quit.
1258    // The only reason this occured was so that it could be logged in the line above.
1259    if((rx_80211_header->frame_control_1 & 0xF) == MAC_FRAME_CTRL1_TYPE_CTRL){
1260        goto mpdu_rx_process_end;
1261    }
1262
1263    // Determine if this STA is currently associated to the active_bss_info
1264    sta_is_associated = station_info_is_member(&active_network_info->members, station_info);
1265
1266    sta_is_authenticated = (sta_is_associated || station_info_is_member(&authenticated_unassociated_stations, station_info));
1267
1268    // Determine destination of packet
1269    unicast_to_me = wlan_addr_eq(rx_80211_header->address_1, wlan_mac_addr);
1270    to_multicast  = wlan_addr_mcast(rx_80211_header->address_1);
1271
1272    // If the packet is good (ie good FCS) and it is destined for me, then process it
1273    if( rx_frame_info->flags & RX_FRAME_INFO_FLAGS_FCS_GOOD){
1274       
1275        // Sequence number is 12 MSB of seq_control field
1276        rx_seq         = ((rx_80211_header->sequence_control) >> 4) & 0xFFF;
1277
1278        // Check if this was a duplicate reception
1279        //   - Packet is unicast and directed towards me
1280        //   - Packet has the RETRY bit set to 1 in the second frame control byte
1281        //   - Received seq num matched previously received seq num for this STA
1282        if( (station_info != NULL) && unicast_to_me ){
1283            if( ((rx_80211_header->frame_control_2) & MAC_FRAME_CTRL2_FLAG_RETRY) && (station_info->latest_rx_seq == rx_seq) ) {
1284                if(rx_event_log_entry != NULL){
1285                    rx_event_log_entry->flags |= RX_FLAGS_DUPLICATE;
1286                    return_val |= MAC_RX_CALLBACK_RETURN_FLAG_DUP;
1287                }
1288            } else {
1289                station_info->latest_rx_seq = rx_seq;
1290            }   
1291        }
1292
1293        if( sta_is_associated ){
1294            // Update PS state
1295            if((rx_80211_header->frame_control_2) & MAC_FRAME_CTRL2_FLAG_POWER_MGMT){
1296                station_info->ps_state |= STATION_INFO_PS_STATE_DOZE;
1297            } else {
1298                station_info->ps_state &= ~STATION_INFO_PS_STATE_DOZE;
1299                poll_tx_queues();
1300            }
1301
1302            if( return_val & MAC_RX_CALLBACK_RETURN_FLAG_DUP ) {
1303                // Finish the function and do not de-encapsulate
1304                goto mpdu_rx_process_end;
1305            } 
1306        }
1307
1308        if(unicast_to_me || to_multicast){
1309            // Process the packet
1310            switch(rx_80211_header->frame_control_1) {
1311                //---------------------------------------------------------------------
1312                case MAC_FRAME_CTRL1_SUBTYPE_QOSDATA:
1313                case MAC_FRAME_CTRL1_SUBTYPE_DATA:
1314                    // Data packet
1315                    //   - Determine if this packet is from an associated station
1316                    //   - Depending on the type and destination, transmit the packet wirelessly or over the wired network
1317                    //
1318
1319                    if( sta_is_associated ){
1320
1321                        // MPDU is flagged as destined to the DS
1322                        if((rx_80211_header->frame_control_2) & MAC_FRAME_CTRL2_FLAG_TO_DS) {
1323                            eth_send = 1;
1324
1325                            // Check if this is a multicast packet
1326                            if(wlan_addr_mcast(rx_80211_header->address_3)){
1327                                // Send the data packet over wireless
1328                                tx_queue_entry = queue_checkout();
1329
1330                                if(tx_queue_entry != NULL){
1331                                    tx_queue_buffer = (tx_80211_queue_buffer_t*)(tx_queue_entry->data);
1332
1333                                    wlan_create_data_frame_header(tx_queue_buffer->pkt,
1334                                                                  rx_80211_header->address_3,
1335                                                                  wlan_mac_addr,
1336                                                                  rx_80211_header->address_2,
1337                                                                  MAC_FRAME_CTRL2_FLAG_FROM_DS);
1338
1339                                    // Overwrite packet type with just-received packet type. This will allow
1340                                    // relaying of QOSDATA frames
1341                                    tx_80211_header = ((mac_header_80211*)(tx_queue_buffer->pkt));
1342                                    tx_80211_header->frame_control_1 = rx_80211_header->frame_control_1;
1343
1344                                    // Fill in the data
1345                                    wlan_mac_high_cdma_start_transfer(tx_queue_buffer->pkt + sizeof(mac_header_80211),
1346                                                                      rx_mac_payload + sizeof(mac_header_80211),
1347                                                                      rx_length - sizeof(mac_header_80211));
1348
1349                                    // Fill in the metadata
1350                                    tx_queue_buffer->flags = 0;
1351                                    tx_queue_buffer->length = rx_length;
1352                                    tx_queue_buffer->seg0_len = rx_length;
1353                                    tx_queue_buffer->seg1_len = 0;
1354                                    tx_queue_buffer->seg1_offset = 0;
1355                                    tx_queue_buffer->station_info = station_info_create(rx_80211_header->address_3);
1356
1357                                    // Make sure the DMA transfer is complete
1358                                    wlan_mac_high_cdma_finish_transfer();
1359
1360                                    // Put the packet in the queue
1361                                    wlan_mac_enqueue_wireless_tx(mcast_qid, tx_queue_entry);
1362
1363                                }
1364                            } else {
1365                                // Packet is not a multicast packet.  Check if it is destined for one of our stations
1366                                if(active_network_info != NULL){
1367                                    associated_station_entry = station_info_find_by_addr(rx_80211_header->address_3, &active_network_info->members);
1368                                }
1369                                if(associated_station_entry != NULL){
1370                                    associated_station = (station_info_t*)(associated_station_entry->data);
1371
1372                                    // Send the data packet over the wireless to our station
1373                                    tx_queue_entry = queue_checkout();
1374
1375                                    if(tx_queue_entry != NULL){
1376                                        tx_queue_buffer = (tx_80211_queue_buffer_t*)(tx_queue_entry->data);
1377
1378                                        wlan_create_data_frame_header(tx_queue_buffer->pkt,
1379                                                                      rx_80211_header->address_3,
1380                                                                      wlan_mac_addr,
1381                                                                      rx_80211_header->address_2,
1382                                                                      MAC_FRAME_CTRL2_FLAG_FROM_DS);
1383
1384                                        // Overwrite packet type with just-received packet type. This will allow
1385                                        // relaying of QOSDATA frames
1386                                        tx_80211_header = ((mac_header_80211*)(tx_queue_buffer->pkt));
1387                                        tx_80211_header->frame_control_1 = rx_80211_header->frame_control_1;
1388
1389                                        // Fill in the data
1390                                        wlan_mac_high_cdma_start_transfer(tx_queue_buffer->pkt + sizeof(mac_header_80211),
1391                                                                          rx_mac_payload + sizeof(mac_header_80211),
1392                                                                          rx_length - sizeof(mac_header_80211));
1393
1394                                        // Fill in the metadata
1395                                        tx_queue_buffer->flags = TX_80211_QUEUE_BUFFER_FLAGS_FILL_DURATION;
1396                                        tx_queue_buffer->length = rx_length;
1397                                        tx_queue_buffer->seg0_len = rx_length;
1398                                        tx_queue_buffer->seg1_len = 0;
1399                                        tx_queue_buffer->seg1_offset = 0;
1400                                        tx_queue_buffer->station_info = associated_station;
1401
1402                                        // Make sure the DMA transfer is complete
1403                                        wlan_mac_high_cdma_finish_transfer();
1404
1405                                        // Put the packet in the queue
1406                                        wlan_mac_enqueue_wireless_tx(associated_station->QID, tx_queue_entry);
1407
1408                                        // Given we sent the packet wirelessly to our stations, if we do not allow Ethernet transmissions
1409                                        //   of wireless transmissions, then do not send over Ethernet
1410                                        #ifndef ALLOW_ETH_TX_OF_WIRELESS_TX
1411                                        eth_send = 0;
1412                                        #endif
1413                                    }
1414                                }
1415                            }
1416
1417                            // Encapsulate the packet and send over the wired network
1418                            if(eth_send){
1419#if WLAN_SW_CONFIG_ENABLE_ETH_BRIDGE
1420                                wlan_eth_decap_and_send(rx_mac_payload,
1421                                                        rx_80211_header->address_3,
1422                                                        rx_80211_header->address_2,
1423                                                        rx_length,
1424                                                        0);
1425#endif
1426                            }
1427                        }
1428                    } else {
1429                        // Packet was not from an associated station
1430                        //   - Print a WARNING and send a de-authentication to trigger a re-association
1431                        //
1432                        //
1433                        if(unicast_to_me){
1434
1435                            // Received a data frame from a STA that claims to be associated with this AP but is not in the AP association table
1436                            //   Discard the MPDU and reply with a de-authentication frame to trigger re-association at the STA
1437                            wlan_printf(PL_WARNING, "Data from non-associated station: [%x %x %x %x %x %x], issuing de-authentication\n", rx_80211_header->address_2[0],rx_80211_header->address_2[1],rx_80211_header->address_2[2],rx_80211_header->address_2[3],rx_80211_header->address_2[4],rx_80211_header->address_2[5]);
1438                            wlan_printf(PL_WARNING, "Address 3: [%x %x %x %x %x %x]\n", rx_80211_header->address_3[0],rx_80211_header->address_3[1],rx_80211_header->address_3[2],rx_80211_header->address_3[3],rx_80211_header->address_3[4],rx_80211_header->address_3[5]);
1439
1440                            // Send de-authentication packet to the station
1441                            tx_queue_entry = queue_checkout();
1442
1443                            if(tx_queue_entry != NULL){
1444                                tx_queue_buffer = (tx_80211_queue_buffer_t*)(tx_queue_entry->data);
1445
1446                                tx_length = wlan_create_deauth_frame(tx_queue_buffer->pkt,
1447                                                                     rx_80211_header->address_2,
1448                                                                     wlan_mac_addr,
1449                                                                     wlan_mac_addr,
1450                                                                     DEAUTH_REASON_NONASSOCIATED_STA);
1451
1452                                // Fill in metadata
1453                                tx_queue_buffer->length = tx_length;
1454                                tx_queue_buffer->seg0_len = tx_length;
1455                                tx_queue_buffer->seg1_len = 0;
1456                                tx_queue_buffer->seg1_offset = 0;
1457                                tx_queue_buffer->station_info = station_info;
1458
1459                                // Put the packet in the queue
1460                                wlan_mac_enqueue_wireless_tx(mgmt_qid, tx_queue_entry);
1461                            }
1462                        }
1463                    } // END if(associated_station != NULL)
1464                break;
1465
1466
1467                //---------------------------------------------------------------------
1468                case (MAC_FRAME_CTRL1_SUBTYPE_PROBE_REQ):
1469                    // Probe Request Packet
1470                    //   - Check that this packet is to the broadcast address
1471                    //   - Look at the tagged parameters
1472                    //   - Depending on the parameters, send a probe response
1473                    //
1474                    if(wlan_addr_eq(rx_80211_header->address_3, bcast_addr) ||
1475                            wlan_addr_eq(rx_80211_header->address_3, wlan_mac_addr)) {
1476                        mac_payload_ptr_u8 += sizeof(mac_header_80211);
1477
1478                        // Loop through tagged parameters
1479                        while(((u32)mac_payload_ptr_u8 -  (u32)rx_mac_payload)<= (rx_length - WLAN_PHY_FCS_NBYTES)){
1480
1481                            // What kind of tag is this?
1482                            switch(mac_payload_ptr_u8[0]){
1483                                //-----------------------------------------------------
1484                                case MGMT_TAG_SSID:
1485                                    // SSID parameter set
1486                                    if((active_network_info != NULL) &&
1487                                       ((mac_payload_ptr_u8[1]==0) || // Wildcard SSID is zero-length
1488                                        ((mac_payload_ptr_u8[1] == strnlen(active_network_info->bss_config.ssid, SSID_LEN_MAX)) && // Check for equal lengths first
1489                                        (memcmp(mac_payload_ptr_u8+2, (u8*)active_network_info->bss_config.ssid, mac_payload_ptr_u8[1])==0)))) {
1490                                        // Send response if Probe Request contained wildcard SSID
1491                                        //  or SSID matching the SSID of this AP's BSS
1492                                        send_response = 1;
1493                                    }
1494                                break;
1495
1496                                //-----------------------------------------------------
1497                                case MGMT_TAG_SUPPORTED_RATES:
1498                                    // Supported rates
1499                                break;
1500
1501                                //-----------------------------------------------------
1502                                case MGMT_TAG_EXTENDED_SUPPORTED_RATES:
1503                                    // Extended supported rates
1504                                break;
1505
1506                                //-----------------------------------------------------
1507                                case MGMT_TAG_DSSS_PARAMETER_SET:
1508                                    // DS Parameter set (e.g. channel)
1509                                break;
1510                            }
1511
1512                            // Move up to the next tag
1513                            mac_payload_ptr_u8 += mac_payload_ptr_u8[1]+2;
1514                        }
1515
1516                        if((active_network_info != NULL) && send_response) {
1517
1518                            // Create a probe response frame
1519                            tx_queue_entry = queue_checkout();
1520
1521                            if(tx_queue_entry != NULL){
1522                                tx_queue_buffer = (tx_80211_queue_buffer_t*)(tx_queue_entry->data);
1523
1524                                tx_length = wlan_create_probe_resp_frame( tx_queue_buffer->pkt,
1525                                                                          rx_80211_header->address_2,
1526                                                                          wlan_mac_addr,
1527                                                                          wlan_mac_addr,
1528                                                                          active_network_info );
1529
1530
1531                                // Fill in metadata
1532                                tx_queue_buffer->flags = TX_80211_QUEUE_BUFFER_FLAGS_FILL_DURATION | TX_80211_QUEUE_BUFFER_FLAGS_FILL_TIMESTAMP;
1533                                tx_queue_buffer->length = tx_length;
1534                                tx_queue_buffer->seg0_len = tx_length;
1535                                tx_queue_buffer->seg1_len = 0;
1536                                tx_queue_buffer->seg1_offset = 0;
1537                                tx_queue_buffer->station_info = station_info;
1538
1539                                // Put the packet in the queue
1540                                wlan_mac_enqueue_wireless_tx(mgmt_qid, tx_queue_entry);
1541                            }
1542
1543                            // Finish the function
1544                            goto mpdu_rx_process_end;
1545                        }
1546                    }
1547                break;
1548
1549
1550                //---------------------------------------------------------------------
1551                case (MAC_FRAME_CTRL1_SUBTYPE_AUTH):
1552                    // Authentication Packet
1553                    //   - Check if authentication is allowed (note: if the station
1554                    //   - Potentially send authentication response
1555                    //
1556                    if( sta_is_associated || (wlan_addr_eq(rx_80211_header->address_3, wlan_mac_addr) && wlan_mac_addr_filter_is_allowed(rx_80211_header->address_2)) ) {
1557                        mac_payload_ptr_u8 += sizeof(mac_header_80211);
1558                        switch(((authentication_frame*)mac_payload_ptr_u8)->auth_algorithm ){
1559                            case AUTH_ALGO_OPEN_SYSTEM:
1560                                allow_auth = 1;
1561                            break;
1562                        }
1563                    }
1564
1565                    // Only send response if the packet was from a requester
1566                    //
1567                    if((active_network_info != NULL) && ((authentication_frame*)mac_payload_ptr_u8)->auth_sequence == AUTH_SEQ_REQ){
1568
1569                        // Only send response if we are allowing authentication and there is room in the authenticated_unassociated_stations list.
1570                        //  Note: the station from which this MAC_FRAME_CTRL1_SUBTYPE_AUTH was received may already be in the authenticated_unassociated_stations
1571                        //  list, so this should be accounted for when comparing the list length to MAX_NUM_AUTH
1572                        if(allow_auth && ( (authenticated_unassociated_stations.length-(sta_is_authenticated && (!sta_is_associated))) < MAX_NUM_AUTH ) ){
1573
1574                            //Only proceed if:
1575                            // (1) The authentication type was AUTH_ALGO_OPEN_SYSTEM
1576                            //      and
1577                            // (2) The number of currently authenticated stations (not counting this station if it
1578                            //      is already authenticated) is less than MAX_NUM_AUTH
1579                            if(sta_is_associated == 0){
1580                                // This station wasn't already authenticated/associated (state 4), so manually add it to the
1581                                // authenticated/unassociated (state 2) list.
1582                                //     - Set ht_capable argument to 0.  This will be updated with the correct value when the
1583                                //       node moves from the state 2 list during association.
1584
1585                                auth_unassoc_station_info = station_info_add_to_list(&authenticated_unassociated_stations, rx_80211_header->address_2);
1586
1587                                if(auth_unassoc_station_info != NULL){
1588                                    auth_unassoc_station_info->flags |= STATION_INFO_FLAG_KEEP;
1589                                    time_hr_min_sec = wlan_mac_time_to_hr_min_sec(get_system_time_usec());
1590                                    xil_printf("*%dh:%02dm:%02ds* STA %02x:%02x:%02x:%02x:%02x:%02x is now authenticated / unassociated\n",
1591                                            time_hr_min_sec.hr, time_hr_min_sec.min, time_hr_min_sec.sec,
1592                                            rx_80211_header->address_2[0], rx_80211_header->address_2[1], rx_80211_header->address_2[2],
1593                                            rx_80211_header->address_2[3], rx_80211_header->address_2[4], rx_80211_header->address_2[5]);
1594                                }
1595                            }
1596
1597                            // Create a successful authentication response frame
1598                            tx_queue_entry = queue_checkout();
1599
1600                            if(tx_queue_entry != NULL){
1601                                tx_queue_buffer = (tx_80211_queue_buffer_t*)(tx_queue_entry->data);
1602
1603                                tx_length = wlan_create_auth_frame( tx_queue_buffer->pkt,
1604                                                                    rx_80211_header->address_2,
1605                                                                    wlan_mac_addr,
1606                                                                    wlan_mac_addr,
1607                                                                    AUTH_ALGO_OPEN_SYSTEM,
1608                                                                    AUTH_SEQ_RESP,
1609                                                                    STATUS_SUCCESS);
1610                                // Fill in metadata
1611                                tx_queue_buffer->flags = TX_80211_QUEUE_BUFFER_FLAGS_FILL_DURATION;
1612                                tx_queue_buffer->length = tx_length;
1613                                tx_queue_buffer->seg0_len = tx_length;
1614                                tx_queue_buffer->seg1_len = 0;
1615                                tx_queue_buffer->seg1_offset = 0;
1616                                tx_queue_buffer->station_info = station_info;
1617
1618                                // Put the packet in the queue
1619                                wlan_mac_enqueue_wireless_tx(mgmt_qid, tx_queue_entry);
1620                            }
1621
1622                            // Finish the function
1623                            goto mpdu_rx_process_end;
1624
1625                        } else {
1626                            // Create a unsuccessful authentication response frame
1627                            tx_queue_entry = queue_checkout();
1628
1629                            if(tx_queue_entry != NULL){
1630                                tx_queue_buffer = (tx_80211_queue_buffer_t*)(tx_queue_entry->data);
1631
1632                                tx_length = wlan_create_auth_frame( tx_queue_buffer->pkt,
1633                                                                    rx_80211_header->address_2,
1634                                                                    wlan_mac_addr,
1635                                                                    wlan_mac_addr,
1636                                                                    AUTH_ALGO_OPEN_SYSTEM,
1637                                                                    AUTH_SEQ_RESP,
1638                                                                    STATUS_AUTH_REJECT_UNSPECIFIED);
1639                                // Fill in metadata
1640                                tx_queue_buffer->flags = TX_80211_QUEUE_BUFFER_FLAGS_FILL_DURATION;
1641                                tx_queue_buffer->length = tx_length;
1642                                tx_queue_buffer->seg0_len = tx_length;
1643                                tx_queue_buffer->seg1_len = 0;
1644                                tx_queue_buffer->seg1_offset = 0;
1645                                tx_queue_buffer->station_info = station_info;
1646
1647                                // Put the packet in the queue
1648                                wlan_mac_enqueue_wireless_tx(mgmt_qid, tx_queue_entry);
1649                            }
1650                        }
1651
1652                        // Finish the function
1653                        goto mpdu_rx_process_end;
1654                    }
1655                break;
1656
1657
1658                //---------------------------------------------------------------------
1659                case (MAC_FRAME_CTRL1_SUBTYPE_ASSOC_REQ):
1660                case (MAC_FRAME_CTRL1_SUBTYPE_REASSOC_REQ):
1661                {
1662                    u32 reject_association = 1;
1663
1664                    if(station_info != NULL){
1665
1666                    // Association Request / Re-association Request
1667
1668                    // Parse the tagged parameters
1669                    mac_payload_ptr_u8 = mac_payload_ptr_u8 + sizeof(mac_header_80211) + sizeof(association_req_frame);
1670                    while ((((u32)mac_payload_ptr_u8) - ((u32)rx_mac_payload)) < (rx_length - WLAN_PHY_FCS_NBYTES)) {
1671                        // Parse each of the tags
1672                        switch(mac_payload_ptr_u8[0]){
1673
1674                            //-------------------------------------------------
1675                            case MGMT_TAG_SSID:
1676                                // SSID parameter set
1677                                //
1678                                strncpy(ssid, (char*)(&(mac_payload_ptr_u8[2])), SSID_LEN_MAX);
1679                                ssid_length = WLAN_MIN(mac_payload_ptr_u8[1],SSID_LEN_MAX);
1680                            break;
1681
1682
1683                            //-------------------------------------------------
1684                            case MGMT_TAG_HT_CAPABILITIES:
1685                                // This station is capable of HT Tx and Rx
1686                                sta_is_ht_capable = 1;
1687                            break;
1688                        }
1689
1690                        // Increment packet pointer to the next tag
1691                        mac_payload_ptr_u8 += mac_payload_ptr_u8[1]+2;
1692                    }
1693
1694                    //   - Check if the packet is for this BSS. Necessary Criteria:
1695                    //      - RA is unicast and directed to this node's wlan_mac_address
1696                    //      - SSID string in payload of reception matches this BSS's SSID string
1697                    //      - BSSID matches this BSS's ID
1698                    if( unicast_to_me &&
1699                        (strncmp(ssid, active_network_info->bss_config.ssid, ssid_length) == 0) &&
1700                        (active_network_info != NULL) && wlan_addr_eq(rx_80211_header->address_3, active_network_info->bss_config.bssid)) {
1701
1702                        // Check if we have authenticated this TA yet have not associated it.
1703                        // Note: We cannot use the sta_is_authenticated boolean for this, as this also
1704                        //  includes fully associated stations.
1705
1706                            if( sta_is_associated || (active_network_info->members.length < MAX_NUM_ASSOC) ) reject_association = 0;
1707
1708                            if((reject_association == 0) && station_info_is_member(&authenticated_unassociated_stations, station_info)){
1709
1710                            station_info_remove_from_list(&authenticated_unassociated_stations, rx_80211_header->address_2);
1711
1712                            // NOTE: The STATION_INFO_FLAG_KEEP bit will still be raised despite having removed the
1713                            //  station_info from the authenticated_unassociated_stations list. This is intentional,
1714                            //  as we are about to add the station_info the the fully associated list.
1715
1716                            // Add the station info
1717                            //     - Set ht_capable argument to 0.  This will be updated below with the
1718                            //       correct value from the tagged parameters in the association request.
1719                            if (network_info_add_member(active_network_info, rx_80211_header->address_2, max_queue_size)) {
1720                                time_hr_min_sec = wlan_mac_time_to_hr_min_sec(get_system_time_usec());
1721                                xil_printf("*%dh:%02dm:%02ds* STA %02x:%02x:%02x:%02x:%02x:%02x is now associated\n",
1722                                        time_hr_min_sec.hr, time_hr_min_sec.min, time_hr_min_sec.sec,
1723                                        rx_80211_header->address_2[0], rx_80211_header->address_2[1], rx_80211_header->address_2[2],
1724                                        rx_80211_header->address_2[3], rx_80211_header->address_2[4], rx_80211_header->address_2[5]);
1725                            }
1726
1727                            wlan_platform_high_userio_disp_status(USERIO_DISP_STATUS_MEMBER_LIST_UPDATE, active_network_info->members.length);
1728                        }
1729
1730                        if( reject_association == 0 ) {
1731                            // Zero the HT_CAPABLE flag
1732                            if(sta_is_ht_capable){
1733                                station_info->capabilities |= STATION_INFO_CAPABILITIES_HT_CAPABLE;
1734                            } else {
1735                                station_info->capabilities &= ~STATION_INFO_CAPABILITIES_HT_CAPABLE;
1736                            }
1737
1738                            // Do not allow Mango nodes to time out
1739                            if(wlan_mac_addr_is_mango(rx_80211_header->address_2)){
1740                                station_info->flags |= STATION_INFO_FLAG_DISABLE_ASSOC_CHECK;
1741                            }
1742
1743
1744                            //
1745                            // TODO:  (Optional) Log association state change
1746                            //
1747
1748                            // Create a successful association response frame
1749                            tx_queue_entry = queue_checkout();
1750
1751                            if(tx_queue_entry != NULL){
1752                                tx_queue_buffer = (tx_80211_queue_buffer_t*)(tx_queue_entry->data);
1753
1754                                tx_length = wlan_create_association_response_frame(tx_queue_buffer->pkt,
1755                                                                                   rx_80211_header->address_2,
1756                                                                                   wlan_mac_addr,
1757                                                                                   active_network_info->bss_config.bssid,
1758                                                                                   STATUS_SUCCESS,
1759                                                                                   station_info->ID,
1760                                                                                   active_network_info);
1761
1762                                // Fill in metadata
1763                                tx_queue_buffer->flags = TX_80211_QUEUE_BUFFER_FLAGS_FILL_DURATION;
1764                                tx_queue_buffer->length = tx_length;
1765                                tx_queue_buffer->seg0_len = tx_length;
1766                                tx_queue_buffer->seg1_len = 0;
1767                                tx_queue_buffer->seg1_offset = 0;
1768                                tx_queue_buffer->station_info = station_info;
1769
1770                                // Put the packet in the queue
1771                                wlan_mac_enqueue_wireless_tx(station_info->QID, tx_queue_entry);
1772                            }
1773
1774                            // Finish the function
1775                            goto mpdu_rx_process_end;
1776
1777                        } else {
1778                            // Create an unsuccessful association response frame
1779                            tx_queue_entry = queue_checkout();
1780
1781                            if(tx_queue_entry != NULL){
1782                                tx_queue_buffer = (tx_80211_queue_buffer_t*)(tx_queue_entry->data);
1783
1784                                tx_length = wlan_create_association_response_frame(tx_queue_buffer->pkt,
1785                                                                                   rx_80211_header->address_2,
1786                                                                                   wlan_mac_addr,
1787                                                                                   active_network_info->bss_config.bssid,
1788                                                                                   STATUS_REJECT_TOO_MANY_ASSOCIATIONS,
1789                                                                                   0,
1790                                                                                   active_network_info);
1791
1792                                // Fill in metadata
1793                                tx_queue_buffer->flags = TX_80211_QUEUE_BUFFER_FLAGS_FILL_DURATION;
1794                                tx_queue_buffer->length = tx_length;
1795                                tx_queue_buffer->seg0_len = tx_length;
1796                                tx_queue_buffer->seg1_len = 0;
1797                                tx_queue_buffer->seg1_offset = 0;
1798                                tx_queue_buffer->station_info = station_info;
1799
1800                                // Put the packet in the queue
1801                                wlan_mac_enqueue_wireless_tx(mgmt_qid, tx_queue_entry);
1802
1803                            }
1804
1805                            // Finish the function
1806                            goto mpdu_rx_process_end;
1807                        }
1808                    }
1809                    }
1810                }
1811                break;
1812
1813
1814                //---------------------------------------------------------------------
1815                case (MAC_FRAME_CTRL1_SUBTYPE_DISASSOC):
1816                    // Disassociation
1817                    //   - Log the association state change
1818                    //   - Remove the association and update the display
1819                    //
1820                    if(active_network_info != NULL){
1821
1822                        // Note: Since we are no longer keeping this station_info, we should ensure it is present
1823                        //  in neither the fully associated list or the authenticated-only list
1824
1825                        if(sta_is_associated){
1826                            network_info_remove_member(active_network_info, rx_80211_header->address_2);
1827                        }
1828
1829                        station_info_remove_from_list(&authenticated_unassociated_stations, rx_80211_header->address_2);
1830
1831                        time_hr_min_sec = wlan_mac_time_to_hr_min_sec(get_system_time_usec());
1832
1833                        xil_printf("*%dh:%02dm:%02ds* STA %02x:%02x:%02x:%02x:%02x:%02x has disassociated\n",
1834                                time_hr_min_sec.hr, time_hr_min_sec.min, time_hr_min_sec.sec,
1835                                rx_80211_header->address_2[0], rx_80211_header->address_2[1], rx_80211_header->address_2[2],
1836                                rx_80211_header->address_2[3], rx_80211_header->address_2[4], rx_80211_header->address_2[5]);
1837
1838                        // Lower the KEEP flag so that the station_info_
1839                        if(station_info != NULL) station_info->flags &= ~STATION_INFO_FLAG_KEEP;
1840
1841                        wlan_platform_high_userio_disp_status(USERIO_DISP_STATUS_MEMBER_LIST_UPDATE, active_network_info->members.length);
1842                    }
1843                break;
1844
1845                case (MAC_FRAME_CTRL1_SUBTYPE_NULLDATA):
1846                break;
1847
1848                //---------------------------------------------------------------------
1849                default:
1850                    //This should be left as a verbose print. It occurs often when communicating with mobile devices since they tend to send
1851                    //null data frames (type: DATA, subtype: 0x4) for power management reasons.
1852                    wlan_printf(PL_VERBOSE, "Received unknown frame control type/subtype %x\n",rx_80211_header->frame_control_1);
1853
1854                break;
1855            }
1856        }
1857
1858        goto mpdu_rx_process_end;
1859
1860    } else {
1861        // Process any Bad FCS packets
1862        goto mpdu_rx_process_end;
1863    }
1864
1865    // Finish any processing for the RX MPDU process
1866    mpdu_rx_process_end:
1867
1868    // Currently, asynchronous transmission of log entries is not supported
1869    //
1870    // if (rx_event_log_entry != NULL) {
1871    //     wn_transmit_log_entry((void *)rx_event_log_entry);
1872    // }
1873
1874    return return_val;
1875}
1876
1877
1878
1879/*****************************************************************************/
1880/**
1881 *
1882 *****************************************************************************/
1883void mpdu_dequeue(tx_80211_queue_buffer_t* tx_queue_buffer){
1884    mac_header_80211* header;
1885    station_info_t* station_info;
1886
1887    header = (mac_header_80211*)(tx_queue_buffer->pkt);
1888    station_info = tx_queue_buffer->station_info;
1889
1890    if(station_info->num_linked_queue_buffer > 1){
1891        //If the is more data (in addition to this packet) queued for this station, we can let it know
1892        //in the frame_control_2 field.
1893        header->frame_control_2 |= MAC_FRAME_CTRL2_FLAG_MORE_DATA;
1894    } else {
1895        header->frame_control_2 &= ~MAC_FRAME_CTRL2_FLAG_MORE_DATA;
1896    }
1897
1898}
1899
1900/*****************************************************************************/
1901/**
1902 * @brief Deauthenticate given station in the Association Table
1903 *
1904 * Deauthenticate the station in the associations table
1905 *
1906 * @param  station_info_t * station_info
1907 *   - Station to be deauthenticated
1908 * @return u32 aid
1909 *   - AID of the station that was deauthenticated; AID of 0 is reserved to indicate failure
1910 *****************************************************************************/
1911u32  deauthenticate_station( station_info_t* station_info ) {
1912
1913    dl_entry* tx_queue_entry;
1914    tx_80211_queue_buffer_t* tx_queue_buffer;
1915    u32 tx_length;
1916    u32 aid;
1917    time_hr_min_sec_t time_hr_min_sec;
1918
1919    if((active_network_info == NULL) || (station_info == NULL)){
1920        return 0;
1921    }
1922
1923    // Get the AID
1924    aid = station_info->ID;
1925
1926    // Send De-authentication packet
1927    tx_queue_entry = queue_checkout();
1928
1929    if(tx_queue_entry != NULL){
1930        tx_queue_buffer = (tx_80211_queue_buffer_t*)(tx_queue_entry->data);
1931
1932        tx_length = wlan_create_deauth_frame(tx_queue_buffer->pkt,
1933                                             station_info->addr,
1934                                             wlan_mac_addr,
1935                                             wlan_mac_addr,
1936                                             DEAUTH_REASON_INACTIVITY);
1937
1938        // Fill in metadata
1939        tx_queue_buffer->flags = TX_80211_QUEUE_BUFFER_FLAGS_FILL_DURATION;
1940        tx_queue_buffer->length = tx_length;
1941        tx_queue_buffer->seg0_len = tx_length;
1942        tx_queue_buffer->seg1_len = 0;
1943        tx_queue_buffer->seg1_offset = 0;
1944        tx_queue_buffer->station_info = station_info;
1945
1946        // Put the packet in the queue
1947        wlan_mac_enqueue_wireless_tx(mgmt_qid, tx_queue_entry);
1948
1949        // Purge any packets in the queue meant for this node
1950        wlan_mac_purge_wireless_tx(station_info->QID);
1951    }
1952
1953    //
1954    // TODO:  (Optional) Log association state change
1955    //
1956
1957    // Remove this STA from association list
1958    network_info_remove_member(active_network_info, station_info->addr);
1959
1960    time_hr_min_sec = wlan_mac_time_to_hr_min_sec(get_system_time_usec());
1961
1962    xil_printf("*%dh:%02dm:%02ds* STA %02x:%02x:%02x:%02x:%02x:%02x has disassociated\n",
1963            time_hr_min_sec.hr, time_hr_min_sec.min, time_hr_min_sec.sec,
1964            station_info->addr[0], station_info->addr[1], station_info->addr[2],
1965            station_info->addr[3], station_info->addr[4], station_info->addr[5]);
1966
1967    // Remove the "keep" flag for this station_info so the framework can cleanup later.
1968    station_info->flags &= ~STATION_INFO_FLAG_KEEP;
1969
1970    wlan_platform_high_userio_disp_status(USERIO_DISP_STATUS_MEMBER_LIST_UPDATE, active_network_info->members.length);
1971
1972    return aid;
1973}
1974
1975
1976
1977/*****************************************************************************/
1978/**
1979 * @brief Deauthenticate all stations in the Association Table
1980 *
1981 * Loop through all associations in the table and deauthenticate the stations
1982 *
1983 * @param  None
1984 * @return None
1985 *****************************************************************************/
1986void deauthenticate_all_stations(){
1987    interrupt_state_t curr_interrupt_state;
1988    station_info_t* curr_station_info;
1989    dl_entry* next_station_info_entry;
1990    dl_entry* curr_station_info_entry;
1991    int iter;
1992
1993    if(active_network_info == NULL) return;
1994
1995    iter = active_network_info->members.length;
1996    curr_interrupt_state = wlan_platform_intc_stop();
1997
1998    next_station_info_entry = active_network_info->members.first;
1999
2000    // Deauthenticate all stations and remove from the association table
2001    //
2002    // NOTE:  Cannot use a for loop for this iteration b/c we could remove
2003    //   elements from the list.
2004    while( (next_station_info_entry != NULL) && (iter-- > 0)){
2005        curr_station_info_entry = next_station_info_entry;
2006        next_station_info_entry = dl_entry_next(curr_station_info_entry);
2007        curr_station_info = (station_info_t*)(curr_station_info_entry->data);
2008        deauthenticate_station(curr_station_info);
2009    }
2010
2011    wlan_platform_intc_set_state(curr_interrupt_state);
2012
2013}
2014
2015/*****************************************************************************/
2016/**
2017 * @brief Handle a reboot of CPU_LOW
2018 *
2019 * If CPU_LOW reboots, any parameters we had previously set in it will be lost.
2020 * This function is called to tell us that we should re-apply any previous
2021 * parameters we had set.
2022 *
2023 * @param  u32 type - type of MAC running in CPU_LOW
2024 * @return None
2025 *****************************************************************************/
2026void handle_cpu_low_reboot(u32 type){
2027
2028    if(type & WLAN_EXP_LOW_SW_ID_DCF) {
2029        gl_cpu_low_supports_dtim_mcast = 1;
2030    } else {
2031        gl_cpu_low_supports_dtim_mcast = 0;
2032    }
2033
2034    if(active_network_info != NULL){
2035        // Re-apply any Beacon Tx configurations
2036        wlan_mac_high_config_txrx_beacon(&gl_beacon_txrx_config);
2037
2038        // Re-apply DTIM mcast buffering settings
2039        wlan_mac_high_enable_mcast_buffering(gl_dtim_mcast_buffer_enable);
2040    }
2041}
2042
2043/*****************************************************************************/
2044/**
2045 *
2046 *****************************************************************************/
2047u32 configure_bss(bss_config_t* bss_config, u32 update_mask){
2048    u32 return_status = 0;
2049    u8 update_beacon_template = 0;
2050    u8 send_beacon_config_to_low = 0;
2051    u8 send_channel_switch_to_low = 0;
2052
2053    network_info_t* local_network_info;
2054    interrupt_state_t curr_interrupt_state;
2055    station_info_t* curr_station_info;
2056    dl_entry* next_station_info_entry;
2057    dl_entry* curr_station_info_entry;
2058    int iter;
2059    time_hr_min_sec_t time_hr_min_sec;
2060    tx_params_t default_beacon_tx_params;
2061
2062    //---------------------------------------------------------
2063    // 1. Check for any invalid inputs or combination of inputs
2064    //      First verify the requested update to the BSS configuration before
2065    //      modifying anything. This will prevent a partial update of BSS
2066    //      configuration with valid parameters before discovering an invalid
2067    //      parameter. Furthermore, we can update the arguments to this function
2068    //      with any relevant default values in the case that the arguments
2069    //      are not updated directly by the call to this function and the
2070    //      active_network_info is NULL, preventing us from inhering whatever
2071    //      might be there.
2072
2073    if (bss_config != NULL){
2074        //////////////////
2075        if (update_mask & BSS_FIELD_MASK_BSSID) {
2076            if (wlan_addr_eq(bss_config->bssid, zero_addr) == 0) {
2077                if ((active_network_info != NULL) && wlan_addr_eq(bss_config->bssid, active_network_info->bss_config.bssid)) {
2078                    // The caller of this function claimed that it was updating the BSSID,
2079                    // but the new BSSID matches the one already specified in active_bss_info.
2080                    // Complete the rest of this function as if that bit in the update mask
2081                    // were not set
2082                    update_mask &= ~BSS_FIELD_MASK_BSSID;
2083                } else {
2084                    // Changing the BSSID, perform necessary argument checks
2085                    if (wlan_addr_eq(bss_config->bssid, wlan_mac_addr) == 0) {
2086                        // In the AP implementation, the BSSID provided must be
2087                        // the hardware MAC address of the node
2088                        return_status |= BSS_CONFIG_FAILURE_BSSID_INVALID;
2089                    }
2090                    if (((update_mask & BSS_FIELD_MASK_SSID) == 0) ||
2091                        ((update_mask & BSS_FIELD_MASK_CHAN) == 0) ||
2092                        ((update_mask & BSS_FIELD_MASK_BEACON_INTERVAL) == 0)) {
2093                        return_status |= BSS_CONFIG_FAILURE_BSSID_INSUFFICIENT_ARGUMENTS;
2094                    }
2095                }
2096            }
2097        } else {
2098            if (active_network_info == NULL) {
2099                // Cannot update BSS without specifying BSSID
2100                return_status |= BSS_CONFIG_FAILURE_BSSID_INSUFFICIENT_ARGUMENTS;
2101            }
2102        }
2103        //////////////////
2104        if (update_mask & BSS_FIELD_MASK_CHAN) {
2105            if (wlan_verify_channel(
2106                    wlan_mac_high_bss_channel_spec_to_radio_chan(bss_config->chan_spec)) != WLAN_SUCCESS) {
2107                return_status |= BSS_CONFIG_FAILURE_CHANNEL_INVALID;
2108            }
2109        }
2110        //////////////////
2111        if (update_mask & BSS_FIELD_MASK_BEACON_INTERVAL) {
2112            if ((bss_config->beacon_interval != BEACON_INTERVAL_NO_BEACON_TX) &&
2113                (bss_config->beacon_interval <  10)) {
2114                return_status |= BSS_CONFIG_FAILURE_BEACON_INTERVAL_INVALID;
2115            }
2116        }
2117        //////////////////
2118        if (update_mask & BSS_FIELD_MASK_HT_CAPABLE) {
2119            if (bss_config->ht_capable > 1) {
2120                return_status |= BSS_CONFIG_FAILURE_HT_CAPABLE_INVALID;
2121            }
2122        } else if(active_network_info == NULL) {
2123            // Adopt C default value
2124            bss_config->ht_capable = WLAN_DEFAULT_BSS_CONFIG_HT_CAPABLE;
2125            update_mask |= BSS_FIELD_MASK_HT_CAPABLE;
2126        }
2127        //////////////////
2128        if (update_mask & BSS_FIELD_MASK_DTIM_PERIOD) {
2129            if(bss_config->dtim_period == 0){
2130                return_status |= BSS_CONFIG_FAILURE_DTIM_PERIOD_INVALID;
2131            }
2132
2133        } else if(active_network_info == NULL) {
2134            // Adopt C default value
2135            bss_config->dtim_period = WLAN_DEFAULT_BSS_CONFIG_DTIM_PERIOD;
2136            update_mask |= BSS_FIELD_MASK_DTIM_PERIOD;
2137        }
2138    }
2139
2140    if (return_status == 0) {
2141        //---------------------------------------------------------
2142        // 2. Apply BSS configuration changes
2143        //      Now that the provided bss_config_t struct is valid, apply the changes.
2144
2145        // Disable interrupts around these modifications to prevent state
2146        // changing out from underneath this context while the new BSS
2147        // configuration parameters are only partially updated.
2148        curr_interrupt_state = wlan_platform_intc_stop();
2149
2150        if ((bss_config == NULL) || (update_mask & BSS_FIELD_MASK_BSSID)) {
2151            // Adopting a new BSSID. This could mean either
2152            //    1) Shutting the BSS down
2153            // or 2) Shutting the BSS down and then starting a new BSS.
2154            //
2155            // In either case, first remove any station_info structs
2156            // that are members of the current active_bss_info and return to
2157            // a NULL active_bss_info state.
2158            //
2159            // This will not result in any OTA transmissions to the stations.
2160
2161            if (active_network_info != NULL) {
2162                //Purge all tranmissions queues
2163                purge_all_wireless_tx_queue();
2164
2165                if ((bss_config == NULL) ||
2166                        ((update_mask & BSS_FIELD_MASK_BSSID) && wlan_addr_eq(bss_config->bssid, zero_addr)) ) {
2167                    xil_printf("Terminating BSS\n");
2168                }
2169
2170                // Remove all associations
2171                next_station_info_entry = active_network_info->members.first;
2172                iter = active_network_info->members.length;
2173
2174                while ((next_station_info_entry != NULL) && (iter-- > 0)) {
2175                    curr_station_info_entry = next_station_info_entry;
2176                    next_station_info_entry = dl_entry_next(curr_station_info_entry);
2177
2178                    curr_station_info = (station_info_t*)(curr_station_info_entry->data);
2179
2180                    // Remove the associations
2181                    network_info_remove_member(active_network_info, curr_station_info->addr);
2182
2183                    time_hr_min_sec = wlan_mac_time_to_hr_min_sec(get_system_time_usec());
2184
2185                    xil_printf("*%dh:%02dm:%02ds* STA %02x:%02x:%02x:%02x:%02x:%02x has disassociated\n",
2186                            time_hr_min_sec.hr, time_hr_min_sec.min, time_hr_min_sec.sec,
2187                            curr_station_info->addr[0], curr_station_info->addr[1], curr_station_info->addr[2],
2188                            curr_station_info->addr[3], curr_station_info->addr[4], curr_station_info->addr[5]);
2189
2190                    // Lower KEEP flag so that the MAC High Framework can cleanup
2191                    curr_station_info->flags &= ~STATION_INFO_FLAG_KEEP;
2192
2193                    // Update the hex display to show station was removed
2194                    wlan_platform_high_userio_disp_status(USERIO_DISP_STATUS_MEMBER_LIST_UPDATE, active_network_info->members.length);
2195                }
2196
2197                // Remove the bss_info from the network list
2198                //     - When the AP "leaves" a BSS, the BSS actually no longer exists.  Therefore, it should
2199                //       not continue to exist in the network list.
2200                dl_list* network_info_list = wlan_mac_high_get_network_info_list();
2201                network_info_entry_t* network_entry     = wlan_mac_high_find_network_info_BSSID(active_network_info->bss_config.bssid);
2202
2203                wlan_mac_high_clear_network_info(active_network_info);
2204                dl_entry_remove(network_info_list, (dl_entry*)network_entry);
2205                network_info_checkin(network_entry);
2206
2207                // Set "active_network_info" to NULL
2208                //     - All functions must be able to handle active_network_info = NULL
2209                active_network_info = NULL;
2210
2211                // Disable beacons immediately
2212                ((tx_frame_info_t*)CALC_PKT_BUF_ADDR(platform_common_dev_info.tx_pkt_buf_baseaddr, TX_PKT_BUF_BEACON))->tx_pkt_buf_state = TX_PKT_BUF_HIGH_CTRL;
2213                gl_beacon_txrx_config.beacon_tx_mode = NO_BEACON_TX;
2214                bzero(gl_beacon_txrx_config.bssid_match, MAC_ADDR_LEN);
2215                wlan_mac_high_config_txrx_beacon(&gl_beacon_txrx_config);
2216
2217                // Set hex display to "No BSS"
2218                wlan_platform_high_userio_disp_status(USERIO_DISP_STATUS_MEMBER_LIST_UPDATE, 0xFF);
2219            }
2220
2221            // (bss_config_update == NULL) is one way to remove the BSS state of the node. This operation
2222            // was executed just above.  Rather that continuing to check non-NULLness of bss_config_update
2223            // throughout the rest of this function, just re-enable interrupts and return early.
2224
2225            if (bss_config == NULL) {
2226                wlan_platform_intc_set_state(curr_interrupt_state);
2227                return return_status;
2228            }
2229
2230            // active_network_info is guaranteed to be NULL at this point in the code
2231            // bss_config_update is guaranteed to be non-NULL at this point in the code
2232
2233            // Update BSS
2234            //     - BSSID must not be zero_addr (reserved address)
2235            if (wlan_addr_eq(bss_config->bssid, zero_addr) == 0) {
2236                // Stop the scan state machine if it is running
2237                if (wlan_mac_scan_is_scanning()) {
2238                    wlan_mac_scan_stop();
2239                }
2240
2241                // Create a new network_info_t or overwrite an existing one with matching BSSID.
2242                //     Note:  The wildcard SSID and 0-valued channel arguments are temporary. Because
2243                //         of the error checking at the top of this function, the bss_config will
2244                //         contain a valid SSID as well as channel. These fields will be updated
2245                //         in step 3).
2246                local_network_info = wlan_mac_high_create_network_info(bss_config->bssid, "", 0);
2247
2248                if (local_network_info != NULL) {
2249                    local_network_info->flags |= NETWORK_FLAGS_KEEP;
2250
2251                    local_network_info->capabilities = (BSS_CAPABILITIES_ESS);
2252
2253                    active_network_info = local_network_info;
2254                }
2255
2256                // Set hex display
2257                wlan_platform_high_userio_disp_status(USERIO_DISP_STATUS_MEMBER_LIST_UPDATE, active_network_info->members.length);
2258            }
2259        }
2260
2261        //---------------------------------------------------------
2262        // 3. Clean up
2263        //      Now that active_network_info has been updated, CPU_HIGH can communicate
2264        //      the changes to CPU_LOW so that the node is tuned to the correct channel,
2265        //      send beacons at the correct interval, and update the beacon
2266        //      template packet buffer.
2267        if (active_network_info != NULL) {
2268
2269            if (update_mask & BSS_FIELD_MASK_CHAN) {
2270                active_network_info->bss_config.chan_spec = bss_config->chan_spec;
2271                send_channel_switch_to_low = 1;
2272                update_beacon_template = 1;
2273            }
2274            if (update_mask & BSS_FIELD_MASK_SSID) {
2275                strncpy(active_network_info->bss_config.ssid, bss_config->ssid, SSID_LEN_MAX);
2276                update_beacon_template = 1;
2277            }
2278            if (update_mask & BSS_FIELD_MASK_BEACON_INTERVAL) {
2279                active_network_info->bss_config.beacon_interval = bss_config->beacon_interval;
2280                memcpy(gl_beacon_txrx_config.bssid_match, active_network_info->bss_config.bssid, MAC_ADDR_LEN);
2281                if ((active_network_info->bss_config.beacon_interval == BEACON_INTERVAL_NO_BEACON_TX) ||
2282                    (active_network_info->bss_config.beacon_interval == BEACON_INTERVAL_UNKNOWN)) {
2283                    ((tx_frame_info_t*)CALC_PKT_BUF_ADDR(platform_common_dev_info.tx_pkt_buf_baseaddr, TX_PKT_BUF_BEACON))->tx_pkt_buf_state = TX_PKT_BUF_HIGH_CTRL;
2284                    gl_beacon_txrx_config.beacon_tx_mode = NO_BEACON_TX;
2285                } else {
2286                    gl_beacon_txrx_config.beacon_tx_mode = AP_BEACON_TX;
2287                }
2288
2289                gl_beacon_txrx_config.beacon_interval_tu = active_network_info->bss_config.beacon_interval;
2290                gl_beacon_txrx_config.beacon_template_pkt_buf = TX_PKT_BUF_BEACON;
2291                update_beacon_template = 1;
2292                send_beacon_config_to_low = 1;
2293            }
2294            if (update_mask & BSS_FIELD_MASK_DTIM_PERIOD) {
2295                gl_beacon_txrx_config.dtim_period = bss_config->dtim_period;
2296                active_network_info->bss_config.dtim_period = bss_config->dtim_period;
2297                send_beacon_config_to_low = 1;
2298            }
2299            if (update_mask & BSS_FIELD_MASK_HT_CAPABLE) {
2300                // Changing the BSS HT_CAPABLE capabilities only affects what is advertised in
2301                // the BSS beacons.  It does not affect the HT capabilities of nodes in the
2302                // network.  It should also not change any of the default TX params since the
2303                // AP is still capable of sending and receiving HT packets.
2304
2305                active_network_info->bss_config.ht_capable = bss_config->ht_capable;
2306
2307                // Update the beacon template to match capabilities
2308                update_beacon_template = 1;
2309            }
2310
2311            // Update the beacon template
2312            //     In the event that CPU_LOW currently has the beacon packet buffer locked,
2313            //     block for now until it unlocks.  This will guarantee that beacon are updated
2314            //     before the function returns.
2315            default_beacon_tx_params = wlan_mac_get_default_tx_params(mcast_mgmt);
2316            if (update_beacon_template) {
2317
2318                while( wlan_mac_high_configure_beacon_tx_template((u8*)bcast_addr,
2319                                                                  wlan_mac_addr,
2320                                                                  active_network_info->bss_config.bssid,
2321                                                                  active_network_info,
2322                                                                  &default_beacon_tx_params,
2323                                                                  TX_FRAME_INFO_FLAGS_FILL_TIMESTAMP | TX_FRAME_INFO_FLAGS_WAIT_FOR_LOCK) != 0 ){}
2324
2325                mgmt_tag_tim_template = NULL;
2326                //Add the TIM tag
2327                update_tim_tag_all(SCHEDULE_ID_RESERVED_MAX);
2328            }
2329
2330            // Update the channel
2331            if (send_channel_switch_to_low) {
2332                wlan_mac_high_set_radio_channel(
2333                        wlan_mac_high_bss_channel_spec_to_radio_chan(active_network_info->bss_config.chan_spec));
2334            }
2335
2336            // Update Beacon configuration
2337            if (send_beacon_config_to_low) {
2338                wlan_mac_high_config_txrx_beacon(&gl_beacon_txrx_config);
2339            }
2340
2341            // Print new BSS information
2342            xil_printf("BSS Details: \n");
2343            xil_printf("  BSSID           : %02x-%02x-%02x-%02x-%02x-%02x\n",   active_network_info->bss_config.bssid[0],active_network_info->bss_config.bssid[1],
2344                                                                                active_network_info->bss_config.bssid[2],active_network_info->bss_config.bssid[3],
2345                                                                                active_network_info->bss_config.bssid[4],active_network_info->bss_config.bssid[5]);
2346            xil_printf("   SSID           : %s\n", active_network_info->bss_config.ssid);
2347            xil_printf("   Channel        : %d\n", wlan_mac_high_bss_channel_spec_to_radio_chan(active_network_info->bss_config.chan_spec));
2348            if (active_network_info->bss_config.beacon_interval == BEACON_INTERVAL_NO_BEACON_TX) {
2349                xil_printf("   Beacon Interval: No Beacon Tx\n");
2350            } else if (active_network_info->bss_config.beacon_interval == BEACON_INTERVAL_UNKNOWN) {
2351                xil_printf("   Beacon Interval: Unknown\n");
2352            } else {
2353                xil_printf("   Beacon Interval: %d TU (%d us)\n", active_network_info->bss_config.beacon_interval, active_network_info->bss_config.beacon_interval*1024);
2354            }
2355        }
2356
2357        // Restore interrupts after all BSS changes
2358        wlan_platform_intc_set_state(curr_interrupt_state);
2359    }
2360
2361    return return_status;
2362}
2363
2364
2365
2366/*****************************************************************************/
2367/**
2368 * @brief Callback to handle push of User I/O button 0
2369 *
2370 * Reference implementation does nothing.
2371 *
2372 * @param None
2373 * @return None
2374 *****************************************************************************/
2375void button_0_press(){
2376    return;
2377}
2378
2379/*****************************************************************************/
2380/**
2381 * @brief Callback to handle release of User I/O button 0
2382 *
2383 * Reference implementation does nothing.
2384 *
2385 * @param None
2386 * @return None
2387 *****************************************************************************/
2388void button_0_release(){
2389    return;
2390}
2391
2392/*****************************************************************************/
2393/**
2394 * @brief Accessor methods for global variables
2395 *
2396 * These functions will return pointers to global variables
2397 *
2398 * @param  None
2399 * @return None
2400 *****************************************************************************/
2401dl_list* get_network_member_list(){
2402    if(active_network_info != NULL){
2403        return &(active_network_info->members);
2404    } else {
2405        return NULL;
2406    }
2407}
2408
2409network_info_t* active_network_info_getter(){ return active_network_info; }
2410
2411#if WLAN_SW_CONFIG_ENABLE_WLAN_EXP
2412
2413// ****************************************************************************
2414// Define MAC Specific User Commands
2415//
2416// NOTE:  All User Command IDs (CMDID_*) must be a 24 bit unique number
2417//
2418
2419//-----------------------------------------------
2420// MAC Specific User Commands
2421//
2422// #define CMDID_USER_<COMMAND_NAME>                       0x100000
2423
2424
2425//-----------------------------------------------
2426// MAC Specific User Command Parameters
2427//
2428// #define CMD_PARAM_USER_<PARAMETER_NAME>                 0x00000000
2429
2430
2431
2432/*****************************************************************************/
2433/**
2434 * Process User Commands
2435 *
2436 * This function is part of the WLAN Exp framework and will process the framework-
2437 * level user commands.  This function intentionally does not implement any user
2438 * commands and it is left to the user to implement any needed functionality.   By
2439 * default, any commands not processed in this function will print an error to the
2440 * UART.
2441 *
2442 * @return  int              - Status of the command:
2443 *                                 NO_RESP_SENT - No response has been sent
2444 *                                 RESP_SENT    - A response has been sent
2445 *
2446 * @note    See on-line documentation for more information:
2447 *          https://warpproject.org/trac/wiki/802.11/wlan_exp/Extending
2448 *
2449 *****************************************************************************/
2450int wlan_exp_process_user_cmd(cmd_resp_hdr_t* cmd_hdr, eth_tx_queue_buffer_t* eth_tx_queue_buffer) {
2451
2452    //
2453    // IMPORTANT ENDIAN NOTES:
2454    //     - command
2455    //         - header - Already endian swapped by the framework (safe to access directly)
2456    //         - args   - Must be endian swapped as necessary by code (framework does not know the contents of the command)
2457    //     - response
2458    //         - header - Will be endian swapped by the framework (safe to write directly)
2459    //         - args   - Must be endian swapped as necessary by code (framework does not know the contents of the response)
2460    //
2461
2462    // Standard variables
2463    //
2464    // Used for accessing command arguments and constructing the command response header/payload
2465    //
2466    // NOTE:  Some of the standard variables below have been commented out.  This was to remove
2467    //     compiler warnings for "unused variables" since the default implementation is empty.  As
2468    //     you add commands, you should un-comment the standard variables.
2469    //
2470
2471    u32 resp_sent = NO_RESP_SENT;
2472    u32 cmd_id = CMD_TO_CMDID(cmd_hdr->cmd);
2473#if 0
2474    // Segment 0 length includes a fully formed command response header
2475    //  because one was created with default values suitable for a responseless
2476    //  acknowledgment.
2477    cmd_resp_hdr_t* resp_hdr = (cmd_resp_hdr_t*)(eth_tx_queue_buffer->seg0
2478                                                 + eth_tx_queue_buffer->seg0_len
2479                                                 - sizeof(cmd_resp_hdr_t));
2480
2481    u32* cmd_args_32 = (u32*)((u8*)cmd_hdr + sizeof(cmd_resp_hdr_t));
2482#endif
2483
2484    switch(cmd_id){
2485
2486//-----------------------------------------------------------------------------
2487// MAC Specific User Commands
2488//-----------------------------------------------------------------------------
2489
2490        // Template framework for a Command
2491        //
2492        // NOTE:  The WLAN Exp framework assumes that the Over-the-Wire format of the data is
2493        //     big endian.  However, the node processes data using little endian.  Therefore,
2494        //     any data received from the host must be properly endian-swapped and similarly,
2495        //     any data sent to the host must be properly endian-swapped.  The built-in Xilinx
2496        //     functions:  Xil_Ntohl() (Network to Host) and Xil_Htonl() (Host to Network) are
2497        //     used for this.
2498        //
2499#if 0
2500        //---------------------------------------------------------------------
2501        case CMDID_USER_<COMMAND_NAME>: {
2502            // Command Description
2503            //
2504            // Message format:
2505            //     cmd_args_32[0:N]    Document command arguments from the host
2506            //
2507            // Response format:
2508            //     resp_args_32[0:M]   Document response arguments from the node
2509            //
2510            // NOTE:  Variables are declared above.
2511            // NOTE:  Please take care of the endianness of the arguments (see comment above)
2512            //
2513
2514            // Variables for template command
2515            int status;
2516            u32 arg_0;
2517            interrupt_state_t curr_interrupt_state;
2518
2519            // Initialize variables
2520            status = CMD_PARAM_SUCCESS;
2521            arg_0 = Xil_Ntohl(cmd_args_32[0]); // Swap endianness of command argument
2522
2523            // Do something with argument(s)
2524            xil_printf("Command argument 0: 0x%08x\n", arg_0);
2525
2526            // If necessary, disable interrupts before processing the command
2527            //  Interrupts must be disabled if the command implementation relies on any state that might
2528            //  change during an interrupt service routine. See the user guide for more details
2529            //  https://warpproject.org/trac/wiki/802.11/wlan_exp/Extending
2530            curr_interrupt_state = wlan_platform_intc_stop();
2531
2532            // Process command arguments and generate any response payload
2533            //     NOTE:  If interrupts were disabled above, take care to avoid any long-running code in this
2534            //         block (i.e. avoid xil_printf()). When interrupts are disabled, CPU High is unable to
2535            //         respond to CPU Low (ie CPU High will not send / receive packets) and execute scheduled
2536            //         tasks, such as LTGs.
2537
2538            // Re-enable interrupts before returning (only do this if wlan_platform_intc_stop() is called above)
2539            wlan_platform_intc_set_state(curr_interrupt_state);
2540
2541            // Send response
2542            //   NOTE:  It is good practice to send a status as the first argument of the response.
2543            //       This way it is easy to determine if the other data in the response is valid.
2544            //       Predefined status values are:  CMD_PARAM_SUCCESS, CMD_PARAM_ERROR
2545            //
2546            wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, status);
2547        }
2548        break;
2549#endif
2550
2551
2552        //---------------------------------------------------------------------
2553        default: {
2554            wlan_exp_printf(WLAN_EXP_PRINT_ERROR, print_type_node, "Unknown AP user command: 0x%x\n", cmd_id);
2555        }
2556        break;
2557    }
2558
2559    return resp_sent;
2560}
2561
2562
2563#endif
2564
Note: See TracBrowser for help on using the repository browser.