source: ReferenceDesigns/w3_802.11/c/wlan_mac_high_sta/wlan_mac_sta.c

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

1.8.0 release wlan-mac-se

File size: 55.2 KB
Line 
1/** @file wlan_mac_sta.c
2 *  @brief Station
3 *
4 *  This contains code for the 802.11 Station.
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/***************************** Include Files *********************************/
15#include "wlan_mac_high_sw_config.h"
16
17// Xilinx SDK includes
18#include "stdio.h"
19#include "stdlib.h"
20#include "string.h"
21#include "xil_cache.h"
22
23// WLAN includes
24#include "wlan_platform_common.h"
25#include "wlan_platform_high.h"
26#include "wlan_mac_802_11_defs.h"
27#include "wlan_mac_queue.h"
28#include "wlan_mac_event_log.h"
29#include "wlan_mac_entries.h"
30#include "wlan_mac_ltg.h"
31#include "wlan_mac_high.h"
32#include "wlan_mac_packet_types.h"
33#include "wlan_mac_eth_util.h"
34#include "ascii_characters.h"
35#include "wlan_mac_schedule.h"
36#include "wlan_mac_dl_list.h"
37#include "wlan_mac_network_info.h"
38#include "wlan_mac_station_info.h"
39#include "wlan_mac_scan.h"
40#include "wlan_mac_sta_join.h"
41#include "wlan_mac_sta.h"
42#include "wlan_mac_common.h"
43#include "wlan_mac_pkt_buf_util.h"
44
45
46// WLAN Exp includes
47#include "wlan_exp.h"
48#include "wlan_exp_common.h"
49#include "wlan_exp_node.h"
50#include "wlan_exp_node_sta.h"
51#include "wlan_exp_transport.h"
52#include "wlan_exp_user.h"
53
54
55/*************************** Constant Definitions ****************************/
56
57#define WLAN_DEFAULT_CHANNEL 1
58#define WLAN_DEFAULT_TX_PWR 15
59#define WLAN_DEFAULT_TX_ANTENNA TX_ANTMODE_SISO_ANTA
60#define WLAN_DEFAULT_RX_ANTENNA RX_ANTMODE_SISO_ANTA
61
62
63// The WLAN_DEFAULT_USE_HT define will set the default unicast TX phy mode
64// to:  1 --> HTMF  or  0 --> NONHT.
65#define WLAN_DEFAULT_USE_HT 1
66
67
68/*********************** Global Variable Definitions *************************/
69
70// Static QIDs
71s16 mgmt_qid;
72s16 ap_qid;
73
74// If you want this station to try to associate to a known AP at boot, type
75//   the string here. Otherwise, let it be an empty string.
76static char access_point_ssid[SSID_LEN_MAX + 1] = "MANGO-AP";
77// static char access_point_ssid[SSID_LEN_MAX + 1] = "";
78
79// Access point information
80u8 my_aid;
81network_info_t* active_network_info;
82
83// Tx queue variables;
84static u32 max_queue_size;
85volatile u8 pause_data_queue;
86
87// MAC address
88u8 wlan_mac_addr[MAC_ADDR_LEN];
89
90// Beacon configuration
91static beacon_txrx_config_t gl_beacon_txrx_config;
92
93
94/*************************** Functions Prototypes ****************************/
95
96#if WLAN_SW_CONFIG_ENABLE_WLAN_EXP
97int  wlan_exp_process_user_cmd(cmd_resp_hdr_t* cmd_hdr, eth_tx_queue_buffer_t* eth_tx_queue_buffer);
98#endif
99
100void sta_set_beacon_ts_update_mode(u32 enable);
101
102
103/******************************** Functions **********************************/
104
105
106int main() {
107    // Call the platform-supplied cpu_init() first to setup any
108    //  processor-specific settings to enable sane execution
109    //  of the platform and framework code below
110    wlan_platform_cpu_high_init();
111
112    // This list of channels will be used by the active scan state machine. The STA will scan
113    //  each channel looking for a network with the default SSID
114    //
115
116    volatile join_parameters_t*             join_parameters;
117
118    // Print initial message to UART
119    xil_printf("\f");
120    xil_printf("----- Mango 802.11 Reference Design -----\n");
121    xil_printf("----- v1.8.0 ----------------------------\n");
122    xil_printf("----- wlan_mac_sta ----------------------\n");
123    xil_printf("Compiled %s %s\n\n", __DATE__, __TIME__);
124
125    wlan_mac_common_malloc_init();
126
127    // Initialize the maximum TX queue size
128    max_queue_size = MAX_TX_QUEUE_LEN;
129
130    // Unpause the queue
131    pause_data_queue = 0;
132
133    // Initialize AID / Beacons configuration (not associated with an AP)
134    my_aid = 0;
135
136    gl_beacon_txrx_config.ts_update_mode = ALWAYS_UPDATE;
137    bzero(gl_beacon_txrx_config.bssid_match, MAC_ADDR_LEN);
138    gl_beacon_txrx_config.beacon_tx_mode = NO_BEACON_TX;
139    gl_beacon_txrx_config.beacon_interval_tu = 0;
140
141    // Initialize the utility library
142    wlan_mac_high_init();
143
144    // Open static queue for management frames
145    mgmt_qid = queue_open((void*)wlan_null_callback, 0, max_queue_size);
146    ap_qid = -1;
147
148    // STA is not currently a member of a BSS
149    configure_bss(NULL, 0);
150
151    // Initialize hex display to "No BSS"
152    wlan_platform_high_userio_disp_status(USERIO_DISP_STATUS_MEMBER_LIST_UPDATE, 0xFF);
153
154    // Initialize the join state machine
155    wlan_mac_sta_join_init();
156
157    // Set default Tx params
158    // Set sane default Tx params. These will be overwritten by the user application
159    tx_params_t tx_params = { .phy = { .mcs = 3, .phy_mode = PHY_MODE_NONHT, .antenna_mode = WLAN_DEFAULT_TX_ANTENNA, .power = WLAN_DEFAULT_TX_PWR },
160                              .mac = { .flags = 0 } };
161
162    if(WLAN_DEFAULT_USE_HT) tx_params.phy.phy_mode = PHY_MODE_HTMF;
163
164    wlan_mac_set_default_tx_params(unicast_data, &tx_params);
165
166    tx_params.phy.mcs = 0;
167    tx_params.phy.phy_mode = PHY_MODE_NONHT;
168
169    wlan_mac_set_default_tx_params(unicast_mgmt, &tx_params);
170    wlan_mac_set_default_tx_params(mcast_data, &tx_params);
171    wlan_mac_set_default_tx_params(mcast_mgmt, &tx_params);
172
173    // Re-apply the defaults to any existing station_info_t structs that this AP
174    // knows about
175    wlan_mac_reapply_default_tx_params();
176
177
178    // Initialize callbacks
179#if WLAN_SW_CONFIG_ENABLE_ETH_BRIDGE
180    wlan_mac_util_set_eth_rx_callback((void*) ethernet_receive);
181#endif
182    wlan_mac_high_set_mpdu_rx_callback((void*) mpdu_rx_process);
183    wlan_mac_high_set_uart_rx_callback((void*) uart_rx);
184    wlan_mac_high_set_poll_tx_queues_callback((void*) poll_tx_queues);
185#if WLAN_SW_CONFIG_ENABLE_LTG
186    wlan_mac_ltg_sched_set_callback((void*) ltg_event);
187#endif //WLAN_SW_CONFIG_ENABLE_LTG
188    wlan_mac_scan_set_tx_probe_request_callback((void*) send_probe_req);
189    wlan_mac_scan_set_state_change_callback((void*) process_scan_state_change);
190
191#if WLAN_SW_CONFIG_ENABLE_WLAN_EXP
192
193    // NOTE:  To use the WLAN Experiments Framework, it must be initialized after
194    //        CPU low has populated the hw_info structure in the MAC High framework.
195
196    // Initialize WLAN Exp
197    wlan_exp_node_init();
198
199    // Set WLAN Exp callbacks
200    wlan_exp_set_process_node_cmd_callback((void*) process_wlan_exp_app_cmd);
201    wlan_exp_set_purge_all_wireless_tx_queue_callback((void*) purge_all_wireless_tx_queue);
202    //   - wlan_exp_set_tx_cmd_add_association_callback() should not be used by the STA
203    wlan_exp_set_process_user_cmd_callback((void*) wlan_exp_process_user_cmd);
204    wlan_exp_set_beacon_ts_update_mode_callback((void*) sta_set_beacon_ts_update_mode);
205    wlan_exp_set_process_config_bss_callback((void*) configure_bss);
206    wlan_exp_set_active_network_info_getter_callback((void*) active_network_info_getter);
207    //   - wlan_exp_set_beacon_tx_param_update_callback() should not be used by the STA
208
209    // Set CPU_HIGH Type in wlan_exp's node_info struct;
210    wlan_exp_node_set_type_high(APPLICATION_ROLE_STA,  __DATE__, __TIME__);
211#endif
212
213    // CPU Low will pass HW information to CPU High as part of the boot process
214    //   - Get necessary HW information
215    memcpy((void*) &(wlan_mac_addr[0]), (void*) get_mac_hw_addr_wlan(), MAC_ADDR_LEN);
216
217    // Set the at-boot MAC Time to 0 usec
218    set_mac_time_usec(0);
219
220    wlan_mac_high_set_radio_channel(WLAN_DEFAULT_CHANNEL);
221    wlan_mac_high_set_rx_ant_mode(WLAN_DEFAULT_RX_ANTENNA);
222    wlan_mac_high_set_tx_ctrl_power(WLAN_DEFAULT_TX_PWR);
223    wlan_mac_high_set_radio_tx_power(WLAN_DEFAULT_TX_PWR);
224
225    wlan_platform_high_userio_disp_status(USERIO_DISP_STATUS_APPLICATION_ROLE, APPLICATION_ROLE_STA);
226
227    // Schedule all events
228    //     None at this time
229
230#if WLAN_SW_CONFIG_ENABLE_LOGGING
231    // Reset the event log
232    event_log_reset();
233#endif
234
235    // Print Station information to the terminal
236    xil_printf("------------------------\n");
237    xil_printf("WLAN MAC Station boot complete.\n");
238    xil_printf("  Default SSID  : %s \n", access_point_ssid);
239
240#ifdef WLAN_USE_UART_MENU
241    xil_printf("\nPress the Esc key in your terminal to access the UART menu\n");
242#endif
243
244    // Start the interrupts
245    wlan_platform_intc_set_state(INTERRUPTS_ENABLED);
246
247    // If there is a default SSID and the DIP switch allows it, initiate a probe request
248    if ((strlen(access_point_ssid) > 0) && ((wlan_platform_userio_get_state() & USERIO_INPUT_MASK_SW_3) == 0)) {
249        // Get current join parameters
250        join_parameters = wlan_mac_sta_get_join_parameters();
251
252        // Set join parameters
253        //     - Zero out BSSID / Channel so the node performs a scan before joining
254        join_parameters->channel = 0;
255        bzero((void*)join_parameters->bssid, MAC_ADDR_LEN);
256
257        wlan_mac_high_free(join_parameters->ssid);
258        join_parameters->ssid = strndup(access_point_ssid, SSID_LEN_MAX);
259
260        // Join the default SSID
261        wlan_mac_sta_join();
262    }
263
264    while(1){
265        wlan_mac_poll();
266    }
267
268    // Unreachable, but non-void return keeps the compiler happy
269    return WLAN_FAILURE;
270}
271
272
273
274/*****************************************************************************/
275/**
276 * @brief Send probe request
277 *
278 * This function is part of the scan infrastructure and will be called whenever
279 * the node needs to send a probe request.
280 *
281 * @param   None
282 * @return  None
283 *
284 *****************************************************************************/
285void send_probe_req(){
286    u16 tx_length;
287    dl_entry* tx_queue_entry;
288    tx_80211_queue_buffer_t* tx_queue_buffer;
289    volatile scan_parameters_t* scan_parameters = wlan_mac_scan_get_parameters();
290
291    // Check out queue element for packet
292    tx_queue_entry = queue_checkout();
293
294    // Create probe request
295    if(tx_queue_entry != NULL){
296        tx_queue_buffer = (tx_80211_queue_buffer_t*)(tx_queue_entry->data);
297
298        tx_length = wlan_create_probe_req_frame(tx_queue_buffer->pkt,
299                                                (u8*)bcast_addr,
300                                                wlan_mac_addr,
301                                                (u8*)bcast_addr,
302                                                scan_parameters->ssid);
303
304        // Fill in metadata
305        tx_queue_buffer->flags = 0;
306        tx_queue_buffer->length = tx_length;
307        tx_queue_buffer->seg0_len = tx_length;
308        tx_queue_buffer->seg1_len = 0;
309        tx_queue_buffer->seg1_offset = 0;
310        tx_queue_buffer->station_info = station_info_create((u8*)bcast_addr);
311
312        // Put the packet in the queue
313        wlan_mac_enqueue_wireless_tx(mgmt_qid, tx_queue_entry);
314
315        // Poll the TX queues to possibly send the packet
316        poll_tx_queues(PKT_BUF_GROUP_GENERAL);
317    }
318}
319
320
321
322/*****************************************************************************/
323/**
324 * @brief Handle state change in the network scanner
325 *
326 * This function is part of the scan infrastructure and will be called whenever
327 * the scanner is started, stopped, paused, or resumed. This allows the STA
328 * to revert the channel to a known-good state when the scanner has stopped and
329 * also serves as notification to the project that it should stop dequeueing data
330 * frames since it might be on a different channel than its intended recipient.
331 *
332 * @param   None
333 * @return  None
334 *
335 *****************************************************************************/
336void process_scan_state_change(scan_state_t scan_state){
337
338    // ------------------------------------------------------------------------
339    // Note on scanning:
340    //
341    //   Currently, scanning should only be done with active_bss_info = NULL, ie the
342    // node is not currently in a BSS.  This is to avoid any corner cases.  The
343    // STA needs to do the following things to make scanning safe when active_bss_info
344    // is not NULL:
345    //
346    //     - Send a NULL data packet indicating that the station is entering a
347    //       DOZE state when the scan is started or resumed.
348    //     - Send a NULL data packet indicating that the station is entering an
349    //       AWAKE state when the scan is paused or stopped.
350    //
351    // Note: The STA doesn't need full power savings functionality to enact this
352    // behavior (e.g. listening for DTIMS at particular intervals, watching the TIM
353    // bitmap for our AID, etc).  The decision to doze or wake isn't a function of
354    // what the AP is up to, it's a function of whether the STA decides to start
355    // scanning.
356    // ------------------------------------------------------------------------
357
358    switch(scan_state){
359        case SCAN_IDLE:
360        case SCAN_PAUSED:
361            pause_data_queue = 0;
362            if(active_network_info != NULL){
363                wlan_mac_high_set_radio_channel(
364                        wlan_mac_high_bss_channel_spec_to_radio_chan(active_network_info->bss_config.chan_spec));
365            }
366        break;
367        case SCAN_RUNNING:
368            pause_data_queue = 1;
369        break;
370    }
371}
372
373
374
375/*****************************************************************************/
376/**
377 * @brief Poll Tx queues to select next available packet to transmit
378 *
379 * This function will attempt to completely fill all Tx packet buffers in the
380 * PKT_BUF_GROUP_GENERAL group.
381 *
382 * The reference implementation uses a simple queue prioritization scheme:
383 *   - Two queues are defined: Management (MANAGEMENT_QID) and Data (UNICAST_QID)
384 *     - The Management queue is for all management traffic
385 *     - The Data queue is for all data to the associated AP
386 *   - The code alternates its polling between queues
387 *
388 *****************************************************************************/
389void poll_tx_queues(){
390    int i;
391    int num_pkt_bufs_avail;
392    int poll_loop_cnt;
393    dl_entry* tx_queue_entry;
394
395    #define MAX_NUM_QUEUE 2
396
397    num_pkt_bufs_avail = wlan_mac_num_tx_pkt_buf_available(PKT_BUF_GROUP_GENERAL);
398
399
400    // Are we pausing transmissions?
401    if (pause_data_queue == 0) {
402        static u32 queue_index = 0;
403
404        // This loop will (at most) check every queue twice
405        //  This handles the case of a single non-empty queue needing to supply packets
406        //  for both GENERAL packet buffers
407        poll_loop_cnt = 0;
408        while((num_pkt_bufs_avail > 0) && (poll_loop_cnt < (2*MAX_NUM_QUEUE))) {
409            poll_loop_cnt++;
410
411            queue_index = (queue_index + 1) % MAX_NUM_QUEUE;
412
413            switch(queue_index){
414                case 0:
415                    tx_queue_entry = queue_dequeue(mgmt_qid);
416                break;
417                case 1:
418                    if(ap_qid != -1){
419                        tx_queue_entry = queue_dequeue( ap_qid );
420                    } else {
421                        tx_queue_entry = NULL;
422                    }
423                break;
424            }
425            if(tx_queue_entry) {
426                // Update the packet buffer group
427                ((tx_80211_queue_buffer_t*)(tx_queue_entry->data))->tx_queue_details.pkt_buf_group = PKT_BUF_GROUP_GENERAL;
428                // Successfully dequeued a management packet - transmit and checkin
429                wlan_mac_transmit_wireless(tx_queue_entry);
430                // Continue the loop
431                num_pkt_bufs_avail--;
432                continue;
433            }
434        }
435    } else {
436        // We are only currently allowed to send management frames. Typically this is caused by an ongoing
437        // active scan
438        for(i=0; i<num_pkt_bufs_avail; i++) {
439            // Dequeue packets until there are no more packet buffers or no more packets
440            tx_queue_entry = queue_dequeue(mgmt_qid);
441            if(tx_queue_entry) {
442                // Update the packet buffer group
443                ((tx_80211_queue_buffer_t*)(tx_queue_entry->data))->tx_queue_details.pkt_buf_group = PKT_BUF_GROUP_GENERAL;
444                // Successfully dequeued a management packet - transmit and checkin
445                wlan_mac_transmit_wireless(tx_queue_entry);
446            } else {
447                // Queue is empty - end this loop
448                break;
449            }
450        }
451    }
452}
453
454
455
456/*****************************************************************************/
457/**
458 * @brief Purges all packets from all Tx queues
459 *
460 * This function discards all currently en-queued packets awaiting transmission and returns all
461 * queue entries to the free pool.
462 *
463 * This function does not discard packets already submitted to the lower-level MAC for transmission
464 *
465 * @param None
466 * @return None
467 *****************************************************************************/
468void purge_all_wireless_tx_queue(){
469    // Purge all data transmit queues
470    wlan_mac_purge_wireless_tx(mgmt_qid); // Management Queue
471    if(ap_qid != -1) wlan_mac_purge_wireless_tx(ap_qid); // AP Queue
472}
473
474/*****************************************************************************/
475/**
476 * @brief Callback to handle insertion of an Ethernet reception into the corresponding wireless Tx queue
477 *
478 * This function is called when a new Ethernet packet is received that must be transmitted via the wireless interface.
479 * The packet must be encapsulated before it is passed to this function. Ethernet encapsulation is implemented in the mac_high framework.
480 *
481 *****************************************************************************/
482int ethernet_receive(eth_rx_queue_buffer_t* eth_rx_queue_buffer){
483
484    tx_80211_queue_buffer_t* tx_queue_buffer;
485    ethernet_header_t* eth_hdr;
486    station_info_t* ap_station_info;
487
488    if(active_network_info == NULL) return 0;
489
490    eth_hdr = (ethernet_header_t*)eth_rx_queue_buffer->pkt;
491
492    if( (eth_hdr->ethertype != ETH_TYPE_ARP) && (eth_hdr->ethertype != ETH_TYPE_IP) ) return 0;
493
494
495    // Check associations
496    //     Is there an AP to send the packet to?
497    if(active_network_info != NULL){
498        ap_station_info = (station_info_t*)((active_network_info->members.first)->data);
499
500        // Send the packet to the AP
501        if(queue_length(ap_qid) < max_queue_size){
502
503            //Encapsulate the packet
504            // Note: the encapsulation function handles filling in the C0/C1 lengths and C1 offset for us
505            tx_queue_buffer = wlan_eth_encap( eth_rx_queue_buffer, WLAN_ETH_ENCAP_FLAGS_OVERWRITE_PYLD_ADDRS );
506
507            if(tx_queue_buffer){
508                tx_queue_buffer->flags = 0;
509
510                wlan_create_data_frame_header(tx_queue_buffer->pkt,
511                                              ap_station_info->addr,
512                                              wlan_mac_addr,
513                                              eth_hdr->dest_mac_addr,
514                                              MAC_FRAME_CTRL2_FLAG_TO_DS);
515
516                // Fill in metadata
517                tx_queue_buffer->flags = TX_80211_QUEUE_BUFFER_FLAGS_FILL_DURATION;
518                tx_queue_buffer->station_info = ap_station_info;
519
520                // Put the packet in the queue
521                wlan_mac_enqueue_wireless_tx(ap_qid, tx_queue_buffer->pyld_queue_hdr.dle);
522            } else {
523                return 0;
524            }
525
526
527
528        } else {
529            // Packet was not successfully enqueued
530            return 0;
531        }
532
533        // Packet was successfully enqueued
534        return 1;
535    } else {
536
537        // STA is not currently associated, so we won't send any eth frames
538        return 0;
539    }
540}
541
542
543
544/*****************************************************************************/
545/**
546 * @brief Process received MPDUs
547 *
548 * This callback function will process all the received MPDUs.
549 *
550 * This function must implement the state machine that will allow a station to join the AP.
551 *
552 * @param  void* pkt_buf_addr
553 *     - Packet buffer address;  Contains the contents of the MPDU as well as other packet information from CPU low
554 * @param  station_info_t * station_info
555 *     - Pointer to metadata about the station from which this frame was received
556 * @param  rx_common_entry* rx_event_log_entry
557 *     - Pointer to the log entry created for this reception by the MAC High Framework
558 * @return u32 flags
559 *
560 *****************************************************************************/
561u32 mpdu_rx_process(void* pkt_buf_addr, station_info_t* station_info, rx_common_entry* rx_event_log_entry) {
562
563    rx_frame_info_t* rx_frame_info = (rx_frame_info_t*)pkt_buf_addr;
564    void* mac_payload = (u8*)pkt_buf_addr + PHY_RX_PKT_BUF_MPDU_OFFSET;
565    u8* mac_payload_ptr_u8 = (u8*)mac_payload;
566    mac_header_80211* rx_80211_header = (mac_header_80211*)((void *)mac_payload_ptr_u8);
567
568    u16 rx_seq;
569    u8 unicast_to_me;
570    u8 to_multicast;
571    u8 is_associated = 0;
572    network_info_entry_t* network_info_entry;
573    network_info_t* curr_network_info;
574    volatile network_info_t* attempt_network_info;
575
576    u32 return_val = 0;
577    u16 length = rx_frame_info->phy_details.length;
578
579
580    // If this function was passed a CTRL frame (e.g., CTS, ACK), then we should just quit.
581    // The only reason this occured was so that it could be logged in the line above.
582    if((rx_80211_header->frame_control_1 & 0xF) == MAC_FRAME_CTRL1_TYPE_CTRL){
583        goto mpdu_rx_process_end;
584    }
585
586    // Determine destination of packet
587    unicast_to_me = wlan_addr_eq(rx_80211_header->address_1, wlan_mac_addr);
588    to_multicast  = wlan_addr_mcast(rx_80211_header->address_1);
589
590    // If the packet is good (ie good FCS) and it is destined for me, then process it
591    if( (rx_frame_info->flags & RX_FRAME_INFO_FLAGS_FCS_GOOD)){
592
593
594        // Sequence number is 12 MSB of seq_control field
595        rx_seq         = ((rx_80211_header->sequence_control) >> 4) & 0xFFF;
596
597        // Check if this was a duplicate reception
598        //   - Packet is unicast and directed towards me
599        //   - Packet has the RETRY bit set to 1 in the second frame control byte
600        //   - Received seq num matched previously received seq num for this STA
601        if( (station_info != NULL) && unicast_to_me ){
602            if( ((rx_80211_header->frame_control_2) & MAC_FRAME_CTRL2_FLAG_RETRY) && (station_info->latest_rx_seq == rx_seq) ) {
603                if(rx_event_log_entry != NULL){
604                    rx_event_log_entry->flags |= RX_FLAGS_DUPLICATE;
605                    return_val |= MAC_RX_CALLBACK_RETURN_FLAG_DUP;
606                }
607            } else {
608                station_info->latest_rx_seq = rx_seq;
609            }
610        }
611
612        if( active_network_info != NULL && station_info_is_member(&active_network_info->members, station_info) ) {
613
614            is_associated  = 1;
615
616            if( return_val & MAC_RX_CALLBACK_RETURN_FLAG_DUP ) {
617                // Finish the function
618                goto mpdu_rx_process_end;
619            }
620        }
621
622        if(unicast_to_me || to_multicast){
623            // Process the packet
624            switch(rx_80211_header->frame_control_1) {
625                //---------------------------------------------------------------------
626                case (MAC_FRAME_CTRL1_SUBTYPE_BEACON):
627                case (MAC_FRAME_CTRL1_SUBTYPE_PROBE_RESP):
628                    //TODO: Log a MAC time change
629                break;
630
631                //---------------------------------------------------------------------
632                case MAC_FRAME_CTRL1_SUBTYPE_QOSDATA:
633                case (MAC_FRAME_CTRL1_SUBTYPE_DATA):
634                    // Data packet
635                    //   - If the STA is associated with the AP and this is from the DS, then transmit over the wired network
636                    //
637                    if(is_associated){
638                        if((rx_80211_header->frame_control_2) & MAC_FRAME_CTRL2_FLAG_FROM_DS) {
639                            // MPDU is flagged as destined to the DS - send it for de-encapsulation and Ethernet Tx (if appropriate)
640#if WLAN_SW_CONFIG_ENABLE_ETH_BRIDGE
641                            if( wlan_addr_eq(rx_80211_header->address_3, wlan_mac_addr) == 0 ){
642                                wlan_eth_decap_and_send(mac_payload,
643                                                        NULL,
644                                                        rx_80211_header->address_3,
645                                                        length,
646                                                        WLAN_ETH_ENCAP_FLAGS_OVERWRITE_PYLD_ADDRS);
647                            }
648#endif
649                        }
650                    }
651                break;
652
653
654                //---------------------------------------------------------------------
655                case (MAC_FRAME_CTRL1_SUBTYPE_ASSOC_RESP):
656                    // Association response
657                    //   - If we are in the correct association state and the response was success, then associate with the AP
658                    //
659                    mac_payload_ptr_u8 += sizeof(mac_header_80211);
660
661                    if(wlan_addr_eq(rx_80211_header->address_1, wlan_mac_addr) && ((association_response_frame*)mac_payload_ptr_u8)->status_code == STATUS_SUCCESS){
662                        // AP is authenticating us. Update BSS_info.
663                        network_info_entry = wlan_mac_high_find_network_info_BSSID(rx_80211_header->address_3);
664
665                        if(network_info_entry != NULL){
666                            curr_network_info = network_info_entry->data;
667                            wlan_mac_sta_successfully_associated(curr_network_info->bss_config.bssid,
668                                                                (((association_response_frame*)mac_payload_ptr_u8)->association_id)&~0xC000);
669
670                        }
671                    } else {
672                        // AP is rejecting association request
673                        //     - Check that the response was from a known BSS
674                        network_info_entry = wlan_mac_high_find_network_info_BSSID(rx_80211_header->address_3);
675
676                        if (network_info_entry != NULL) {
677                            curr_network_info = network_info_entry->data;
678                            attempt_network_info = wlan_mac_sta_get_attempt_network_info();
679                            if(attempt_network_info && wlan_addr_eq(curr_network_info->bss_config.bssid, attempt_network_info->bss_config.bssid)) wlan_mac_sta_join_return_to_idle();
680                            xil_printf("Join process association failed for BSS %s\n", network_info_entry->data->bss_config.ssid);
681                        }
682
683                        xil_printf("Association failed, reason code %d\n", ((association_response_frame*)mac_payload_ptr_u8)->status_code);
684                    }
685                break;
686
687
688                //---------------------------------------------------------------------
689                case (MAC_FRAME_CTRL1_SUBTYPE_AUTH):
690                    // Authentication Response
691
692                    if( wlan_addr_eq(rx_80211_header->address_1, wlan_mac_addr)) {
693
694                        // Move the packet pointer to after the header
695                        mac_payload_ptr_u8 += sizeof(mac_header_80211);
696
697                        // Check the authentication algorithm
698                        switch(((authentication_frame*)mac_payload_ptr_u8)->auth_algorithm){
699
700                            case AUTH_ALGO_OPEN_SYSTEM:
701                                // Check that this was a successful authentication response
702                                if(((authentication_frame*)mac_payload_ptr_u8)->auth_sequence == AUTH_SEQ_RESP){
703
704                                    if(((authentication_frame*)mac_payload_ptr_u8)->status_code == STATUS_SUCCESS){
705                                        // AP is authenticating us. Update BSS_info.
706                                        network_info_entry = wlan_mac_high_find_network_info_BSSID(rx_80211_header->address_3);
707                                        if(network_info_entry != NULL){
708                                            curr_network_info = network_info_entry->data;
709                                            wlan_mac_sta_successfully_authenticated(curr_network_info->bss_config.bssid);
710                                        }
711                                    }
712
713                                    // Finish the function
714                                    goto mpdu_rx_process_end;
715                                }
716                            break;
717
718                            default:
719                                // STA cannot support authentication request
720                                //     - Check that the response was from a known BSS
721                                network_info_entry = wlan_mac_high_find_network_info_BSSID(rx_80211_header->address_3);
722
723                                if (network_info_entry != NULL) {
724                                    curr_network_info = (network_info_t*)(network_info_entry->data);
725                                    attempt_network_info = wlan_mac_sta_get_attempt_network_info();
726                                    if(attempt_network_info && wlan_addr_eq(curr_network_info->bss_config.bssid, attempt_network_info->bss_config.bssid)) wlan_mac_sta_join_return_to_idle();
727                                    xil_printf("Join process authentication failed for BSS %s\n", network_info_entry->data->bss_config.ssid);
728                                }
729
730                                xil_printf("Authentication failed.  AP uses authentication algorithm %d which is not support by the 802.11 reference design.\n", ((authentication_frame*)mac_payload_ptr_u8)->auth_algorithm);
731                            break;
732                        }
733                    }
734                break;
735
736
737                //---------------------------------------------------------------------
738                case (MAC_FRAME_CTRL1_SUBTYPE_DEAUTH):
739                    // De-authentication
740                    //   - If we are being de-authenticated, then log and update the association state
741                    //   - Start and active scan to find the AP if an SSID is defined
742                    //
743                    if(active_network_info != NULL){
744                        if(wlan_addr_eq(rx_80211_header->address_1, wlan_mac_addr) && is_associated){
745
746                            //
747                            // TODO:  (Optional) Log association state change
748                            //
749
750                            // Stop any on-going join
751                            if (wlan_mac_sta_is_joining()) { wlan_mac_sta_join_return_to_idle(); }
752
753                            // Purge all packets for the AP
754                            wlan_mac_purge_wireless_tx(ap_qid);
755
756                            // Update the hex display to show that we are no longer associated
757                            wlan_platform_high_userio_disp_status(USERIO_DISP_STATUS_MEMBER_LIST_UPDATE, 0);
758
759                            // Remove the association
760                            curr_network_info = active_network_info;
761                            configure_bss(NULL, 0);
762
763                            //
764                            // Note:  This is the place in the code where it would be easy to add new
765                            //     "just de-authenticated" behaviors, such as an auto-re-join protocol.
766                            //     The comments below show a simple "re-join the same AP" protocol using
767                            //     the curr_bss_info variable assigned above.
768                            //
769                            // Try to re-join the AP
770                            // volatile join_parameters_t*  join_parameters = wlan_mac_sta_get_join_parameters();
771                            // bzero((void*)join_parameters->bssid, MAC_ADDR_LEN);
772                            // wlan_mac_high_free(join_parameters->ssid);
773                            // join_parameters->ssid = strndup(curr_bss_info->ssid, SSID_LEN_MAX);
774                            // wlan_mac_sta_join();
775                        }
776                    }
777                break;
778
779                //---------------------------------------------------------------------
780                default:
781                    //This should be left as a verbose print. It occurs often when communicating with mobile devices since they tend to send
782                    //null data frames (type: DATA, subtype: 0x4) for power management reasons.
783                    wlan_printf(PL_VERBOSE, "Received unknown frame control type/subtype %x\n",rx_80211_header->frame_control_1);
784                break;
785            }
786        }
787
788        // Finish the function
789        goto mpdu_rx_process_end;
790    } else {
791        // Process any Bad FCS packets
792        goto mpdu_rx_process_end;
793    }
794
795
796    // Finish any processing for the RX MPDU process
797    mpdu_rx_process_end:
798
799    return return_val;
800}
801
802#if WLAN_SW_CONFIG_ENABLE_LTG
803/*****************************************************************************/
804/**
805 * @brief Callback to handle new Local Traffic Generator event
806 *
807 * This function is called when the LTG scheduler determines a traffic generator should create a new packet. The
808 * behavior of this function depends entirely on the LTG payload parameters.
809 *
810 * The reference implementation defines 3 LTG payload types:
811 *  - LTG_PYLD_TYPE_FIXED: generate 1 fixed-length packet to single destination; callback_arg is pointer to ltg_pyld_fixed struct
812 *  - LTG_PYLD_TYPE_UNIFORM_RAND: generate 1 random-length packet to single destination; callback_arg is pointer to ltg_pyld_uniform_rand_t struct
813 *  - 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 struct
814 *
815 * @param u32 id
816 *  - Unique ID of the previously created LTG
817 * @param void* callback_arg
818 *  - Callback argument provided at LTG creation time; interpretation depends on LTG type
819 * @return None
820 *****************************************************************************/
821void ltg_event(u32 id, void* callback_arg){
822
823    u32 payload_length;
824    u32 min_ltg_payload_length;
825    u8* addr_da;
826    u8* addr_ra;
827    u16 duration;
828    station_info_t* station_info;
829    dl_entry* tx_queue_entry = NULL;
830    tx_80211_queue_buffer_t* tx_queue_buffer = NULL;
831
832    if(((ltg_pyld_hdr_t*)callback_arg)->type == LTG_PYLD_TYPE_CTRL_RESP){
833
834        tx_queue_entry = queue_checkout();
835        if(tx_queue_entry != NULL){
836            tx_queue_buffer = ((tx_80211_queue_buffer_t*)(tx_queue_entry->data));
837
838            addr_ra = ((ltg_pyld_ctrl_resp_t*)callback_arg)->addr_ra;
839            duration = ((ltg_pyld_ctrl_resp_t*)callback_arg)->duration;
840
841            if(((ltg_pyld_ctrl_resp_t*)callback_arg)->subtype == LTG_PYLD_CTRL_RESP_SUBTYPE_CTS){
842                payload_length = wlan_create_cts_frame(tx_queue_buffer->pkt,
843                                                       addr_ra,
844                                                       duration);
845                tx_queue_buffer->flags = TX_80211_QUEUE_BUFFER_FLAGS_TYPE_CTS;
846            } else { //LTG_PYLD_CTRL_RESP_SUBTYPE_ACK
847                payload_length = wlan_create_ack_frame(tx_queue_buffer->pkt,
848                                                       addr_ra);
849                tx_queue_buffer->flags = TX_80211_QUEUE_BUFFER_FLAGS_TYPE_ACK;
850            }
851
852            // Fill in metadata
853            tx_queue_buffer->flags |= TX_80211_QUEUE_BUFFER_FLAGS_BYPASS_RECOVERY;
854            tx_queue_buffer->length = payload_length;
855
856            // With LTG_PYLD_TYPE_CTRL_RESP, we will transmit to the receive address (addr_ra) regardless of
857            // whether that address is an AP that we are associated to. To do that, we need to make sure that
858            // a station_info_t exists for that address
859            tx_queue_buffer->station_info = station_info_create(addr_ra);
860
861            wlan_mac_enqueue_wireless_tx(mgmt_qid, tx_queue_entry);
862
863        }
864    } else {
865        if(active_network_info != NULL){
866            switch(((ltg_pyld_hdr_t*)callback_arg)->type){
867                case LTG_PYLD_TYPE_FIXED:
868                    addr_da = ((ltg_pyld_fixed_t*)callback_arg)->addr_da;
869                    payload_length = ((ltg_pyld_fixed_t*)callback_arg)->length;
870                break;
871                case LTG_PYLD_TYPE_UNIFORM_RAND:
872                    addr_da = ((ltg_pyld_uniform_rand_t*)callback_arg)->addr_da;
873                    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;
874                break;
875                default:
876                    xil_printf("ERROR ltg_event: Unknown LTG Payload Type! (%d)\n", ((ltg_pyld_hdr_t*)callback_arg)->type);
877                    return;
878                break;
879            }
880
881            station_info = (station_info_t*)((active_network_info->members.first)->data);
882
883            // Send a Data packet to AP
884            if(queue_length(ap_qid) < max_queue_size){
885                // Checkout 1 element from the queue;
886                tx_queue_entry = queue_checkout();
887                if(tx_queue_entry != NULL){
888                    // Create LTG packet
889                    tx_queue_buffer = ((tx_80211_queue_buffer_t*)(tx_queue_entry->data));
890
891
892                    min_ltg_payload_length = wlan_create_ltg_frame(tx_queue_buffer->pkt,
893                                                                   station_info->addr,
894                                                                   wlan_mac_addr,
895                                                                   addr_da,
896                                                                   MAC_FRAME_CTRL2_FLAG_TO_DS,
897                                                                   id);
898
899                    payload_length = WLAN_MAX(payload_length+sizeof(mac_header_80211)+WLAN_PHY_FCS_NBYTES, min_ltg_payload_length);
900
901
902
903                    // Fill in metadata
904                    tx_queue_buffer->flags = TX_80211_QUEUE_BUFFER_FLAGS_FILL_DURATION | TX_80211_QUEUE_BUFFER_FLAGS_FILL_UNIQ_SEQ;
905                    tx_queue_buffer->length = payload_length;
906                    tx_queue_buffer->seg0_len = min_ltg_payload_length;
907                    tx_queue_buffer->seg1_len = 0;
908                    tx_queue_buffer->seg1_offset = 0;
909                    tx_queue_buffer->station_info = station_info;
910
911                    // Submit the new packet to the appropriate queue
912                    wlan_mac_enqueue_wireless_tx(ap_qid, tx_queue_entry);
913                }
914            }
915        }
916    }
917}
918#endif //WLAN_SW_CONFIG_ENABLE_LTG
919
920/*****************************************************************************/
921/**
922 * @brief Disassociate the STA from the associated AP
923 *
924 * This function will disassociate the STA from the AP if it is associated.  Otherwise,
925 * it will do nothing.  It also logs any association state change
926 *
927 * @param  None
928 * @return int
929 *  -  0 if successful
930 *  - -1 if unsuccessful
931 *
932 *  @note This function uses global variables:  association_state, association_table
933 *****************************************************************************/
934int sta_disassociate( void ) {
935    int status = 0;
936    station_info_entry_t* ap_station_info_entry;
937    dl_entry* tx_queue_entry;
938    tx_80211_queue_buffer_t* tx_queue_buffer;
939    u32 tx_length;
940
941    // If the STA is currently associated, remove the association; otherwise do nothing
942    if(active_network_info != NULL){
943
944        // Get the AP station info
945        ap_station_info_entry = (station_info_entry_t*)(active_network_info->members.first);
946
947        //
948        // TODO:  (Optional) Log association state change
949        //
950
951        // ---------------------------------------------------------------
952        // Send de-authentication message to tell AP that the STA is leaving
953
954        // Jump to BSS channel before sending.  No need to change back.
955        wlan_mac_high_set_radio_channel(wlan_mac_high_bss_channel_spec_to_radio_chan(active_network_info->bss_config.chan_spec));
956
957        // Send disassociation packet
958        tx_queue_entry = queue_checkout();
959
960        if(tx_queue_entry != NULL){
961            tx_queue_buffer = (tx_80211_queue_buffer_t*)(tx_queue_entry->data);
962
963            tx_length = wlan_create_disassoc_frame(tx_queue_buffer->pkt,
964                                                   ap_station_info_entry->addr,
965                                                   wlan_mac_addr,
966                                                   wlan_mac_addr,
967                                                   DISASSOC_REASON_STA_IS_LEAVING);
968
969            // Fill in metadata
970            tx_queue_buffer->flags = TX_80211_QUEUE_BUFFER_FLAGS_FILL_DURATION;
971            tx_queue_buffer->length = tx_length;
972            tx_queue_buffer->seg0_len = tx_length;
973            tx_queue_buffer->seg1_len = 0;
974            tx_queue_buffer->seg1_offset = 0;
975            tx_queue_buffer->station_info = ap_station_info_entry->data;
976
977            // Put the packet in the queue
978            wlan_mac_enqueue_wireless_tx(mgmt_qid, tx_queue_entry);
979
980            // Purge any data for the AP
981            wlan_mac_purge_wireless_tx(ap_qid);
982        }
983
984        // Set BSS to NULL
985        configure_bss(NULL, 0);
986    }
987
988    return status;
989}
990
991/*****************************************************************************/
992/**
993 *
994 *****************************************************************************/
995u32 configure_bss(bss_config_t* bss_config, u32 update_mask){
996    u32 return_status = 0;
997    u8 send_channel_switch_to_low = 0;
998    u8 send_beacon_config_to_low = 0;
999
1000    network_info_t* local_network_info;
1001    interrupt_state_t curr_interrupt_state;
1002    station_info_t* curr_station_info;
1003    station_info_entry_t* curr_station_info_entry;
1004    station_info_t* ap_station_info = NULL;
1005
1006    //---------------------------------------------------------
1007    // 1. Check for any invalid inputs or combination of inputs
1008    //      First verify the requested update to the BSS configuration before
1009    //      modifying anything. This will prevent a partial update of BSS
1010    //      configuration with valid parameters before discovering an invalid
1011    //      parameter.
1012
1013    if (bss_config != NULL) {
1014        if (update_mask & BSS_FIELD_MASK_BSSID) {
1015            if (wlan_addr_eq(bss_config->bssid, zero_addr) == 0) {
1016                if ((active_network_info != NULL) && wlan_addr_eq(bss_config->bssid, active_network_info->bss_config.bssid)) {
1017                    // The caller of this function claimed that it was updating the BSSID,
1018                    // but the new BSSID matches the one already specified in active_bss_info.
1019                    // Complete the rest of this function as if that bit in the update mask
1020                    // were not set
1021                    update_mask &= ~BSS_FIELD_MASK_BSSID;
1022                } else {
1023                    // Changing the BSSID, perform necessary argument checks
1024                    if ((bss_config->bssid[0] & MAC_ADDR_MSB_MASK_LOCAL) == 1) {
1025                        // In the STA implementation, the BSSID provided must not
1026                        // be locally generated.
1027                        return_status |= BSS_CONFIG_FAILURE_BSSID_INVALID;
1028                    }
1029                    if (((update_mask & BSS_FIELD_MASK_SSID) == 0) ||
1030                        ((update_mask & BSS_FIELD_MASK_CHAN) == 0)) {
1031                        return_status |= BSS_CONFIG_FAILURE_BSSID_INSUFFICIENT_ARGUMENTS;
1032                    }
1033                }
1034            }
1035        } else {
1036            if (active_network_info == NULL) {
1037                // Cannot update BSS without specifying BSSID
1038                return_status |= BSS_CONFIG_FAILURE_BSSID_INSUFFICIENT_ARGUMENTS;
1039            }
1040        }
1041        if (update_mask & BSS_FIELD_MASK_CHAN) {
1042            if (wlan_verify_channel(
1043                    wlan_mac_high_bss_channel_spec_to_radio_chan(bss_config->chan_spec)) != WLAN_SUCCESS) {
1044                return_status |= BSS_CONFIG_FAILURE_CHANNEL_INVALID;
1045            }
1046        }
1047        if (update_mask & BSS_FIELD_MASK_BEACON_INTERVAL) {
1048            // There is no error condition for setting the beacon interval
1049            // at the STA since a STA is incapable of sending beacons
1050        }
1051        if (update_mask & BSS_FIELD_MASK_HT_CAPABLE) {
1052            if (bss_config->ht_capable > 1) {
1053                return_status |= BSS_CONFIG_FAILURE_HT_CAPABLE_INVALID;
1054            }
1055        }
1056        if (update_mask & BSS_FIELD_MASK_DTIM_PERIOD) {
1057            // For a STA, there is no invalid selection of dtim_period so we never return
1058            // BSS_CONFIG_FAILURE_DTIM_PERIOD_INVALID. An AP that does not contain a TIM
1059            // MGMT tag in its beacon will have a value of 0 in the dtim_period field of
1060            // the corresponding network_info_t.
1061        }
1062    }
1063
1064    if (return_status == 0) {
1065        //---------------------------------------------------------
1066        // 2. Apply BSS configuration changes
1067        //      Now that the provided bss_config_t struct is valid, apply the changes.
1068
1069        // Disable interrupts around these modifications to prevent state
1070        // changing out from underneath this context while the new BSS
1071        // configuration parameters are only partially updated.
1072        curr_interrupt_state = wlan_platform_intc_stop();
1073
1074        if ((bss_config == NULL) || (update_mask & BSS_FIELD_MASK_BSSID)) {
1075            // Adopting a new BSSID. This could mean either
1076            //    1) Shutting the BSS down
1077            // or 2) Shutting the BSS down and then starting a new BSS.
1078            //
1079            // In either case, first remove any station_info structs
1080            // that are members of the current active_bss_info and return to
1081            // a NULL active_bss_info state.
1082            //
1083            // This will not result in any OTA transmissions to the stations.
1084
1085            if (active_network_info != NULL) {
1086
1087                if ((bss_config == NULL) ||
1088                        ((update_mask & BSS_FIELD_MASK_BSSID) && wlan_addr_eq(bss_config->bssid, zero_addr)) ) {
1089                    xil_printf("Leaving BSS\n");
1090                }
1091
1092                curr_station_info_entry = (station_info_entry_t*)(active_network_info->members.first);
1093                curr_station_info = curr_station_info_entry->data;
1094
1095                // Purge any data for the AP
1096                wlan_mac_purge_wireless_tx(ap_qid);
1097
1098                // Set QID to invalid value (framework will close the queue during network_info_remove_member
1099                ap_qid = -1;
1100
1101                // Lower the KEEP flag
1102                curr_station_info->flags &= ~STATION_INFO_FLAG_KEEP;
1103
1104                // Remove the association
1105                network_info_remove_member( active_network_info, curr_station_info_entry->addr );
1106
1107                // Update the hex display to show STA is not currently associated
1108                wlan_platform_high_userio_disp_status(USERIO_DISP_STATUS_MEMBER_LIST_UPDATE, 0);
1109
1110                // Inform the MAC High Framework to no longer will keep this BSS Info. This will
1111                // allow it to be overwritten in the future to make space for new BSS Infos.
1112                active_network_info->flags &= ~NETWORK_FLAGS_KEEP;
1113
1114                // Set "active_network_info" to NULL
1115                //     - All functions must be able to handle active_bss_info = NULL
1116                active_network_info = NULL;
1117
1118                // Disable beacon processing immediately
1119                bzero(gl_beacon_txrx_config.bssid_match, MAC_ADDR_LEN);
1120                wlan_mac_high_config_txrx_beacon(&gl_beacon_txrx_config);
1121
1122                // Set hex display to "No BSS"
1123                wlan_platform_high_userio_disp_status(USERIO_DISP_STATUS_MEMBER_LIST_UPDATE, 0xFF);
1124            }
1125
1126            // Pause the data queue, if un-paused
1127            //     Since interrupts are disabled, this does not need to be done before the purge_queue()
1128            if (pause_data_queue == 0) {
1129                pause_data_queue = 1;
1130            }
1131
1132            // (bss_config_update == NULL) is one way to remove the BSS state of the node. This operation
1133            // was executed just above.  Rather that continuing to check non-NULLness of bss_config
1134            // throughout the rest of this function, just re-enable interrupts and return early.
1135
1136            if (bss_config == NULL) {
1137                wlan_platform_intc_set_state(curr_interrupt_state);
1138                return return_status;
1139            }
1140
1141            // active_bss_info is guaranteed to be NULL at this point in the code
1142            // bss_config is guaranteed to be non-NULL at this point in the code
1143
1144            // Update BSS
1145            //     - BSSID must not be zero_addr (reserved address)
1146            if (wlan_addr_eq(bss_config->bssid, zero_addr) == 0) {
1147                // Stop the join state machine if it is running
1148                if (wlan_mac_sta_is_joining()) {
1149                    wlan_mac_sta_join_return_to_idle();
1150                }
1151
1152                // Stop the scan state machine if it is running
1153                if (wlan_mac_scan_is_scanning()) {
1154                    wlan_mac_scan_stop();
1155                }
1156
1157                // Create a new bss_info or overwrite an existing one with matching BSSID.
1158                //     Note:  The wildcard SSID and 0-valued channel arguments are temporary. Because
1159                //         of the error checking at the top of this function, the bss_config will
1160                //         contain a valid SSID as well as channel. These fields will be updated
1161                //         in step 3).
1162                local_network_info = wlan_mac_high_create_network_info(bss_config->bssid, "", 0);
1163
1164                if (local_network_info != NULL) {
1165                    local_network_info->flags |= NETWORK_FLAGS_KEEP;
1166
1167                    local_network_info->capabilities = (BSS_CAPABILITIES_ESS);
1168
1169                    active_network_info = local_network_info;
1170
1171                    // Add AP to association table
1172                    //     - Set ht_capable argument to the HT_CAPABLE capability of the BSS.  Given that the STA does not know
1173                    //       the HT capabilities of the AP, it is reasonable to assume that they are the same as the BSS.
1174                    //
1175                    ap_station_info = network_info_add_member(active_network_info, active_network_info->bss_config.bssid, max_queue_size);
1176
1177                    if (ap_station_info != NULL) {
1178
1179                        if(active_network_info->bss_config.ht_capable){
1180                            ap_station_info->capabilities |= STATION_INFO_CAPABILITIES_HT_CAPABLE;
1181                        } else {
1182                            ap_station_info->capabilities &= ~STATION_INFO_CAPABILITIES_HT_CAPABLE;
1183                        }
1184
1185                        ap_station_info->flags |= STATION_INFO_FLAG_KEEP;
1186
1187                        ap_qid = ap_station_info->QID;
1188
1189                        time_hr_min_sec_t time_hr_min_sec = wlan_mac_time_to_hr_min_sec(get_system_time_usec());
1190                        xil_printf("*%dh:%02dm:%02ds* Now associated with AP %02x:%02x:%02x:%02x:%02x:%02x\n",
1191                                time_hr_min_sec.hr, time_hr_min_sec.min, time_hr_min_sec.sec,
1192                                active_network_info->bss_config.bssid[0], active_network_info->bss_config.bssid[1], active_network_info->bss_config.bssid[2],
1193                                active_network_info->bss_config.bssid[3], active_network_info->bss_config.bssid[4], active_network_info->bss_config.bssid[5]);
1194
1195                        //
1196                        // TODO:  (Optional) Log association state change
1197                        //
1198                    }
1199                }
1200
1201                // Set hex display
1202                wlan_platform_high_userio_disp_status(USERIO_DISP_STATUS_MEMBER_LIST_UPDATE, my_aid);
1203            }
1204        }
1205
1206        //---------------------------------------------------------
1207        // 3. Clean up
1208        //      Now that active_bss_info has been updated, CPU_HIGH can communicate
1209        //      the changes to CPU_LOW so that the node is tuned to the correct channel,
1210        //      send beacons at the correct interval, and update the beacon
1211        //      template packet buffer.
1212        if (active_network_info != NULL) {
1213
1214            if (update_mask & BSS_FIELD_MASK_CHAN) {
1215                active_network_info->bss_config.chan_spec = bss_config->chan_spec;
1216                send_channel_switch_to_low = 1;
1217            }
1218            if (update_mask & BSS_FIELD_MASK_SSID) {
1219                strncpy(active_network_info->bss_config.ssid, bss_config->ssid, SSID_LEN_MAX);
1220            }
1221            if (update_mask & BSS_FIELD_MASK_BEACON_INTERVAL) {
1222                active_network_info->bss_config.beacon_interval = bss_config->beacon_interval;
1223                send_beacon_config_to_low = 1;
1224            }
1225            if (update_mask & BSS_FIELD_MASK_HT_CAPABLE) {
1226                active_network_info->bss_config.ht_capable = bss_config->ht_capable;
1227            }
1228
1229            // Update the channel
1230            if (send_channel_switch_to_low) {
1231                wlan_mac_high_set_radio_channel(
1232                        wlan_mac_high_bss_channel_spec_to_radio_chan(active_network_info->bss_config.chan_spec));
1233            }
1234
1235            // Update Beacon configuration
1236            if (send_beacon_config_to_low) {
1237                memcpy(gl_beacon_txrx_config.bssid_match, active_network_info->bss_config.bssid, MAC_ADDR_LEN);
1238
1239                gl_beacon_txrx_config.beacon_interval_tu = active_network_info->bss_config.beacon_interval;        // CPU_LOW does not need this parameter for the STA project
1240                gl_beacon_txrx_config.beacon_template_pkt_buf = TX_PKT_BUF_BEACON;              // CPU_LOW does not need this parameter for the STA project
1241
1242                wlan_mac_high_config_txrx_beacon(&gl_beacon_txrx_config);
1243            }
1244
1245            // Unpause the queue, if paused
1246            if (pause_data_queue) {
1247                pause_data_queue = 0;
1248            }
1249
1250            // Update the hex diplay with the current AID
1251            wlan_platform_high_userio_disp_status(USERIO_DISP_STATUS_MEMBER_LIST_UPDATE, my_aid);
1252
1253            // Print new BSS information
1254            xil_printf("BSS Details: \n");
1255            xil_printf("  BSSID           : %02x-%02x-%02x-%02x-%02x-%02x\n",active_network_info->bss_config.bssid[0],active_network_info->bss_config.bssid[1],
1256                                                                             active_network_info->bss_config.bssid[2],active_network_info->bss_config.bssid[3],
1257                                                                             active_network_info->bss_config.bssid[4],active_network_info->bss_config.bssid[5]);
1258            xil_printf("   SSID           : %s\n", active_network_info->bss_config.ssid);
1259            xil_printf("   Channel        : %d\n", wlan_mac_high_bss_channel_spec_to_radio_chan(active_network_info->bss_config.chan_spec));
1260            if (active_network_info->bss_config.beacon_interval == BEACON_INTERVAL_NO_BEACON_TX) {
1261                xil_printf("   Beacon Interval: No Beacon Tx\n");
1262            } else if (active_network_info->bss_config.beacon_interval == BEACON_INTERVAL_UNKNOWN) {
1263                xil_printf("   Beacon Interval: Unknown\n");
1264            } else {
1265                xil_printf("   Beacon Interval: %d TU (%d us)\n", active_network_info->bss_config.beacon_interval, active_network_info->bss_config.beacon_interval*1024);
1266            }
1267        }
1268
1269        // Restore interrupts after all BSS changes
1270        wlan_platform_intc_set_state(curr_interrupt_state);
1271    }
1272
1273    return return_status;
1274}
1275
1276
1277
1278/*****************************************************************************/
1279/**
1280 * @brief Callback to handle beacon MAC time update mode
1281 *
1282 * @param  u32 enable        - Enable / Disable MAC time update from beacons
1283 * @return None
1284 *
1285 *****************************************************************************/
1286void sta_set_beacon_ts_update_mode(u32 enable){
1287    if (enable) {
1288        gl_beacon_txrx_config.ts_update_mode = ALWAYS_UPDATE;
1289    } else {
1290        gl_beacon_txrx_config.ts_update_mode = NEVER_UPDATE;
1291    }
1292
1293    // Push beacon configuration to CPU_LOW
1294    wlan_mac_high_config_txrx_beacon(&gl_beacon_txrx_config);
1295}
1296
1297/*****************************************************************************/
1298/**
1299 * @brief Accessor methods for global variables
1300 *
1301 * These functions will return pointers to global variables
1302 *
1303 * @param  None
1304 * @return None
1305 *****************************************************************************/
1306dl_list* get_network_member_list(){
1307    if(active_network_info != NULL){
1308        return &(active_network_info->members);
1309    } else {
1310        return NULL;
1311    }
1312}
1313
1314network_info_t* active_network_info_getter(){ return active_network_info; }
1315
1316
1317
1318
1319#if WLAN_SW_CONFIG_ENABLE_WLAN_EXP
1320
1321// ****************************************************************************
1322// Define MAC Specific User Commands
1323//
1324// NOTE:  All User Command IDs (CMDID_*) must be a 24 bit unique number
1325//
1326
1327//-----------------------------------------------
1328// MAC Specific User Commands
1329//
1330// #define CMDID_USER_<COMMAND_NAME>                       0x100000
1331
1332
1333//-----------------------------------------------
1334// MAC Specific User Command Parameters
1335//
1336// #define CMD_PARAM_USER_<PARAMETER_NAME>                 0x00000000
1337
1338
1339
1340/*****************************************************************************/
1341/**
1342 * Process User Commands
1343 *
1344 * This function is part of the WLAN Exp framework and will process the framework-
1345 * level user commands.  This function intentionally does not implement any user
1346 * commands and it is left to the user to implement any needed functionality.   By
1347 * default, any commands not processed in this function will print an error to the
1348 * UART.
1349 *
1350 * @return  int              - Status of the command:
1351 *                                 NO_RESP_SENT - No response has been sent
1352 *                                 RESP_SENT    - A response has been sent
1353 *
1354 * @note    See on-line documentation for more information:
1355 *          https://warpproject.org/trac/wiki/802.11/wlan_exp/Extending
1356 *
1357 *****************************************************************************/
1358int wlan_exp_process_user_cmd(cmd_resp_hdr_t* cmd_hdr, eth_tx_queue_buffer_t* eth_tx_queue_buffer) {
1359
1360    //
1361    // IMPORTANT ENDIAN NOTES:
1362    //     - command
1363    //         - header - Already endian swapped by the framework (safe to access directly)
1364    //         - args   - Must be endian swapped as necessary by code (framework does not know the contents of the command)
1365    //     - response
1366    //         - header - Will be endian swapped by the framework (safe to write directly)
1367    //         - args   - Must be endian swapped as necessary by code (framework does not know the contents of the response)
1368    //
1369
1370    // Standard variables
1371    //
1372    // Used for accessing command arguments and constructing the command response header/payload
1373    //
1374    // NOTE:  Some of the standard variables below have been commented out.  This was to remove
1375    //     compiler warnings for "unused variables" since the default implementation is empty.  As
1376    //     you add commands, you should un-comment the standard variables.
1377    //
1378    u32 resp_sent = NO_RESP_SENT;
1379    u32 cmd_id = CMD_TO_CMDID(cmd_hdr->cmd);
1380#if 0
1381    // Segment 0 length includes a fully formed command response header
1382    //  because one was created with default values suitable for a responseless
1383    //  acknowledgment.
1384    cmd_resp_hdr_t* resp_hdr = (cmd_resp_hdr_t*)(eth_tx_queue_buffer->seg0
1385                                                 + eth_tx_queue_buffer->seg0_len
1386                                                 - sizeof(cmd_resp_hdr_t));
1387
1388    u32* cmd_args_32 = (u32*)((u8*)cmd_hdr + sizeof(cmd_resp_hdr_t));
1389#endif
1390
1391    switch(cmd_id){
1392
1393//-----------------------------------------------------------------------------
1394// MAC Specific User Commands
1395//-----------------------------------------------------------------------------
1396
1397        // Template framework for a Command
1398        //
1399        // NOTE:  The WLAN Exp framework assumes that the Over-the-Wire format of the data is
1400        //     big endian.  However, the node processes data using little endian.  Therefore,
1401        //     any data received from the host must be properly endian-swapped and similarly,
1402        //     any data sent to the host must be properly endian-swapped.  The built-in Xilinx
1403        //     functions:  Xil_Ntohl() (Network to Host) and Xil_Htonl() (Host to Network) are
1404        //     used for this.
1405        //
1406#if 0
1407        //---------------------------------------------------------------------
1408        case CMDID_USER_<COMMAND_NAME>: {
1409            // Command Description
1410            //
1411            // Message format:
1412            //     cmd_args_32[0:N]    Document command arguments from the host
1413            //
1414            // Response format:
1415            //     resp_args_32[0:M]   Document response arguments from the node
1416            //
1417            // NOTE:  Variables are declared above.
1418            // NOTE:  Please take care of the endianness of the arguments (see comment above)
1419            //
1420
1421            // Variables for template command
1422            int status;
1423            u32 arg_0;
1424            interrupt_state_t curr_interrupt_state;
1425
1426            // Initialize variables
1427            status = CMD_PARAM_SUCCESS;
1428            arg_0 = Xil_Ntohl(cmd_args_32[0]);              // Swap endianness of command argument
1429
1430            // Do something with argument(s)
1431            xil_printf("Command argument 0: 0x%08x\n", arg_0);
1432
1433            // If necessary, disable interrupts before processing the command
1434            //  Interrupts must be disabled if the command implementation relies on any state that might
1435            //  change during an interrupt service routine. See the user guide for more details
1436            //  https://warpproject.org/trac/wiki/802.11/wlan_exp/Extending
1437            curr_interrupt_state = wlan_platform_intc_stop();
1438
1439            // Process command arguments and generate any response payload
1440            //     NOTE:  If interrupts were disabled above, take care to avoid any long-running code in this
1441            //         block (i.e. avoid xil_printf()). When interrupts are disabled, CPU High is unable to
1442            //         respond to CPU Low (ie CPU High will not send / receive packets) and execute scheduled
1443            //         tasks, such as LTGs.
1444
1445            // Re-enable interrupts before returning (only do this if wlan_platform_intc_stop() is called above)
1446            wlan_platform_intc_set_state(curr_interrupt_state);
1447
1448            // Send response
1449            //   NOTE:  It is good practice to send a status as the first argument of the response.
1450            //       This way it is easy to determine if the other data in the response is valid.
1451            //       Predefined status values are:  CMD_PARAM_SUCCESS, CMD_PARAM_ERROR
1452            //
1453            wlan_exp_add_u32_resp_arg(eth_tx_queue_buffer, resp_hdr, status);
1454        }
1455        break;
1456#endif
1457
1458
1459        //---------------------------------------------------------------------
1460        default: {
1461            wlan_exp_printf(WLAN_EXP_PRINT_ERROR, print_type_node, "Unknown STA user command: 0x%x\n", cmd_id);
1462        }
1463        break;
1464    }
1465
1466    return resp_sent;
1467}
1468
1469
1470#endif
1471
Note: See TracBrowser for help on using the repository browser.