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

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

1.8.0 release wlan-mac-se

File size: 23.7 KB
Line 
1/** @file wlan_mac_sta_join.c
2 *  @brief Join FSM
3 *
4 *  This contains code for the STA join process.
5 *
6 *  @copyright Copyright 2014-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 *   The join process allows the STA to join a given BSS.  There are two major
15 * components to the join process:  SEARCHING and ATTEMPTING.  If all the necessary
16 * information is known about the BSS, then the join process only has to perform
17 * the "ATTEMPTING" process.  However, if only a SSID is known, then the join
18 * process must use the scan infrastructure in wlan_mac_scan.c/h to perform
19 * the "SEARCHING" process to get more information about the BSS so that it can
20 * proceed to the "ATTEMPTING" process.
21 *
22 *   In order to make the join process robust to any wireless environment (ie
23 * robust to packet loss), the scheduler is used to "poll" functions as part
24 * of the "SEARCHING" and "ATTEMPTING" process.  This will ensure that even
25 * with packet loss, the join process will "re-attempt" its current step.
26 *
27 */
28
29/***************************** Include Files *********************************/
30#include "wlan_mac_high_sw_config.h"
31
32// Xilinx SDK includes
33#include "xparameters.h"
34#include "xil_types.h"
35#include "stdio.h"
36#include "stdlib.h"
37#include "string.h"
38
39// WLAN includes
40#include "wlan_mac_802_11_defs.h"
41#include "wlan_mac_high.h"
42#include "wlan_mac_packet_types.h"
43#include "wlan_mac_scan.h"
44#include "wlan_mac_schedule.h"
45#include "wlan_mac_dl_list.h"
46#include "wlan_mac_network_info.h"
47#include "wlan_mac_sta_join.h"
48#include "wlan_mac_sta.h"
49#include "wlan_mac_common.h"
50#include "wlan_mac_queue.h"
51#include "wlan_mac_pkt_buf_util.h"
52#include "wlan_mac_station_info.h"
53#include "wlan_platform_high.h"
54
55
56/*************************** Constant Definitions ****************************/
57
58
59/*********************** Global Variable Definitions *************************/
60
61extern u8 pause_data_queue;
62extern tx_params_t default_unicast_mgmt_tx_params;
63extern u8 my_aid;
64extern network_info_t* active_network_info;
65extern u8 wlan_mac_addr[MAC_ADDR_LEN];
66extern u16 mgmt_qid;
67
68/*************************** Variable Definitions ****************************/
69
70// Join FSM states
71typedef enum join_state_t{
72    IDLE,
73    SEARCHING,
74    ATTEMPTING
75} join_state_t;
76
77typedef enum authentication_state_t{
78    UNAUTHENTICATED,
79    AUTHENTICATED,
80    ASSOCIATED
81} authentication_state_t;
82
83// Global join parameters
84//     This variable needs to be treated as volatile since it is expected to be
85//     modified by other contexts after a call to wlan_mac_join_get_parameters
86volatile join_parameters_t gl_join_parameters;
87
88
89// Scan state variables
90static join_state_t join_state;
91static authentication_state_t authentication_state;
92static network_info_t* attempt_network_info;
93char* scan_ssid_save;
94
95static u32 search_sched_id;
96static u32 attempt_sched_id;
97
98// Callback Function
99//     Used to perform any tasks after a successful join
100static function_ptr_t join_success_callback;
101
102
103/*************************** Functions Prototypes ****************************/
104
105void start_join_attempt();
106
107void wlan_mac_sta_join_bss_search_poll(u32 schedule_id);
108
109void transmit_join_auth_req();
110void transmit_join_assoc_req();
111
112/******************************** Functions **********************************/
113
114
115/*****************************************************************************/
116/**
117 * Initialize the join state
118 *
119 * This function will initialize the join state machine an set the join
120 * parameters to the default values.
121 *
122 * @return  int              - WLAN_SUCCESS (function cannot fail)
123 *
124 *****************************************************************************/
125int wlan_mac_sta_join_init(){
126
127    // Initialize join success callback
128    join_success_callback = (function_ptr_t)wlan_null_callback;
129
130    // Set default join parameters
131    bzero((u8*)gl_join_parameters.bssid, MAC_ADDR_LEN);
132    gl_join_parameters.ssid = NULL;
133    gl_join_parameters.channel = 0;
134
135    // Set global join state variables
136    join_state = IDLE;
137    authentication_state = UNAUTHENTICATED;
138
139    attempt_network_info = NULL;
140    scan_ssid_save = NULL;
141
142    search_sched_id = SCHEDULE_ID_RESERVED_MAX;
143    attempt_sched_id = SCHEDULE_ID_RESERVED_MAX;
144
145    return WLAN_SUCCESS;
146}
147
148
149
150/*****************************************************************************/
151/**
152 * Set callbacks
153 *
154 *****************************************************************************/
155void wlan_mac_sta_set_join_success_callback(function_ptr_t callback){
156    join_success_callback = callback;
157}
158
159
160
161/*****************************************************************************/
162/**
163 * Get global join parameters structure
164 *
165 * This is in lieu of getter / setter methods for all of the join parameters.
166 *
167 * @return  volatile join_parameters_t*     - Pointer to join parameters
168 *
169 *****************************************************************************/
170volatile join_parameters_t* wlan_mac_sta_get_join_parameters(){
171    return &gl_join_parameters;
172}
173
174/*****************************************************************************/
175/**
176 * Get global bss_info pointer that STA is attempting to join
177 *
178 * @return  volatile network_info_t*     - Pointer to network_info
179 *
180 *****************************************************************************/
181volatile network_info_t* wlan_mac_sta_get_attempt_network_info(){
182    if(wlan_mac_sta_is_joining()){
183        return attempt_network_info;
184    } else {
185        return NULL;
186    }
187}
188
189
190/*****************************************************************************/
191/**
192 * Is the node joining?
193 *
194 * @return  u32              - Is Joining?
195 *                                 1 - Currently joining
196 *                                 0 - Not joining
197 *
198 *****************************************************************************/
199u32 wlan_mac_sta_is_joining(){
200    if (join_state == IDLE) {
201        return 0;
202    } else {
203        return 1;
204    }
205}
206
207void wlan_mac_sta_successfully_authenticated(u8* bssid){
208    if(attempt_network_info && wlan_addr_eq(bssid, attempt_network_info->bss_config.bssid)){
209        if(authentication_state == UNAUTHENTICATED){
210            authentication_state = AUTHENTICATED;
211            wlan_mac_sta_join_bss_attempt_poll(0);
212        }
213    }
214}
215
216void wlan_mac_sta_successfully_associated(u8* bssid, u16 AID){
217    if(attempt_network_info && wlan_addr_eq(bssid, attempt_network_info->bss_config.bssid)){
218        if(authentication_state == AUTHENTICATED){
219            authentication_state = ASSOCIATED;
220            wlan_mac_sta_join_bss_attempt_poll(AID);
221        }
222    }
223}
224
225/*****************************************************************************/
226/**
227 * @brief Join an AP
228 *
229 * This function begins the process to join an AP with the parameters
230 * present in the global gl_join_parameters.  Depending on the information
231 * present in the gl_join_parameters, the STA may perform both the
232 * "SEARCHING" and "ATTEMPTING" process or just the "ATTEMPTING" process.
233 *
234 * A value of NULL for the SSID element in join_parameters_t indicates
235 * that the function should halt any ongoing attempts to join an AP.
236 *
237 * A value of {0,0,0,0,0,0} for the BSSID or a value of 0 for the channel,
238 * will result in the join process first "SEARCHING" for the BSS.
239 *
240 *****************************************************************************/
241void wlan_mac_sta_join(){
242    volatile scan_parameters_t* scan_parameters;
243
244    // If the SSID is NULL, then we need to halt any joins
245    if (gl_join_parameters.ssid == NULL) {
246        wlan_mac_sta_join_return_to_idle();
247    } else {
248
249        // Check if the join state machine is already running:
250        //     - Return the join state machine to IDLE
251        //     - Re-enter function
252        //
253        // Currently, the join state machine is out of sync with the gl_join_parameters
254        // since they have already been changed by a user.
255        //
256        if (wlan_mac_sta_is_joining()) {
257            wlan_mac_sta_join_return_to_idle();
258            wlan_mac_sta_join();
259            return;
260        }
261
262        // Check if the BSSID or Channel are reserved values
263        if (wlan_addr_eq(gl_join_parameters.bssid, zero_addr) || (gl_join_parameters.channel == 0)) {
264            // Start an active scan and find the AP
265            join_state = SEARCHING;
266
267            // Get the current scan parameters
268            scan_parameters = wlan_mac_scan_get_parameters();
269
270            // Set the scan SSID
271            //     - Save the current scan parameters SSID so to revert after the join has finished
272            //     - strndup automatically mallocs memory for strings, but previous strings need to
273            //       be freed manually
274            //
275            scan_ssid_save = strndup(scan_parameters->ssid, SSID_LEN_MAX);
276            wlan_mac_high_free(scan_parameters->ssid);
277            scan_parameters->ssid = strndup(gl_join_parameters.ssid, SSID_LEN_MAX);
278
279            // Start the scan
280            wlan_mac_scan_start();
281
282            // Schedule wlan_mac_sta_bss_search_poll() to determine when the BSS is found
283            //     - Timing for this poll can be adjusted using defines in wlan_mac_sta_join.h
284            //
285            search_sched_id = wlan_mac_schedule_add_event(SCHEDULE_ID_FINE, BSS_SEARCH_POLL_INTERVAL_USEC, SCHEDULE_REPEAT_FOREVER, (void*)wlan_mac_sta_join_bss_search_poll);
286
287        } else {
288            // Create a network info from the current join parameters
289            attempt_network_info = wlan_mac_high_create_network_info((u8*)gl_join_parameters.bssid,
290                                                             (char*)gl_join_parameters.ssid,
291                                                             (u8)gl_join_parameters.channel);
292
293            // Stop any on-going scans
294            wlan_mac_scan_stop();
295
296            // Start the "ATTEMPTING" process
297            start_join_attempt();
298        }
299    }
300}
301
302
303
304/*****************************************************************************/
305/**
306 * @brief Start the "ATTEMPTING" part of the join process
307 *
308 * This function begins the "ATTEMPTING" part of the join process.
309 *
310 *****************************************************************************/
311void start_join_attempt() {
312
313    // Check the network info that STA is attempting to join
314    if (attempt_network_info == NULL) {
315        xil_printf("Join FSM Error: attempting to join BSS without setting attempt_bss_info\n");
316        return;
317    }
318
319    // Set the join state
320    join_state = ATTEMPTING;
321
322    // Check the current association
323    if (active_network_info != NULL) {
324        if (wlan_addr_eq(gl_join_parameters.bssid, active_network_info->bss_config.bssid)) {
325            // Already associated with this BSS
326            wlan_mac_sta_join_return_to_idle();
327            return;
328        } else {
329            // Currently associated with a different BSS.  Disassociate
330            // and continue to the join the new AP.
331            sta_disassociate();
332        }
333    }
334
335    // Pause the STA data queue since this will change association state
336    //     - The STA data queue will be un-paused during the call to
337    //       sta_set_association_state() if the join was successful
338    //
339    pause_data_queue = 1;
340
341    // Move the AP's channel
342    wlan_mac_high_set_radio_channel(wlan_mac_high_bss_channel_spec_to_radio_chan(attempt_network_info->bss_config.chan_spec));
343
344    // Attempt to join the BSS
345    wlan_mac_sta_join_bss_attempt_poll(0);
346
347    // Schedule the "Attempt to join the BSS" in case a packet is lost
348    //     - Timing for this poll can be adjusted using defines in wlan_mac_sta_join.h
349    //
350    attempt_sched_id = wlan_mac_schedule_add_event(SCHEDULE_ID_FINE, BSS_ATTEMPT_POLL_INTERVAL_USEC, SCHEDULE_REPEAT_FOREVER, (void*)wlan_mac_sta_join_bss_attempt_poll);
351}
352
353
354
355/*****************************************************************************/
356/**
357 * @brief Stop the join process
358 *
359 * This function stops the join process and returns the FSM to "IDLE"
360 *
361 *****************************************************************************/
362void wlan_mac_sta_join_return_to_idle(){
363
364    volatile scan_parameters_t* scan_parameters;
365    interrupt_state_t prev_interrupt_state;
366
367    // Stop any on-going scans
368    wlan_mac_scan_stop();
369
370    // Stop interrupts while removing scheduled events
371    prev_interrupt_state = wlan_platform_intc_stop();
372
373    // Set the join state
374    join_state = IDLE;
375    authentication_state = UNAUTHENTICATED;
376
377    // Remove any scheduled search polls
378    if(search_sched_id != SCHEDULE_ID_RESERVED_MAX){
379        wlan_mac_schedule_remove_event(search_sched_id);
380        search_sched_id = SCHEDULE_ID_RESERVED_MAX;
381    }
382
383    // Remove any scheduled attempt polls
384    if(attempt_sched_id != SCHEDULE_ID_RESERVED_MAX){
385        wlan_mac_schedule_remove_event(attempt_sched_id);
386        attempt_sched_id = SCHEDULE_ID_RESERVED_MAX;
387    }
388
389    // Restore interrupt state
390    wlan_platform_intc_set_state(prev_interrupt_state);
391
392    // Remove "attempt_bss_info"
393    attempt_network_info = NULL;
394
395    // Return the scan SSID parameter back to its previous state
396    //     - Since wlan_mac_sta_return_to_idle() can be called at any time, the
397    //       SSID should only be returned once lest the saved SSID in join get
398    //       out of sync with the current scan SSID since the SSID is only saved
399    //       when wlan_mac_sta_join() is called.
400    //
401    if (scan_ssid_save != NULL) {
402        // Get the scan parameters
403        scan_parameters = wlan_mac_scan_get_parameters();
404
405        // Restore the SSID in the scan parameters with the value stored when
406        // wlan_mac_sta_join() was called
407        wlan_mac_high_free(scan_parameters->ssid);
408        scan_parameters->ssid = strndup(scan_ssid_save, SSID_LEN_MAX);
409        wlan_mac_high_free(scan_ssid_save);
410
411        // Set the saved SSID to NULL
412        scan_ssid_save = NULL;
413     }
414}
415
416
417
418/*****************************************************************************/
419/**
420 * @brief Polling function during "SEARCHING" process
421 *
422 * This function is used during the "SEARCHING" process to check the state of
423 * node to determine if it is able to move on to the "ATTEMPTING" part of the
424 * join process.
425 *
426 * Once started, the "SEARCHING" process will continue forever until explicitly
427 * stopped by calling wlan_mac_sta_join_return_to_idle().
428 *
429 *****************************************************************************/
430void wlan_mac_sta_join_bss_search_poll(u32 schedule_id){
431    dl_list* ssid_match_list = NULL;
432    dl_entry* curr_dl_entry = NULL;
433
434    switch(join_state){
435        case IDLE:
436            xil_printf("JOIN FSM Error: Searching/Idle mismatch\n");
437        break;
438
439        case SEARCHING:
440            if (wlan_mac_scan_get_num_scans() >= 0) {
441                // In a future release, we may modify the join process to prioritize among
442                // networks with matching SSIDs. In this scenario, the condition on
443                // wlan_mac_scan_get_num_scans() may be made more strict to require at least
444                // one full "loop" through all channels.
445                ssid_match_list = wlan_mac_high_find_network_info_SSID(gl_join_parameters.ssid);
446
447                if (ssid_match_list->length > 0) {
448                    // Join the first entry in the list
449                    //     - This could be modified in the future to use some other selection,
450                    //       for example RX power.
451                    //
452                    curr_dl_entry = ssid_match_list->first;
453
454                    // Return to the IDLE state
455                    //     - Will stop the current scan
456                    //     - This must be done before setting "attempt_bss_info"
457                    wlan_mac_sta_join_return_to_idle();
458
459                    // Set network info to attempt to join
460                    attempt_network_info = (network_info_t*)(curr_dl_entry->data);
461
462                   // Start the "ATTEMPTING" process
463                   start_join_attempt();
464                }
465            }
466        break;
467
468        case ATTEMPTING:
469            xil_printf("Join FSM Error: Searching/Attempting mismatch\n");
470        break;
471    }
472}
473
474
475
476/*****************************************************************************/
477/**
478 * Attempt to join the BSS
479 *
480 * This function is used during the "ATTEMPTING" process to check the state of
481 * node to determine if it is able to finish the join process.  This function
482 * is designed to be called multiple times during each join attempt and will
483 * perform a different action based on the state of the BSS.  This function will
484 * attempt to move the BSS from:
485 *       UNAUTHENTICATED --> AUTHENTICATED --> ASSOCIATED
486 *
487 * This function can be called by the STA directly as part of the mpdu_rx_process()
488 * function when receiving responses from the AP or it will be called periodically
489 * by the scheduler.  This will ensure that the join process is robust even if a
490 * packet is lost.
491 *
492 * Once started, the "ATTEMPTING" process will continue forever until explicitly
493 * stopped by calling wlan_mac_sta_join_return_to_idle().
494 *
495 * @param  aid               - Association ID of the join
496 *
497 * Given that this function can be called while the BSS is is different states, the
498 * association ID can be ignored (and will have a bogus value) in certain contexts.
499 * Depending on who is calling this function, the argument means different things:
500 *   (1) When called by the scheduler, the argument is automatically filled in with the schedule ID
501 *       but the state will always be BSS_STATE_UNAUTHENTICATED or BSS_STATE_AUTHENTICATED, so the
502 *       aid will be ignored.
503 *   (2) STA will call this when it receives an authentication packet that elevates the state
504 *       to BSS_AUTHENTICATED. In this context, the argument is meaningless (explicitly 0 valued)
505 *   (3) STA will call this when it receives an association response that elevates the state to
506 *       BSS_ASSOCIATED. In this context, the argument will be the AID provided by the AP sending
507 *       the association response.
508 *
509 *****************************************************************************/
510void wlan_mac_sta_join_bss_attempt_poll(u32 aid){
511    bss_config_t bss_config;
512    u32 update_mask;
513
514    if (attempt_network_info == NULL) {
515        wlan_mac_sta_join_return_to_idle();
516        return;
517    }
518
519    switch(join_state){
520        case IDLE:
521             xil_printf("JOIN FSM Error: Attempting/Idle mismatch\n");
522        break;
523
524        case SEARCHING:
525             xil_printf("JOIN FSM Error: Attempting/Searching mismatch\n");
526        break;
527
528        case ATTEMPTING:
529            switch(authentication_state){
530                case UNAUTHENTICATED:
531                    transmit_join_auth_req();
532                break;
533
534                case AUTHENTICATED:
535                    transmit_join_assoc_req();
536                break;
537
538                case ASSOCIATED:
539                    // Important: wlan_mac_sta_join_return_to_idle() will NULL out attempt_bss_info,
540                    //     so it should not be called before actually setting the association state
541
542                    // Set AID
543                    my_aid = aid;
544
545                    bss_config = attempt_network_info->bss_config;
546                    update_mask = BSS_FIELD_MASK_ALL;
547
548                    if (configure_bss(&bss_config, update_mask) == 0) {
549                        // Join was successful, so execute callback
550                        join_success_callback(attempt_network_info);
551                    } else {
552                        // Join was not successful
553                        xil_printf("Unable to associate with BSS %s\n", attempt_network_info->bss_config.ssid);
554                    }
555
556                    // Stop the join process
557                    wlan_mac_sta_join_return_to_idle();
558                break;
559
560                default:
561                    xil_printf("Error: STA attempt poll: Unknown state %d for BSS info %s\n", authentication_state, attempt_network_info->bss_config.ssid);
562                break;
563            }
564        break;
565    }
566}
567
568
569
570/*****************************************************************************/
571/**
572 * Transmit authentication request
573 *
574 * This internal function will transmit an authentication request if the state
575 * machine is in the "ATTEMPTING" to join state.
576 *
577 *****************************************************************************/
578void transmit_join_auth_req(){
579    u16 tx_length;
580    dl_entry* tx_queue_entry;
581    tx_80211_queue_buffer_t* tx_queue_buffer;
582
583    // Only transmit if FSM is "ATTEMPTING" to join
584    if (join_state == ATTEMPTING) {
585
586        tx_queue_entry = queue_checkout();
587
588        if (tx_queue_entry != NULL) {
589            tx_queue_buffer = (tx_80211_queue_buffer_t*)(tx_queue_entry->data);
590
591            tx_length = wlan_create_auth_frame(tx_queue_buffer->pkt,
592                                               attempt_network_info->bss_config.bssid,
593                                               wlan_mac_addr,
594                                               attempt_network_info->bss_config.bssid,
595                                               AUTH_ALGO_OPEN_SYSTEM,
596                                               AUTH_SEQ_REQ,
597                                               STATUS_SUCCESS);
598
599            // Fill in metadata
600            tx_queue_buffer->flags = TX_80211_QUEUE_BUFFER_FLAGS_FILL_DURATION;
601            tx_queue_buffer->length = tx_length;
602            tx_queue_buffer->seg0_len = tx_length;
603            tx_queue_buffer->seg1_len = tx_length;
604            tx_queue_buffer->seg1_offset = 0;
605            tx_queue_buffer->station_info = station_info_create(attempt_network_info->bss_config.bssid);
606
607            // Put the packet in the queue
608            wlan_mac_enqueue_wireless_tx(mgmt_qid, tx_queue_entry);
609
610            // Poll the TX queues to possibly send the packet
611            poll_tx_queues(PKT_BUF_GROUP_GENERAL);
612        }
613    }
614}
615
616
617
618/*****************************************************************************/
619/**
620 * Transmit association request
621 *
622 * This internal function will transmit an association request if the state
623 * machine is in the "ATTEMPTING" to join state.
624 *
625 *****************************************************************************/
626void transmit_join_assoc_req(){
627    u16 tx_length;
628    dl_entry* tx_queue_entry;
629    tx_80211_queue_buffer_t* tx_queue_buffer;
630
631    // Only transmit if FSM is "ATTEMPTING" to join
632    if (join_state == ATTEMPTING) {
633
634        tx_queue_entry = queue_checkout();
635
636        if (tx_queue_entry != NULL) {
637            tx_queue_buffer = (tx_80211_queue_buffer_t*)(tx_queue_entry->data);
638
639            tx_length = wlan_create_association_req_frame(tx_queue_buffer->pkt,
640                                                          attempt_network_info->bss_config.bssid,
641                                                          wlan_mac_addr,
642                                                          attempt_network_info->bss_config.bssid,
643                                                          attempt_network_info);
644            // Fill in metadata
645            tx_queue_buffer->flags = TX_80211_QUEUE_BUFFER_FLAGS_FILL_DURATION;
646            tx_queue_buffer->length = tx_length;
647            tx_queue_buffer->seg0_len = tx_length;
648            tx_queue_buffer->seg1_len = 0;
649            tx_queue_buffer->seg1_offset = 0;
650            tx_queue_buffer->station_info = station_info_create(attempt_network_info->bss_config.bssid);
651
652            // Put the packet in the queue
653            wlan_mac_enqueue_wireless_tx(mgmt_qid, tx_queue_entry);
654
655            // Poll the TX queues to possibly send the packet
656            poll_tx_queues(PKT_BUF_GROUP_GENERAL);
657        }
658    }
659}
660
661
Note: See TracBrowser for help on using the repository browser.