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

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

1.8.0 release wlan-mac-se

File size: 33.5 KB
Line 
1/** @file wlan_mac_station_info.c
2 *  @brief Station Information Metadata Subsystem
3 *
4 *  This contains code tracking metadata about stations.
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/***************************** Include Files *********************************/
15
16#include "wlan_mac_high_sw_config.h"
17
18#include "xil_types.h"
19#include "stdlib.h"
20#include "stdio.h"
21#include "wlan_platform_high.h"
22#include "string.h"
23
24#include "wlan_mac_pkt_buf_util.h"
25#include "wlan_mac_high.h"
26#include "wlan_mac_station_info.h"
27#include "wlan_mac_dl_list.h"
28#include "wlan_mac_802_11_defs.h"
29#include "wlan_mac_schedule.h"
30#include "wlan_mac_addr_filter.h"
31#include "wlan_mac_network_info.h"
32#include "wlan_platform_common.h"
33#include "wlan_mac_common.h"
34#include "wlan_common_types.h"
35#include "wlan_mac_eth_util.h"
36
37/*********************** Global Variable Definitions *************************/
38
39
40extern platform_high_dev_info_t platform_high_dev_info;
41
42/*************************** Variable Definitions ****************************/
43
44static dl_list station_info_free; ///< Free station_info_t
45
46/// The counts_txrx_list is stored chronologically from .first being oldest
47/// and .last being newest. The "find" function search from last to first
48/// to minimize search time for new BSSes you hear from often.
49static dl_list station_info_list; ///< Filled station_info_t
50
51
52
53// Default Transmission Parameters
54typedef struct default_tx_params_t{
55    tx_params_t unicast_mgmt;
56    tx_params_t unicast_data;
57    tx_params_t multicast_mgmt;
58    tx_params_t multicast_data;
59} default_tx_params_t;
60
61static default_tx_params_t default_tx_params;
62
63
64/*************************** Functions Prototypes ****************************/
65
66station_info_entry_t* station_info_find_oldest();
67
68
69/******************************** Functions **********************************/
70
71void station_info_init() {
72
73    u32 i;
74    u32 num_station_info;
75    station_info_entry_t* station_info_entry_base;
76
77    // Set sane default Tx params. These will be overwritten by the user application
78    tx_params_t tx_params = { .phy = { .mcs = 0, .phy_mode = PHY_MODE_NONHT, .antenna_mode = TX_ANTMODE_SISO_ANTA, .power = 15 },
79                              .mac = { .flags = 0 } };
80
81    wlan_mac_set_default_tx_params(unicast_data, &tx_params);
82    wlan_mac_set_default_tx_params(unicast_mgmt, &tx_params);
83    wlan_mac_set_default_tx_params(mcast_data, &tx_params);
84    wlan_mac_set_default_tx_params(mcast_mgmt, &tx_params);
85
86    dl_list_init(&station_info_free);
87    dl_list_init(&station_info_list);
88
89    // Clear the memory in the dram used for bss_infos
90    bzero((void*)STATION_INFO_BUFFER_BASE, STATION_INFO_BUFFER_SIZE);
91
92    // The number of elements we can initialize is limited by the smaller of two values:
93    //     (1) The number of dl_entry structs we can squeeze into STATION_INFO_DL_ENTRY_MEM_SIZE
94    //     (2) The number of station_info_t structs we can squeeze into STATION_INFO_BUFFER_SIZE
95    num_station_info = WLAN_MIN(STATION_INFO_DL_ENTRY_MEM_SIZE/sizeof(station_info_entry_t), STATION_INFO_BUFFER_SIZE/sizeof(station_info_t));
96
97    // At boot, every dl_entry buffer descriptor is free
98    // To set up the doubly linked list, we exploit the fact that we know the starting state is sequential.
99    // This matrix addressing is not safe once the queue is used. The insert/remove helper functions should be used
100    station_info_entry_base = (station_info_entry_t*)(STATION_INFO_DL_ENTRY_MEM_BASE);
101
102    for (i = 0; i < num_station_info; i++) {
103        station_info_entry_base[i].data = (station_info_t*)(STATION_INFO_BUFFER_BASE + (i*sizeof(station_info_t)));
104        dl_entry_insertEnd(&station_info_free, (dl_entry*)&(station_info_entry_base[i]));
105    }
106
107    xil_printf("Station Info list (len %d) placed in DRAM: using %d kB\n", num_station_info, (num_station_info*sizeof(station_info_t))/1024);
108
109    return;
110}
111
112
113void station_info_init_finish(){
114    //Will be called after interrupts have been started. Safe to use scheduler now.
115    wlan_mac_schedule_add_event(SCHEDULE_ID_COARSE, 10000000, SCHEDULE_REPEAT_FOREVER, (void*)station_info_timestamp_check);
116}
117
118inline station_info_t* station_info_txreport_process(void* pkt_buf_addr, wlan_mac_low_tx_details_t* wlan_mac_low_tx_details) {
119    tx_frame_info_t* tx_frame_info = (tx_frame_info_t*)pkt_buf_addr;
120    mac_header_80211* tx_80211_header = (mac_header_80211*)((u8*)tx_frame_info + PHY_TX_PKT_BUF_MPDU_OFFSET);
121    station_info_t* curr_station_info;
122    u64 curr_system_time = get_system_time_usec();
123#if WLAN_SW_CONFIG_ENABLE_TXRX_COUNTS
124    station_txrx_counts_t* curr_txrx_counts;
125    txrx_counts_sub_t* txrx_counts_sub;
126    u8 pkt_type;
127    pkt_type = (tx_80211_header->frame_control_1 & MAC_FRAME_CTRL1_MASK_TYPE);
128#endif
129
130    curr_station_info = station_info_create(tx_80211_header->address_1);
131
132    if(curr_station_info == NULL) return NULL;
133
134    // By this point in the function, curr_station_info is guaranteed to be pointing to a valid station_info_t struct
135    // that we should update with this reception.
136
137    // Update the latest TXRX time
138    curr_station_info->latest_txrx_timestamp = curr_system_time;
139
140    if(wlan_mac_low_tx_details->flags & TX_DETAILS_FLAGS_RECEIVED_RESPONSE){
141        curr_station_info->latest_rx_timestamp = curr_system_time;
142    }
143
144#if WLAN_SW_CONFIG_ENABLE_TXRX_COUNTS
145    curr_txrx_counts = &(curr_station_info->txrx_counts);
146
147    switch(pkt_type){
148        default:
149            //Unknown type
150            return curr_station_info;
151        break;
152        case MAC_FRAME_CTRL1_TYPE_DATA:
153            txrx_counts_sub = &(curr_txrx_counts->data);
154        break;
155        case MAC_FRAME_CTRL1_TYPE_MGMT:
156            txrx_counts_sub = &(curr_txrx_counts->mgmt);
157        break;
158    }
159
160    (txrx_counts_sub->tx_num_attempts)++;
161#endif
162
163    return curr_station_info;
164}
165
166inline station_info_t* station_info_posttx_process(void* pkt_buf_addr) {
167    tx_frame_info_t* tx_frame_info = (tx_frame_info_t*)pkt_buf_addr;
168    mac_header_80211* tx_80211_header = (mac_header_80211*)((u8*)tx_frame_info + PHY_TX_PKT_BUF_MPDU_OFFSET);
169    station_info_t* curr_station_info;
170#if WLAN_SW_CONFIG_ENABLE_TXRX_COUNTS
171    station_txrx_counts_t* curr_txrx_counts;
172    txrx_counts_sub_t* txrx_counts_sub;
173    u8 pkt_type;
174    pkt_type = (tx_80211_header->frame_control_1 & MAC_FRAME_CTRL1_MASK_TYPE);
175#endif
176
177    curr_station_info = station_info_create(tx_80211_header->address_1);
178
179    if(curr_station_info == NULL) return NULL;
180
181#if WLAN_SW_CONFIG_ENABLE_TXRX_COUNTS
182    curr_txrx_counts = &(curr_station_info->txrx_counts);
183
184    switch(pkt_type){
185        default:
186            //Unknown type
187            return curr_station_info;
188        break;
189        case MAC_FRAME_CTRL1_TYPE_DATA:
190            txrx_counts_sub = &(curr_txrx_counts->data);
191        break;
192        case MAC_FRAME_CTRL1_TYPE_MGMT:
193            txrx_counts_sub = &(curr_txrx_counts->mgmt);
194        break;
195    }
196
197    (txrx_counts_sub->tx_num_packets_total)++;
198    (txrx_counts_sub->tx_num_bytes_total) += (tx_frame_info->length);
199
200    if((tx_frame_info->tx_result) == TX_FRAME_INFO_RESULT_SUCCESS){
201        (txrx_counts_sub->tx_num_packets_success)++;
202        (txrx_counts_sub->tx_num_bytes_success) += tx_frame_info->length;
203    }
204#endif
205
206    return curr_station_info;
207
208}
209
210inline station_info_t* station_info_postrx_process(void* pkt_buf_addr) {
211    rx_frame_info_t* rx_frame_info = (rx_frame_info_t*)pkt_buf_addr;
212    void* mac_payload = (u8*)pkt_buf_addr + PHY_RX_PKT_BUF_MPDU_OFFSET;
213    mac_header_80211* rx_80211_header = (mac_header_80211*)((void *)mac_payload);
214    station_info_t* curr_station_info = NULL;
215    u8 pkt_type;
216    u64 curr_system_time = get_system_time_usec();
217
218    pkt_type = (rx_80211_header->frame_control_1 & MAC_FRAME_CTRL1_MASK_TYPE);
219
220    if ( (rx_frame_info->flags & RX_FRAME_INFO_FLAGS_FCS_GOOD) &&
221            (pkt_type !=  MAC_FRAME_CTRL1_TYPE_CTRL)) {
222        // We will only consider good FCS receptions in our counts. We cannot
223        // trust the address bytes themselves if the FCS is in error. Furthermore,
224        // control frames will not be considered for counts either since the CTS
225        // and ACK frames have no addr2 field.
226
227        curr_station_info = station_info_create(rx_80211_header->address_2);
228
229        if(curr_station_info == NULL) return NULL;
230
231        // If this reception is HTMF, we have a pretty good indication that this device
232        // is capable of also receiving HTMF waveforms. We'll update its flags accordingly
233        if(rx_frame_info->phy_details.phy_mode == PHY_MODE_HTMF) curr_station_info->capabilities |= STATION_INFO_CAPABILITIES_HT_CAPABLE;
234
235        // By this point in the function, curr_station_info is guaranteed to be pointing to a valid station_info_t struct
236        // that we should update with this reception.
237
238        // Update the latest TXRX time
239        curr_station_info->latest_txrx_timestamp = curr_system_time;
240
241        // Update the latest RX time
242        curr_station_info->latest_rx_timestamp = curr_system_time;
243
244    }
245
246    return curr_station_info;
247}
248
249void station_info_rx_process_hostname( void* pkt_buf_addr, station_info_t* station_info ){
250    // Some DHCP frames contain a hostname that makes it easier to recognize a station_info_t
251    // as a particular device on the network. This is purely informational and has no effect
252    // on standard 802.11 operations.
253
254    // To minimize confusion, we should avoid inserting a hostname into a station_info_t
255    // for devices that have multiple hosts upstream of them (e.g. an AP). We will only extract
256    // the hostname from DHCP packets where the transmitter address (addr2) of the 802.11 header
257    // matches the hardware MAC address inside the DHCP payload itself. This will not be the case
258    // for AP transmissions.
259
260    mac_header_80211* rx80211_hdr = (mac_header_80211*)((u8*)pkt_buf_addr + PHY_RX_PKT_BUF_MPDU_OFFSET);
261
262    llc_header_t* llc_hdr;
263    u16 pre_llc_offset;
264    ipv4_header_t* ip_hdr;
265    dhcp_packet* dhcp;
266    udp_header_t* udp;
267    u8* eth_mid_ptr;
268    u8 is_dhcp_req;
269    u8 continue_loop;
270
271    switch(rx80211_hdr->frame_control_1){
272        case MAC_FRAME_CTRL1_SUBTYPE_QOSDATA:
273            pre_llc_offset = sizeof(qos_control);
274        break;
275        case MAC_FRAME_CTRL1_SUBTYPE_DATA:
276            pre_llc_offset = 0;
277        break;
278        default:
279            // Unrecognized type
280            return;
281        break;
282    }
283
284    llc_hdr = (llc_header_t*)((u8*)rx80211_hdr + sizeof(mac_header_80211) + pre_llc_offset);
285
286    if(llc_hdr->type == ETH_TYPE_IP){
287        ip_hdr = (ipv4_header_t*)((u8*)rx80211_hdr + sizeof(mac_header_80211) + sizeof(llc_header_t) + pre_llc_offset );
288
289        if (ip_hdr->protocol == IPV4_PROT_UDP) {
290            udp = (udp_header_t*)((void*)ip_hdr + 4*((u8)(ip_hdr->version_ihl) & 0xF));
291
292            // All Bootstrap Protocol packets contain the client MAC address as part of the
293            // payload. For STA de-encapsulation, we need to replace the wireless MAC address
294            // of the STA with the wired MAC address of the client
295            if ((Xil_Ntohs(udp->src_port) == UDP_SRC_PORT_BOOTPC) ||
296                (Xil_Ntohs(udp->src_port) == UDP_SRC_PORT_BOOTPS)) {
297
298                // Disable the checksum since this will change the bytes in the packet
299                udp->checksum = 0;
300
301                dhcp = (dhcp_packet*)((u8*)udp + sizeof(udp_header_t));
302
303                if (Xil_Ntohl(dhcp->magic_cookie) == DHCP_MAGIC_COOKIE) {
304                    eth_mid_ptr = (u8*)((void*)dhcp + sizeof(dhcp_packet));
305                    // Iterate over all tagged parameters in the DHCP request, looking for the hostname parameter
306                    //     NOTE:  Stop after 20 tagged parameters (handles case of mal-formed DHCP packets missing END tag)
307                    continue_loop = 20;
308                    while(continue_loop) {
309                        continue_loop--;
310                        switch(eth_mid_ptr[0]) {
311                            case DHCP_OPTION_TAG_TYPE:
312                                if((eth_mid_ptr[2] == DHCP_OPTION_TYPE_DISCOVER) ||
313                                   (eth_mid_ptr[2] == DHCP_OPTION_TYPE_REQUEST)) {
314                                        is_dhcp_req = 1;
315                                }
316                            break;
317                            case DHCP_HOST_NAME:
318                                if (is_dhcp_req && wlan_addr_eq(dhcp->chaddr, rx80211_hdr->address_2) ) {
319                                    if(station_info != NULL) {
320                                        // rx_frame_info has pointer to STA entry in association table - fill in that entry's hostname field
321                                        // Zero out the hostname field of the station_info
322                                        //     NOTE: This will effectively Null-terminate the string
323                                        bzero(station_info->hostname, STATION_INFO_HOSTNAME_MAXLEN+1);
324                                        // Copy the string from the DHCP payload into the hostname field
325                                        memcpy(station_info->hostname,
326                                                &(eth_mid_ptr[2]),
327                                                WLAN_MIN(STATION_INFO_HOSTNAME_MAXLEN, eth_mid_ptr[1]));
328                                    }
329                                }
330                            break;
331                            case DHCP_OPTION_END:
332                                continue_loop = 0;
333                            break;
334                        } // END switch(DHCP tag type)
335                        // Increment by size of current tagged parameter
336                        eth_mid_ptr += (2+eth_mid_ptr[1]);
337                    } // END iterate over DHCP tags
338                } // END is DHCP valid
339            } // END is DHCP
340        } // END is UDP
341    }
342
343
344
345
346}
347
348#if WLAN_SW_CONFIG_ENABLE_TXRX_COUNTS
349void station_info_rx_process_counts(void* pkt_buf_addr, station_info_t* station_info, u32 option_flags) {
350    rx_frame_info_t* rx_frame_info = (rx_frame_info_t*)pkt_buf_addr;
351    void* mac_payload = (u8*)pkt_buf_addr + PHY_RX_PKT_BUF_MPDU_OFFSET;
352    mac_header_80211* rx_80211_header          = (mac_header_80211*)((void *)mac_payload);
353    station_txrx_counts_t* curr_txrx_counts;
354    txrx_counts_sub_t* txrx_counts_sub;
355    u8 pkt_type;
356    u16 length = rx_frame_info->phy_details.length;
357
358    pkt_type = (rx_80211_header->frame_control_1 & MAC_FRAME_CTRL1_MASK_TYPE);
359
360    if ( (station_info != NULL) && (rx_frame_info->flags & RX_FRAME_INFO_FLAGS_FCS_GOOD) &&
361            (pkt_type !=  MAC_FRAME_CTRL1_TYPE_CTRL)) {
362        // We will only consider good FCS receptions in our counts. We cannot
363        // trust the address bytes themselves if the FCS is in error. Furthermore,
364        // control frames will not be considered for counts either since the CTS
365        // and ACK frames have no addr2 field.
366
367        curr_txrx_counts = &(station_info->txrx_counts);
368
369        switch(pkt_type){
370            default:
371                //Unknown type
372                return;
373            break;
374            case MAC_FRAME_CTRL1_TYPE_DATA:
375                txrx_counts_sub = &(curr_txrx_counts->data);
376            break;
377            case MAC_FRAME_CTRL1_TYPE_MGMT:
378                txrx_counts_sub = &(curr_txrx_counts->mgmt);
379            break;
380        }
381
382        (txrx_counts_sub->rx_num_packets_total)++;
383        (txrx_counts_sub->rx_num_bytes_total) += (length - WLAN_PHY_FCS_NBYTES - sizeof(mac_header_80211));
384
385        if( (option_flags & RX_PROCESS_COUNTS_OPTION_FLAG_IS_DUPLICATE) == 0){
386            //Unique reception
387            (txrx_counts_sub->rx_num_packets)++;
388            (txrx_counts_sub->rx_num_bytes) += (length - WLAN_PHY_FCS_NBYTES - sizeof(mac_header_80211));
389        }
390    }
391}
392#endif
393
394void station_info_print(dl_list* list, u32 option_flags){
395    // list == NULL : Print all in flat station_info_list
396    // list !- NULL : Print only in provided list
397    int iter;
398    u32 i;
399    dl_list* local_list;
400    dl_entry* curr_dl_entry;
401    station_info_t* curr_station_info;
402#if WLAN_SW_CONFIG_ENABLE_TXRX_COUNTS
403    station_txrx_counts_t* curr_txrx_counts;
404#endif
405
406    if(list != NULL){
407        local_list = list;
408    } else {
409        local_list = &station_info_list;
410    }
411
412    i = 0;
413    iter          = local_list->length;
414    curr_dl_entry = local_list->first;
415
416    // Print the header
417    xil_printf("************************ Station Information *************************\n");
418
419    while ((curr_dl_entry != NULL) && (iter-- > 0)) {
420        curr_station_info = (station_info_t*)(curr_dl_entry->data);
421        xil_printf("%d: [%d] %02x-%02x-%02x-%02x-%02x-%02x ", i, curr_station_info->ID, curr_station_info->addr[0],
422                                                              curr_station_info->addr[1],curr_station_info->addr[2],curr_station_info->addr[3],
423                                                              curr_station_info->addr[4],curr_station_info->addr[5]);
424
425
426        if((curr_station_info->flags & STATION_INFO_FLAG_KEEP)){
427            xil_printf("(KEEP)\n");
428        } else {
429            xil_printf("\n");
430        }
431
432        xil_printf(" Num Linked Queue Buffer:    %d\n", curr_station_info->num_linked_queue_buffer);
433
434        xil_printf(" Data Tx MCS:                %d\n", curr_station_info->tx_params_data.phy.mcs);
435        xil_printf(" Data Tx PHY mode:           %d\n", curr_station_info->tx_params_data.phy.phy_mode);
436        xil_printf(" Data Tx power:              %d\n", curr_station_info->tx_params_data.phy.power);
437        xil_printf(" Data Tx antenna_mode:       0x%x\n", curr_station_info->tx_params_data.phy.antenna_mode);
438        xil_printf(" Management Tx MCS:          %d\n", curr_station_info->tx_params_mgmt.phy.mcs);
439        xil_printf(" Management Tx PHY mode:     %d\n", curr_station_info->tx_params_mgmt.phy.phy_mode);
440        xil_printf(" Management Tx power:        %d\n", curr_station_info->tx_params_mgmt.phy.power);
441        xil_printf(" Management Tx antenna_mode: 0x%x\n", curr_station_info->tx_params_mgmt.phy.antenna_mode);
442
443#if WLAN_SW_CONFIG_ENABLE_TXRX_COUNTS
444        if(option_flags & STATION_INFO_PRINT_OPTION_FLAG_INCLUDE_COUNTS){
445            curr_txrx_counts = &(curr_station_info->txrx_counts);
446            xil_printf("  Data   Rx Num Bytes:           %d\n", (u32)(curr_txrx_counts->data.rx_num_bytes));
447            xil_printf("  Data   Rx Num Bytes Total:     %d\n", (u32)(curr_txrx_counts->data.rx_num_bytes_total));
448            xil_printf("  Data   Tx Num Bytes Success:   %d\n", (u32)(curr_txrx_counts->data.tx_num_bytes_success));
449            xil_printf("  Data   Tx Num Bytes Total:     %d\n", (u32)(curr_txrx_counts->data.tx_num_bytes_total));
450            xil_printf("  Data   Rx Num Packets:         %d\n", (u32)(curr_txrx_counts->data.rx_num_packets));
451            xil_printf("  Data   Rx Num Packets Total:   %d\n", (u32)(curr_txrx_counts->data.rx_num_packets_total));
452            xil_printf("  Data   Tx Num Packets Success: %d\n", (u32)(curr_txrx_counts->data.tx_num_packets_success));
453            xil_printf("  Data   Tx Num Packets Total:   %d\n", (u32)(curr_txrx_counts->data.tx_num_packets_total));
454            xil_printf("  Data   Tx Num Attempts:        %d\n", (u32)(curr_txrx_counts->data.tx_num_attempts));
455            xil_printf("  Mgmt.  Rx Num Bytes:           %d\n", (u32)(curr_txrx_counts->mgmt.rx_num_bytes));
456            xil_printf("  Mgmt.  Rx Num Bytes Total:     %d\n", (u32)(curr_txrx_counts->mgmt.rx_num_bytes_total));
457            xil_printf("  Mgmt.  Tx Num Bytes Success:   %d\n", (u32)(curr_txrx_counts->mgmt.tx_num_bytes_success));
458            xil_printf("  Mgmt.  Tx Num Bytes Total:     %d\n", (u32)(curr_txrx_counts->mgmt.tx_num_bytes_total));
459            xil_printf("  Mgmt.  Rx Num Packets:         %d\n", (u32)(curr_txrx_counts->mgmt.rx_num_packets));
460            xil_printf("  Mgmt.  Rx Num Packets Total:   %d\n", (u32)(curr_txrx_counts->mgmt.rx_num_packets_total));
461            xil_printf("  Mgmt.  Tx Num Packets Success: %d\n", (u32)(curr_txrx_counts->mgmt.tx_num_packets_success));
462            xil_printf("  Mgmt.  Tx Num Packets Total:   %d\n", (u32)(curr_txrx_counts->mgmt.tx_num_packets_total));
463            xil_printf("  Mgmt.  Tx Num Attempts:        %d\n", (u32)(curr_txrx_counts->mgmt.tx_num_attempts));
464        }
465#endif
466
467        xil_printf("    Last update:   %d msec ago\n", (u32)((get_system_time_usec() - curr_station_info->latest_txrx_timestamp)/1000));
468
469
470        curr_dl_entry = dl_entry_next(curr_dl_entry);
471        i++;
472    }
473}
474
475
476void station_info_reset_all_counts_txrx(){
477    //This function will return all counts to 0.
478
479#if WLAN_SW_CONFIG_ENABLE_TXRX_COUNTS
480    int iter;
481    u32 i;
482    dl_entry* curr_dl_entry;
483    station_info_t* curr_station_info;
484    station_txrx_counts_t* curr_txrx_counts;
485
486    i = 0;
487    iter = station_info_list.length;
488    curr_dl_entry = station_info_list.last;
489
490
491    while ((curr_dl_entry != NULL) && (iter-- > 0)) {
492        curr_station_info = (station_info_t*)(curr_dl_entry->data);
493        curr_txrx_counts = &(curr_station_info->txrx_counts);
494
495        bzero(&(curr_txrx_counts->data), sizeof(txrx_counts_sub_t));
496        bzero(&(curr_txrx_counts->mgmt), sizeof(txrx_counts_sub_t));
497
498        curr_dl_entry = dl_entry_prev(curr_dl_entry);
499        i++;
500    }
501#endif
502}
503
504
505
506void station_info_timestamp_check() {
507    dl_entry* curr_dl_entry;
508    station_info_t* curr_station_info;
509
510    curr_dl_entry = station_info_list.first;
511
512    while(curr_dl_entry != NULL){
513        curr_station_info = (station_info_t*)(curr_dl_entry->data);
514
515        if((get_system_time_usec() - curr_station_info->latest_txrx_timestamp) > STATION_INFO_TIMEOUT_USEC){
516            if( ((curr_station_info->flags & STATION_INFO_FLAG_KEEP) == 0) && (curr_station_info->num_linked_queue_buffer <= 0) ){
517                station_info_clear(curr_station_info);
518                dl_entry_remove(&station_info_list, curr_dl_entry);
519                station_info_checkin(curr_dl_entry);
520            }
521        } else {
522            // Nothing after this entry is older, so it's safe to quit
523            return;
524        }
525
526        curr_dl_entry = dl_entry_next(curr_dl_entry);
527    }
528}
529
530station_info_entry_t* station_info_checkout(){
531    station_info_entry_t* entry;
532
533    if(station_info_free.length > 0){
534        entry = ((station_info_entry_t*)(station_info_free.first));
535        dl_entry_remove(&station_info_free,station_info_free.first);
536        return entry;
537    } else {
538        return NULL;
539    }
540}
541
542void station_info_checkin(dl_entry* entry){
543    dl_entry_insertEnd(&station_info_free, (dl_entry*)entry);
544    return;
545}
546
547station_info_entry_t* station_info_find_by_id(u32 id, dl_list* list){
548    int iter;
549    station_info_entry_t* curr_station_info_entry;
550    station_info_t* curr_station_info;
551    dl_list* list_to_search;
552
553    if(list == NULL){
554        // Error. "List" must be provided. ID has no meaning for the
555        //  flat "station_info_list" global.
556        xil_printf("Error: station_info_find_by_id must be provided with a list argument\n");
557        return NULL;
558    } else {
559        list_to_search = list;
560    }
561
562    iter = list_to_search->length;
563    curr_station_info_entry = (station_info_entry_t*)(list_to_search->last);
564
565    while ((curr_station_info_entry != NULL) && (iter-- > 0)) {
566        curr_station_info = curr_station_info_entry->data;
567        if (curr_station_info->ID == (int)id) {
568            return curr_station_info_entry;
569        }
570
571        curr_station_info_entry = dl_entry_prev(curr_station_info_entry);
572    }
573    return NULL;
574}
575
576station_info_entry_t* station_info_find_by_addr(u8* addr, dl_list* list){
577    int iter;
578    station_info_entry_t* curr_station_info_entry;
579    dl_list* list_to_search;
580
581    if(list == NULL){
582        //Optional "list" argument not provided. Search will occur over
583        // flat "station_info_list" global.
584        list_to_search = &station_info_list;
585    } else {
586        list_to_search = list;
587    }
588
589    iter = list_to_search->length;
590    curr_station_info_entry = (station_info_entry_t*)(list_to_search->last);
591
592    while ((curr_station_info_entry != NULL) && (iter-- > 0)) {
593
594        if (wlan_addr_eq(addr, curr_station_info_entry->addr)) {
595            return curr_station_info_entry;
596        }
597
598        curr_station_info_entry = dl_entry_prev(curr_station_info_entry);
599    }
600    return NULL;
601}
602
603station_info_entry_t* station_info_find_oldest(){
604    int iter;
605    station_info_entry_t* curr_station_info_entry;
606    station_info_t* station_info;
607
608    iter                    = station_info_list.length;
609    curr_station_info_entry = (station_info_entry_t*)(station_info_list.first);
610
611    while ((curr_station_info_entry != NULL) && (iter-- > 0)) {
612        station_info = curr_station_info_entry->data;
613
614        if (((station_info->flags & STATION_INFO_FLAG_KEEP) == 0) && (station_info->num_linked_queue_buffer <= 0)) {
615            return curr_station_info_entry;
616        }
617
618        curr_station_info_entry = dl_entry_next(curr_station_info_entry);
619    }
620    return NULL;
621}
622
623
624
625// Function will create a station_info_t and make sure that the address is unique
626// in the flat station_info_list.
627//
628station_info_t* station_info_create(u8* addr){
629    station_info_entry_t* curr_station_info_entry;
630    station_info_t* curr_station_info = NULL;
631
632    curr_station_info_entry = station_info_find_by_addr(addr, NULL);
633
634    if (curr_station_info_entry != NULL){
635        // Get the Tx/Rx Counts from the entry
636        curr_station_info = curr_station_info_entry->data;
637
638        // Remove the entry from the info list so it can be added back later
639        dl_entry_remove(&station_info_list, (dl_entry*)curr_station_info_entry);
640    } else {
641        // Have not seen this addr before; attempt to grab a new dl_entry
642        // struct from the free pool
643        curr_station_info_entry = station_info_checkout();
644
645        if (curr_station_info_entry == NULL){
646            // No free dl_entry; Re-allocate the oldest entry in the filled list
647            curr_station_info_entry = station_info_find_oldest();
648
649            if (curr_station_info_entry != NULL) {
650                dl_entry_remove(&station_info_list, (dl_entry*)curr_station_info_entry);
651            } else {
652                xil_printf("Cannot create station_info.\n");
653                return NULL;
654            }
655        }
656
657        // Get the Station Info from the entry
658        curr_station_info = curr_station_info_entry->data;
659
660        // Clear any old information
661        station_info_clear(curr_station_info);
662
663        // Copy the addr to the station_info_t
664        memcpy(curr_station_info->addr, addr, MAC_ADDR_LEN);
665
666        // Copy the addr to the station_info_entry_t
667        memcpy(curr_station_info_entry->addr, addr, MAC_ADDR_LEN);
668
669        // Set default tx_params_t for management and data frames
670        if (wlan_addr_mcast(addr)){
671            curr_station_info->tx_params_data = default_tx_params.multicast_data;
672            curr_station_info->tx_params_mgmt = default_tx_params.multicast_mgmt;
673        } else {
674            curr_station_info->tx_params_data = default_tx_params.unicast_data;
675            curr_station_info->tx_params_mgmt = default_tx_params.unicast_mgmt;
676        }
677    }
678
679    // Update the timestamp
680    // TODO: This behavior is debatable. The idea here is that, since this
681    // entry was just created, whoever called this function probably does
682    // not want the framework to automatically purge it the next time
683    // station_info_timestamp_check() is called. This shouldn't happen
684    // if care is taken to either:
685    //  (1) Update the timestamp after this function is called and before
686    //      an interrupt context is left.
687    //  (2) Set the STATION_INFO_FLAG_KEEP bit to 1 after this function
688    //      is called and before an interrupt context is left.
689    // This update is just for extra safety and makes it more difficult
690    // to accidentally have the framework delete this struct.
691    curr_station_info->latest_txrx_timestamp = get_system_time_usec();
692
693    // Insert the updated entry into the network list
694    dl_entry_insertEnd(&station_info_list, (dl_entry*)curr_station_info_entry);
695
696    return curr_station_info;
697}
698
699/**
700 * @brief Reset List of Stations
701 *
702 * Reset all Station Infos except ones flagged to be kept
703 *
704 * @param  None
705 * @return None
706 */
707void station_info_reset_all(){
708    dl_entry* next_dl_entry = station_info_list.first;
709    dl_entry* curr_dl_entry;
710    station_info_t* curr_station_info;
711    int iter = station_info_list.length;
712
713    while( (next_dl_entry != NULL) && (iter-- > 0) ){
714        curr_dl_entry = next_dl_entry;
715        next_dl_entry = dl_entry_next(curr_dl_entry);
716        curr_station_info = (station_info_t*)(curr_dl_entry->data);
717
718        if( ((curr_station_info->flags & STATION_INFO_FLAG_KEEP) == 0) && (curr_station_info->num_linked_queue_buffer <= 0)){
719            station_info_clear(curr_station_info);
720            dl_entry_remove(&station_info_list, curr_dl_entry);
721            station_info_checkin(curr_dl_entry);
722        }
723    }
724}
725
726#if WLAN_SW_CONFIG_ENABLE_TXRX_COUNTS
727/**
728 * @brief Zero all Counts
729 *
730 * Zero all counts
731 *
732 * @param  None
733 * @return None
734 */
735void txrx_counts_zero_all(){
736    dl_entry* next_dl_entry = station_info_list.first;
737    dl_entry* curr_dl_entry;
738    station_info_t* curr_station_info;
739    station_txrx_counts_t* curr_txrx_counts;
740    int iter = station_info_list.length;
741
742    while( (next_dl_entry != NULL) && (iter-- > 0) ){
743        curr_dl_entry = next_dl_entry;
744        next_dl_entry = dl_entry_next(curr_dl_entry);
745        curr_station_info = (station_info_t*)(curr_dl_entry->data);
746        curr_txrx_counts = &(curr_station_info->txrx_counts);
747        station_info_clear_txrx_counts(curr_txrx_counts);
748    }
749
750}
751
752void station_info_clear_txrx_counts(station_txrx_counts_t* txrx_counts){
753    bzero(txrx_counts, sizeof(station_txrx_counts_t));
754}
755#endif
756
757void station_info_clear(station_info_t* station_info){
758    if (station_info != NULL){
759        bzero(station_info, sizeof(station_info_t));
760
761        //Certain parameters treat zero as a valid value. These
762        // parameters are manually updated here to indicate this
763        // station_info_t is new.
764        station_info->latest_rx_seq = 0xFFFF;
765        station_info->QID = -1;
766        station_info->ID = -1;
767        station_info->latest_rx_timestamp = (u64)-1;
768        station_info->latest_txrx_timestamp = (u64)-1;
769    }
770}
771
772
773
774inline dl_list* station_info_get_list(){
775    return &station_info_list;
776}
777
778
779station_info_t* station_info_add_to_list(dl_list* app_station_info_list, u8* addr){
780    station_info_entry_t* entry = NULL;
781    station_info_t* station_info = NULL;
782
783    // Search for the station_info inside the provided list
784    entry = station_info_find_by_addr(addr, app_station_info_list);
785
786    if(entry != NULL){
787        station_info = (station_info_t*)(entry->data);
788        // This addr is already tied to an list entry. We'll just pass this call
789        // the pointer to that entry back to the calling function without creating a new entry
790    } else {
791
792        // This addr is new, so we'll have to add an entry into the list
793        entry = wlan_mac_high_malloc(sizeof(station_info_entry_t));
794        if(entry == NULL){
795            return NULL;
796        }
797
798        memcpy(entry->addr, addr, MAC_ADDR_LEN);
799
800        station_info = station_info_create(addr);
801
802        if(station_info == NULL){
803            wlan_mac_high_free(entry);
804            return NULL;
805        }
806
807        bzero(&(station_info->rate_info),sizeof(rate_selection_info_t));
808        station_info->rate_info.rate_selection_scheme = RATE_SELECTION_SCHEME_STATIC;
809
810        // Populate the entry
811        entry->data = (void*)station_info;
812
813        // Add it to the list
814        dl_entry_insertEnd(app_station_info_list, (dl_entry*)entry);
815
816    }
817    return station_info;
818}
819
820int station_info_remove_from_list(dl_list* app_station_info_list, u8* addr){
821    station_info_entry_t* entry;
822
823    entry = station_info_find_by_addr(addr, app_station_info_list);
824
825    if(entry == NULL){
826        // This addr doesn't refer to any station currently in the list,
827        // so there is nothing to remove. We'll return an error to let the calling
828        // function know that something is wrong.
829        return WLAN_FAILURE;
830    } else {
831
832        // Remove station from the list;
833        dl_entry_remove(app_station_info_list, (dl_entry*)entry);
834
835        wlan_mac_high_free(entry);
836
837        return WLAN_SUCCESS;
838
839    }
840}
841
842/**
843 * @brief Is the provided station a valid member of the provided list
844 *
845 * Function will check that the provided station is part of the dl_list provided as the first argument
846 *
847 * @param  dl_list* station_info_list
848 *     - Pointer to list of Station Info structs
849 * @param  station_info * station
850 *     - Station info pointer to check
851 * @return u8
852 *     - 0  - Station is not a member of the provided list
853 *     - 1  - Station is a member of the provided listp_
854 *
855 */
856u8  station_info_is_member(dl_list* app_station_info_list, station_info_t* station_info){
857    dl_entry* curr_station_info_entry;
858    station_info_t* station_info_temp;
859    int iter = app_station_info_list->length;
860
861    curr_station_info_entry = app_station_info_list->first;
862
863    while( (curr_station_info_entry != NULL) && (iter-- > 0) ){
864
865        station_info_temp = (station_info_t*)(curr_station_info_entry->data);
866
867        if(station_info == station_info_temp){
868            return 1;
869        }
870
871        curr_station_info_entry = dl_entry_next(curr_station_info_entry);
872    }
873
874    return 0;
875}
876
877tx_params_t wlan_mac_get_default_tx_params(default_tx_param_sel_t default_tx_param_sel){
878    tx_params_t ret;
879
880    switch(default_tx_param_sel){
881        case unicast_mgmt:
882            ret = default_tx_params.unicast_mgmt;
883        break;
884        case unicast_data:
885            ret = default_tx_params.unicast_data;
886        break;
887        case mcast_mgmt:
888            ret = default_tx_params.multicast_mgmt;
889        break;
890        case mcast_data:
891            ret = default_tx_params.multicast_data;
892        break;
893    }
894    return ret;
895}
896void wlan_mac_set_default_tx_params(default_tx_param_sel_t default_tx_param_sel, tx_params_t* tx_params){
897    switch(default_tx_param_sel){
898        case unicast_mgmt:
899            default_tx_params.unicast_mgmt = *tx_params;
900        break;
901        case unicast_data:
902            default_tx_params.unicast_data = *tx_params;
903        break;
904        case mcast_mgmt:
905            default_tx_params.multicast_mgmt = *tx_params;
906        break;
907        case mcast_data:
908            default_tx_params.multicast_data = *tx_params;
909        break;
910    }
911}
912
913void wlan_mac_reapply_default_tx_params(){
914    station_info_entry_t* station_info_entry;
915    station_info_t* station_info;
916    int iter;
917
918    station_info_entry = (station_info_entry_t*)(station_info_list.first);
919    iter = station_info_list.length;
920
921    while( (station_info_entry != NULL) && (iter-- > 0) ){
922        station_info = station_info_entry->data;
923
924        if (wlan_addr_mcast(station_info_entry->addr)){
925            station_info->tx_params_data = default_tx_params.multicast_data;
926            station_info->tx_params_mgmt = default_tx_params.multicast_mgmt;
927        } else {
928            station_info->tx_params_data = default_tx_params.unicast_data;
929            station_info->tx_params_mgmt = default_tx_params.unicast_mgmt;
930        }
931        station_info_entry = (station_info_entry_t*)dl_entry_next((dl_entry*)station_info_entry);
932    }
933
934    // Update the beacon template if it's being used. For projects like STA, this function will not result in any behavior changes
935    wlan_mac_high_update_beacon_tx_params(&(default_tx_params.multicast_mgmt));
936
937}
Note: See TracBrowser for help on using the repository browser.