- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

# /space/home/slher/rel/Beken/v6_4_5/macsw/ip/umac/src/scanu/scanu.c

Go to the documentation of this file.

    00001
    00018 /*
    00019  * INCLUDE FILES
    00020  ****************************************************************************************
    00021  */
    00022
    00023 // for endian functions
    00024 #include "co_endian.h"
    00025 // for co read/write
    00026 #include "co_utils.h"
    00027 #include "scanu.h"
    00028
    00029 #include "scanu_task.h"
    00030 #include "co_status.h"
    00031 #include "mac_frame.h"
    00032 #include "me_mgmtframe.h"
    00033 #include "me_utils.h"
    00034
    00035 #include "scan_task.h"
    00036 #include "rxu_task.h"
    00037 #include "me.h"
    00038 #include "mac_ie.h"
    00039
    00040 #include "vif_mgmt.h"
    00041 #include "tpc.h"
    00042
    00043 #if (NX_P2P)
    00044 #include "p2p.h"
    00045 #endif //(NX_P2P)
    00046
    00047 /*
    00048  * GLOBAL VARIABLES
    00049  ****************************************************************************************
    00050  */
    00051
    00053 struct scanu_env_tag scanu_env;
    00054
    00055 /*
    00056  * PRIVATE FUNCTIONS DEFINITION
    00057  ****************************************************************************************
    00058  */
    00059
    00068 static uint32_t scanu_build_ie(void)
    00069 {
    00070     struct scanu_start_req const *param = scanu_env.param;
    00071     struct scanu_add_ie_tag *add_ie = &scanu_add_ie;
    00072     struct scan_probe_req_ie_tag *ie = &scan_probe_req_ie;
    00073     uint32_t add_ie_buf = CPU2HW(add_ie->buf);
    00074     uint32_t ie_buf = CPU2HW(ie->buf);
    00075     uint8_t sup_rate_len = MAC_RATESET_LEN;
    00076     uint8_t sup_rate_oft = 0;
    00077     uint8_t ie_len;
    00078     uint16_t add_ie_len = param->add_ie_len;
    00079
    00080     // Check if the additional IE buffer is valid
    00081     if (add_ie_len > SCANU_MAX_IE_LEN)
    00082         add_ie_len = 0;
    00083
    00084     // Compute the number of legacy rates depending on the band we scan
    00085     if ((scanu_env.band == PHY_BAND_5G) || param->no_cck)
    00086     {
    00087         sup_rate_len = MAC_RATES_ELMT_MAX_LEN;
    00088         sup_rate_oft = 4;
    00089     }
    00090
    00091     // The supported rates is the first element to put
    00092     co_write8p(ie_buf++, MAC_ELTID_RATES);
    00093     co_write8p(ie_buf++, MAC_RATES_ELMT_MAX_LEN);
    00094     co_pack8p(ie_buf, &mac_id2rate[sup_rate_oft], MAC_RATES_ELMT_MAX_LEN);
    00095     ie_buf += MAC_RATES_ELMT_MAX_LEN;
    00096
    00097     // Check if the first element of the IE buffer is the request information
    00098     if (add_ie_len && (co_read8p(add_ie_buf) == MAC_ELTID_REQUEST))
    00099     {
    00100         // Copy the IE
    00101         ie_len = co_read8p(add_ie_buf + 1) + 2;
    00102         co_copy8p(ie_buf, add_ie_buf, ie_len);
    00103         ie_buf += ie_len;
    00104         add_ie_buf += ie_len;
    00105         add_ie_len -= ie_len;
    00106     }
    00107
    00108     // Extended supported rates
    00109     if (sup_rate_len > MAC_RATES_ELMT_MAX_LEN)
    00110     {
    00111         ie_len = sup_rate_len - MAC_RATES_ELMT_MAX_LEN;
    00112         co_write8p(ie_buf++, MAC_ELTID_EXT_RATES);
    00113         co_write8p(ie_buf++, ie_len);
    00114         co_pack8p(ie_buf, &mac_id2rate[MAC_RATES_ELMT_MAX_LEN], ie_len);
    00115         ie_buf += ie_len;
    00116     }
    00117
    00118     // Then comes the DS parameter
    00119     if (scanu_env.band == PHY_BAND_2G4)
    00120     {
    00121         co_write8p(ie_buf++, MAC_ELTID_DS);
    00122         co_write8p(ie_buf++, 1);
    00123         ie_buf++; // Skip the channel number, as it will be filled by the LMAC
    00124     }
    00125
    00126     // Now we may have the Supported Operating Classes in the additional IE
    00127     if (add_ie_len && (co_read8p(add_ie_buf) == MAC_ELTID_SUPP_OPER_CLASS))
    00128     {
    00129         // Copy the IE
    00130         ie_len = co_read8p(add_ie_buf + 1) + 2;
    00131         co_copy8p(ie_buf, add_ie_buf, ie_len);
    00132         ie_buf += ie_len;
    00133         add_ie_buf += ie_len;
    00134         add_ie_len -= ie_len;
    00135     }
    00136
    00137     // Now we put the HT capabilities
    00138     if (LOCAL_CAPA(HT))
    00139     {
    00140         me_add_ie_ht_capa(&ie_buf);
    00141     }
    00142
    00143     // And we copy the rest of the additional IEs
    00144     if (add_ie_len)
    00145     {
    00146         co_copy8p(ie_buf, add_ie_buf, add_ie_len);
    00147         ie_buf += add_ie_len;
    00148     }
    00149
    00150     #if NX_VHT
    00151     // Add the VHT capability information
    00152     if ((scanu_env.band == PHY_BAND_5G) && LOCAL_CAPA(VHT))
    00153     {
    00154         me_add_ie_vht_capa(&ie_buf);
    00155     }
    00156     #endif
    00157
    00158     #if NX_HE
    00159     // Add the HE capability information
    00160     if (LOCAL_CAPA(HE))
    00161     {
    00162         me_add_ie_he_capa(&ie_buf);
    00163     }
    00164     #endif
    00165
    00166     // Sanity check - we shall not have overflowed the IE buffer
    00167     ASSERT_ERR((ie_buf - CPU2HW(ie->buf)) <= SCAN_MAX_IE_LEN);
    00168
    00169     // Return the complete length
    00170     return (ie_buf - CPU2HW(ie->buf));
    00171 }
    00172
    00173
    00184 static void scanu_dma_cb(void *env, int dma_type)
    00185 {
    00186     // Scan the next requested band
    00187     scanu_scan_next();
    00188 }
    00189
    00190
    00198 static void scanu_ie_download(void)
    00199 {
    00200     struct scanu_start_req const *param = scanu_env.param;
    00201
    00202     // Check if we have an IE buffer for this band
    00203     if ((param->add_ies == 0) || (param->add_ie_len > SCANU_MAX_IE_LEN))
    00204     {
    00205         // Start the scan procedure immediately
    00206         scanu_scan_next();
    00207     }
    00208     else
    00209     {
    00210         struct scanu_add_ie_tag *ie_desc = &scanu_add_ie;
    00211         #if !NX_FULLY_HOSTED
    00212         struct dma_desc *hw_dma = &ie_desc->dma_desc;
    00213         struct hal_dma_desc_tag *gp_dma = &scanu_env.dma_desc;
    00214
    00215         // Initialization of the HW DMA descriptor
    00216         hw_dma->src = param->add_ies;
    00217         hw_dma->length = param->add_ie_len;
    00218
    00219         // Push the DMA request
    00220         hal_dma_push(gp_dma, DMA_DL);
    00221
    00222         #else
    00223
    00224         /* Platform DMA doesn't allow CPU to Shared mem transfer */
    00225         memcpy(ie_desc->buf, (void *)param->add_ies, param->add_ie_len);
    00226         scanu_scan_next();
    00227
    00228         #endif /* !NX_FULLY_HOSTED */
    00229     }
    00230 }
    00231
    00241 static void scanu_get_security_info(uint32_t ies, uint16_t ies_len, uint16_t capa,
    00242                                     struct mac_scan_result *res)
    00243 {
    00244     #if !NX_FULLY_HOSTED
    00245     // This information is not used in FullMAC firmware so no need to parse it
    00246     res->akm = 0;
    00247     res->group_cipher = 0;
    00248     res->pairwise_cipher = 0;
    00249
    00250     #else
    00251     uint32_t sec_ie;
    00252     uint8_t sec_ie_len;
    00253     int cnt, len;
    00254
    00255     res->akm = 0;
    00256     res->group_cipher = 0;
    00257     res->pairwise_cipher = 0;
    00258
    00259     if (!(capa & MAC_CAPA_PRIVA))
    00260     {
    00261         res->akm = CO_BIT(MAC_AKM_NONE);
    00262         return;
    00263     }
    00264
    00265     #define READ_CIPHER_SUITE(type)                                         \
    00266         {                                                                   \
    00267             int val = mac_cipher_suite_value(co_ntohl(co_read32p(sec_ie))); \
    00268             if (val > 0)                                                    \
    00269                 res->type |= CO_BIT(val);                                   \
    00270             sec_ie += 4;                                                    \
    00271             len -= 4;                                                       \
    00272          }
    00273
    00274     #define READ_AKM_SUITE()                                             \
    00275         {                                                                \
    00276             int val = mac_akm_suite_value(co_ntohl(co_read32p(sec_ie))); \
    00277             if (val > 0)                                                 \
    00278                 res->akm |= CO_BIT(val);                                 \
    00279             sec_ie += 4;                                                 \
    00280             len -= 4;                                                    \
    00281          }
    00282
    00283     #define READ_CNT()                          \
    00284         cnt = co_wtohs(co_read16p(sec_ie));     \
    00285         sec_ie += 2;                            \
    00286         len -= 2;
    00287
    00288     // First look for RSN Element
    00289     sec_ie = mac_ie_rsn_find(ies, ies_len, &sec_ie_len);
    00290     if (sec_ie)
    00291     {
    00292         uint16_t rsn_capa;
    00293
    00294         sec_ie += MAC_RSNIE_GROUP_CIPHER_OFT;
    00295         len = sec_ie_len + MAC_INFOELT_INFO_OFT - MAC_RSNIE_GROUP_CIPHER_OFT;
    00296
    00297         READ_CIPHER_SUITE(group_cipher);
    00298
    00299         READ_CNT();
    00300         while ((cnt > 0) && (len >= 4))
    00301         {
    00302             READ_CIPHER_SUITE(pairwise_cipher);
    00303             cnt--;
    00304         }
    00305
    00306         if (sec_ie_len < 2)
    00307             return;
    00308
    00309         READ_CNT();
    00310         while ((cnt > 0) && (len >= 4))
    00311         {
    00312             READ_AKM_SUITE();
    00313             cnt--;
    00314         }
    00315
    00316         if (len < 2)
    00317             return;
    00318
    00319         rsn_capa = co_wtohs(co_read16p(sec_ie));
    00320         sec_ie += 2;
    00321         len -= 2;
    00322
    00323         if (len >= 2)
    00324         {
    00325             READ_CNT();
    00326             sec_ie += MAC_RSNIE_RSN_PMKID_SIZE * cnt;
    00327             len -= MAC_RSNIE_RSN_PMKID_SIZE * cnt;
    00328         }
    00329
    00330         if (rsn_capa & (MAC_RSNIE_CAPA_MFPR_BIT | MAC_RSNIE_CAPA_MFPC_BIT))
    00331         {
    00332             if (len >= 4)
    00333             {
    00334                 READ_CIPHER_SUITE(group_cipher);
    00335             }
    00336             else
    00337             {
    00338                 res->group_cipher |= CO_BIT(MAC_CIPHER_BIP_CMAC_128);
    00339             }
    00340         }
    00341
    00342         return;
    00343     }
    00344
    00345     // Else look for WPA Element
    00346     sec_ie = mac_ie_wpa_find(ies, ies_len, &sec_ie_len);
    00347     if (sec_ie)
    00348     {
    00349         res->akm = CO_BIT(MAC_AKM_PRE_RSN);
    00350
    00351         sec_ie += MAC_WPA_GROUP_CIPHER_OFT;
    00352         len = sec_ie_len + MAC_INFOELT_INFO_OFT -  MAC_WPA_GROUP_CIPHER_OFT;
    00353
    00354         READ_CIPHER_SUITE(group_cipher);
    00355
    00356         READ_CNT();
    00357         while ((cnt > 0) && (len >= 4))
    00358         {
    00359             READ_CIPHER_SUITE(pairwise_cipher);
    00360             cnt--;
    00361         }
    00362
    00363         if (len < 2)
    00364             return;
    00365
    00366         READ_CNT();
    00367         while ((cnt > 0) && (len >= 4))
    00368         {
    00369             READ_AKM_SUITE();
    00370             cnt--;
    00371         }
    00372
    00373         return;
    00374     }
    00375
    00376     #if RW_WAPI_EN
    00377     // Last try WAPI Element
    00378     sec_ie = mac_ie_wapi_find(ies, ies_len, &sec_ie_len);
    00379     if (sec_ie)
    00380     {
    00381
    00382         sec_ie += MAC_WAPI_AKM_SUITE_CNT_OFT;
    00383         len = sec_ie_len + MAC_INFOELT_INFO_OFT - MAC_WAPI_AKM_SUITE_CNT_OFT;
    00384
    00385         READ_CNT();
    00386         while ((cnt > 0) && (len >= 4))
    00387         {
    00388             READ_AKM_SUITE();
    00389             cnt--;
    00390         }
    00391
    00392         if (len < 2)
    00393             return;
    00394
    00395         READ_CNT();
    00396         while ((cnt > 0) && (len >= 4))
    00397         {
    00398             READ_CIPHER_SUITE(pairwise_cipher);
    00399             cnt--;
    00400         }
    00401
    00402         if (len < 4)
    00403             return;
    00404
    00405         READ_CIPHER_SUITE(group_cipher);
    00406
    00407         return;
    00408     }
    00409     #endif // RW_WAPI_EN
    00410
    00411     // No 'Security' Element, assume WEP
    00412     res->akm = CO_BIT(MAC_AKM_PRE_RSN);
    00413     res->group_cipher = CO_BIT(MAC_CIPHER_WEP40);
    00414
    00415     #undef READ_CIPHER_SUITE
    00416     #undef READ_AKM_SUITE
    00417     #undef READ_CNT
    00418
    00419     #endif // NX_FULLY_HOSTED
    00420 }
    00421
    00437 static bool scanu_new_bssid_set(struct scanu_mbssid_profile_tag *mbssid,
    00438                                 uint8_t max_bss_ind,
    00439                                 struct mac_scan_result const *res)
    00440 {
    00441     struct mac_addr bssid;
    00442     struct mac_scan_result *new_res;
    00443     uint8_t ssid_len = mac_ie_len(mbssid->ssid_ie_addr) - MAC_INFOELT_INFO_OFT;
    00444
    00445     // Compute the nonTransmitted BSSID
    00446     if (!mac_nontxed_bssid_get(mbssid->bssid_index, max_bss_ind, &res->bssid, &bssid))
    00447         return false;
    00448
    00449     // Check if the element is already present
    00450     new_res = scanu_find_result(&bssid, false);
    00451     if (new_res)
    00452         return true;
    00453
    00454     // Allocate a new element for the BSSID
    00455     new_res = scanu_find_result(&bssid, true);
    00456     if (new_res == NULL)
    00457         return false;
    00458
    00459     // Copy the info about the new BSSID from the reference one
    00460     *new_res = *res;
    00461     // Copy the new BSSID specific information
    00462     new_res->bssid = bssid;
    00463     new_res->ssid.length = ssid_len;
    00464     co_unpack8p(new_res->ssid.array, mbssid->ssid_ie_addr + MAC_SSID_SSID_OFT, ssid_len);
    00465     new_res->max_bssid_indicator = max_bss_ind;
    00466     new_res->multi_bssid_index = mbssid->bssid_index;
    00467     scanu_env.result_cnt++;
    00468     new_res->valid_flag = true;
    00469
    00470     return true;
    00471 }
    00472
    00480 static void scanu_store_multi_bssid_info(struct mac_scan_result const *res)
    00481 {
    00482     struct scanu_mbssids_tag *mbssids = &scanu_env.mbssids;
    00483
    00484     for (int i = 0; i < mbssids->mbssid_cnt; i++)
    00485     {
    00486         if (!scanu_new_bssid_set(&mbssids->bssids[i], mbssids->max_bssid_ind, res))
    00487             return;
    00488     }
    00489 }
    00490
    00506 static void scanu_get_multi_bssid_info(uint32_t ies, uint16_t ies_len)
    00507 {
    00508     uint32_t capa_addr = 0;
    00509     uint32_t bssid_index_ie_addr = 0;
    00510     uint32_t ssid_ie_addr = 0;
    00511     uint8_t ssid_len;
    00512     struct scanu_mbssids_tag *mbssids = &scanu_env.mbssids;
    00513     mbssids->mbssid_cnt = 0;
    00514
    00515     while (ies_len)
    00516     {
    00517         uint32_t mbssid_ie_addr;
    00518         uint32_t mbssid_ie_len;
    00519         uint32_t sub_ie_addr;
    00520         uint32_t sub_ie_len;
    00521         uint32_t sub_ies;
    00522         uint16_t subies_len;
    00523         uint32_t bssid_ies;
    00524         uint16_t bssid_ies_len;
    00525
    00526         // Try to get a Multiple BSSID element
    00527         mbssid_ie_addr = mac_ie_multi_bssid_find(ies, ies_len);
    00528         if (!mbssid_ie_addr)
    00529             return;
    00530
    00531         mbssid_ie_len = mac_ie_len(mbssid_ie_addr);
    00532         mbssids->max_bssid_ind = co_read8p(mbssid_ie_addr + MAC_MULTI_BSSID_MAX_INDICATOR_OFT);
    00533         sub_ies = mbssid_ie_addr + MAC_MULTI_BSSID_SUB_IES_OFT;
    00534         subies_len = mbssid_ie_len - MAC_MULTI_BSSID_SUB_IES_OFT;
    00535
    00536         while (subies_len)
    00537         {
    00538             // A Multiple BSSID element has been found, search for a nonTransmittedBSSID
    00539             // profile inside it
    00540             sub_ie_addr = mac_ie_sub_non_txed_bssid_find(sub_ies, subies_len);
    00541             if (!sub_ie_addr)
    00542                 break;
    00543
    00544             sub_ie_len = mac_ie_len(sub_ie_addr);
    00545             bssid_ies = sub_ie_addr + MAC_MBSSID_NON_TXED_PROF_INFO_OFT;
    00546             bssid_ies_len = sub_ie_len - MAC_MBSSID_NON_TXED_PROF_INFO_OFT;
    00547             sub_ies += sub_ie_len;
    00548             subies_len -= sub_ie_len;
    00549
    00550             // Check if this is the start of a BSS profile - To do that we check if the
    00551             // nonTransmitted BSSID capability element is the first of the sub-element
    00552             if (mac_ie_non_txed_bssid_capa_find(bssid_ies, MAC_NON_TXED_BSSID_CAPA_LEN))
    00553             {
    00554                 // New BSS profile, restart the search for both the BSSID index and SSID
    00555                 capa_addr = bssid_ies + MAC_NON_TXED_BSSID_CAPA_OFT;
    00556                 bssid_index_ie_addr = 0;
    00557                 ssid_ie_addr = 0;
    00558             }
    00559             else if (!capa_addr)
    00560                 continue;
    00561
    00562             // Now search for the BSSID index and SSID
    00563             if (!bssid_index_ie_addr)
    00564                 bssid_index_ie_addr = mac_ie_multi_bssid_index_find(bssid_ies, bssid_ies_len);
    00565             if (!ssid_ie_addr)
    00566                 ssid_ie_addr = mac_ie_ssid_find(bssid_ies, bssid_ies_len, &ssid_len);
    00567
    00568             // Check if we have all the info related to the nonTransmitted BSSID and
    00569             // configure it
    00570             if (bssid_index_ie_addr && ssid_ie_addr)
    00571             {
    00572                 struct scanu_mbssid_profile_tag *mbssid = &mbssids->bssids[mbssids->mbssid_cnt];
    00573                 mbssid->bssid_index = co_read8p(bssid_index_ie_addr + MAC_MULTI_BSSID_INDEX_OFT);
    00574                 mbssid->ssid_ie_addr = ssid_ie_addr;
    00575                 mbssid->capa = co_read16p(capa_addr);
    00576                 mbssids->mbssid_cnt++;
    00577                 if (mbssids->mbssid_cnt == SCANU_MAX_NONTXED_BSSID_PER_BEACON)
    00578                     return;
    00579                 capa_addr = 0;
    00580             }
    00581         }
    00582         ies += mbssid_ie_len;
    00583         ies_len -= mbssid_ie_len;
    00584     }
    00585 }
    00586
    00597 static bool scanu_is_scanned_ssid(struct mac_ssid *ssid)
    00598 {
    00599     struct scanu_start_req const *param = scanu_env.param;
    00600     int i;
    00601
    00602     #if (NX_P2P)
    00603     if (scanu_env.p2p_scan)
    00604     {
    00605         if (!memcmp(&ssid->array[0], P2P_SSID_WILDCARD, P2P_SSID_WILDCARD_LEN))
    00606             return true;
    00607     }
    00608     else
    00609     #endif //(NX_P2P)
    00610     {
    00611         // Check if the SSID is one we are looking for
    00612         if (!param->ssid_cnt)
    00613             // No SSID specifically searched, so consider this one as valid
    00614             return true;
    00615
    00616         for (i = 0; i < param->ssid_cnt; i++)
    00617         {
    00618             struct mac_ssid const *scanned_ssid = &param->ssid[i];
    00619             if ((scanned_ssid->length == 0) || (MAC_SSID_CMP(scanned_ssid, ssid)))
    00620                 // Received SSID is an expected one
    00621                 return true;
    00622         }
    00623     }
    00624
    00625     return false;
    00626 }
    00627
    00641 static bool scanu_check_ssid(struct mac_scan_result *res)
    00642 {
    00643     struct scanu_mbssids_tag *mbssids = &scanu_env.mbssids;
    00644
    00645     // Check if the SSID matches one we are looking for
    00646     if (scanu_is_scanned_ssid(&res->ssid))
    00647         // SSID matches, exit immediately
    00648         return true;
    00649
    00650     // Main SSID does not match, check if there is some nonTransmitted BSSID profiles present
    00651     // that would match a searched SSID
    00652     for (int i = 0; i < mbssids->mbssid_cnt; i++)
    00653     {
    00654         struct scanu_mbssid_profile_tag *mbssid = &mbssids->bssids[i];
    00655         struct mac_ssid ssid;
    00656
    00657         ssid.length = mac_ie_len(mbssid->ssid_ie_addr) - MAC_INFOELT_INFO_OFT;
    00658         co_unpack8p(ssid.array, mbssid->ssid_ie_addr + MAC_SSID_SSID_OFT, ssid.length);
    00659
    00660         // Check if the SSID matches one we are looking for
    00661         if (scanu_is_scanned_ssid(&ssid))
    00662             // SSID matches, exit immediately
    00663             return true;
    00664     }
    00665
    00666     return false;
    00667
    00668 }
    00669
    00684 static int scanu_join_frame_handler(struct rxu_mgt_ind const *frame)
    00685 {
    00686     struct mac_scan_result *scan;
    00687     struct scanu_start_req const *param = scanu_env.param;
    00688     uint32_t var_part_addr, var_part_len;
    00689     uint32_t ht_op_addr = 0, vht_op_addr = 0;
    00690     struct bcn_frame const *frm = (struct bcn_frame const *)frame->payload;
    00691     struct vif_info_tag *vif = &vif_info_tab[param->vif_idx];
    00692     struct me_bss_info *bss = &vif->bss_info;
    00693     bool changed;
    00694
    00695     // We are in the join process, so the received BSSID shall correspond either to the
    00696     // BSSID we join to, or the reference BSSID in case of Multiple BSSID
    00697     if (!MAC_ADDR_CMP(&frm->h.addr3, &scanu_env.bssid) &&
    00698         !MAC_ADDR_CMP(&frm->h.addr3, &scanu_env.ref_bssid))
    00699         return KE_MSG_CONSUMED;
    00700
    00701     // find the scan result associated to the BSSID
    00702     scan = scanu_find_result(&scanu_env.bssid, false);
    00703     if (scan == NULL)
    00704         return KE_MSG_CONSUMED;
    00705
    00706     // Initialize the variable part address
    00707     var_part_addr = CPU2HW(frm->variable);
    00708     var_part_len = frame->length - MAC_BEACON_VARIABLE_PART_OFT;
    00709
    00710     // Initialize EDCA parameter set count to an invalid value to ensure that we
    00711     // will retrieve the EDCA parameters at least once
    00712     #if NX_HE
    00713     bss->mu_edca_param.param_set_cnt = 0xFF;
    00714     #endif
    00715     bss->edca_param.param_set_cnt = 0xFF;
    00716
    00717     // Copy some parameters from the scan result
    00718     bss->bsstype = scan->bsstype;
    00719     bss->bssid = scan->bssid;
    00720     bss->beacon_period = frm->bcnint;
    00721     bss->ssid = scan->ssid;
    00722     bss->chan.band = scan->chan->band;
    00723     bss->chan.prim20_freq = scan->chan->freq;
    00724     bss->chan.tx_power = scan->chan->tx_power;
    00725     bss->chan.flags = scan->chan->flags;
    00726     bss->bssid_index = scan->multi_bssid_index;
    00727     bss->max_bssid_ind = scan->max_bssid_indicator;
    00728     // chan bandwidth info is updated by me_bw_check
    00729     BSS_CAPA_RESET(bss);
    00730
    00731     // retrieve the rate set (normal + extended)
    00732     me_extract_rate_set(var_part_addr, var_part_len, &(bss->rate_set));
    00733     if (scan->chan->band == PHY_BAND_2G4)
    00734     {
    00735         uint32_t basic_11b_rates;
    00736         basic_11b_rates = me_legacy_rate_bitfield_build(&(bss->rate_set), true) & 0x0F;
    00737         // Get highest allowed 11b rate
    00738         if (basic_11b_rates)
    00739             // Get highest allowed 11b rate
    00740             bss->high_11b_rate = 31 - co_clz(basic_11b_rates);
    00741         else
    00742             // If no 11b basic rates, set the highest mandatory one
    00743             bss->high_11b_rate = HW_RATE_2MBPS;
    00744     }
    00745
    00746     // retrieve the EDCA Parameter
    00747     if (me_extract_edca_params(var_part_addr, var_part_len, &bss->edca_param,
    00748                                &changed))
    00749     {
    00750         BSS_CAPA_SET(bss, QOS);
    00751     }
    00752
    00753     // retrieve the HT/VHT/HE Capability
    00754     if (LOCAL_CAPA(HT) && BSS_CAPA(bss, QOS) &&
    00755         me_extract_ht_capa(var_part_addr, var_part_len, &bss->ht_cap))
    00756     {
    00757         BSS_CAPA_SET(bss, HT);
    00758         // retrieve the HT operation field
    00759         ht_op_addr = mac_ie_ht_oper_find(var_part_addr, var_part_len);
    00760
    00761         #if NX_HE
    00762         if (LOCAL_CAPA(HE) &&
    00763             me_extract_he_capa(var_part_addr, var_part_len, &bss->he_cap))
    00764         {
    00765             BSS_CAPA_SET(bss, HE);
    00766
    00767             // retrieve the HE operation field
    00768             me_extract_he_oper(var_part_addr, var_part_len, bss);
    00769         }
    00770         #endif
    00771
    00772         #if NX_VHT
    00773         // We get the VHT elements in two cases:
    00774         //  - Either we are VHT capable
    00775         //  - Or we are HE capable and the BSS is a HE one. Indeed in that case
    00776         //    some VHT parameters (BW, A-MDPU max size, MDPU max size, etc.)
    00777         //    apply to the HE as well
    00778         if ((LOCAL_CAPA(VHT) || BSS_CAPA(bss, HE)) &&
    00779             me_extract_vht_capa(var_part_addr, var_part_len, &bss->vht_cap))
    00780         {
    00781             BSS_CAPA_SET(bss, VHT);
    00782             // retrieve the VHT operation field
    00783             vht_op_addr = mac_ie_vht_oper_find(var_part_addr, var_part_len);
    00784         }
    00785         #endif
    00786     }
    00787
    00788     // Initialize the BW and channel parameters
    00789     me_bw_check(ht_op_addr, vht_op_addr, bss);
    00790
    00791     // Get power constraint
    00792     me_extract_power_constraint(var_part_addr, var_part_len, bss);
    00793
    00794     // Get regulatory rules
    00795     me_extract_country_reg(var_part_addr, var_part_len, bss);
    00796
    00797     // Initialize TX power
    00798     tpc_update_vif_tx_power(vif);
    00799
    00800     // Get Mobility Domain ID and FT capability and policy
    00801     me_extract_mobility_domain(var_part_addr, var_part_len, bss);
    00802
    00803     // We consider now the BSS information as valid
    00804     BSS_CAPA_SET(bss, VALID);
    00805
    00806     // Set join_status success
    00807     scanu_env.join_status = 1;
    00808
    00809     return KE_MSG_CONSUMED;
    00810 }
    00811
    00826 static int scanu_scan_frame_handler(struct rxu_mgt_ind const *frame)
    00827 {
    00828     struct mac_scan_result *scan;
    00829     uint32_t elmt_addr, var_part_addr, var_part_len;
    00830     struct bcn_frame const *frm = (struct bcn_frame const *)frame->payload;
    00831     uint8_t elmt_length;
    00832     struct mac_addr const *bssid = &frm->h.addr3;
    00833
    00834     // check if the scan frame matches the SCAN requested BSSID
    00835     if (!MAC_ADDR_GROUP(&scanu_env.bssid) &&
    00836         !MAC_ADDR_CMP(bssid, &scanu_env.bssid))
    00837         return KE_MSG_CONSUMED;
    00838
    00839     // find a scan result that has the same BSSID (or allocate it)
    00840     scan = scanu_find_result(bssid, true);
    00841     if (scan == NULL)
    00842         return KE_MSG_CONSUMED;
    00843
    00844     // copy the BSSID
    00845     MAC_ADDR_CPY(&scan->bssid, bssid);
    00846
    00847     // ESS or IBSS
    00848     if ((frm->capa & MAC_CAPA_ESS) == MAC_CAPA_ESS)
    00849         scan->bsstype = INFRASTRUCTURE_MODE;
    00850     else
    00851         scan->bsstype = INDEPENDENT_BSS_MODE;
    00852
    00853     // Initialize the variable part address
    00854     var_part_addr = CPU2HW(frm->variable);
    00855     var_part_len = frame->length - MAC_BEACON_VARIABLE_PART_OFT;
    00856
    00857     // retrieve the SSID if broadcasted
    00858     elmt_addr = mac_ie_ssid_find(var_part_addr, var_part_len, &elmt_length);
    00859     if (elmt_addr != 0)
    00860     {
    00861         scan->ssid.length = elmt_length;
    00862         // copy the SSID length
    00863         co_unpack8p(scan->ssid.array, elmt_addr + MAC_SSID_SSID_OFT, elmt_length);
    00864     }
    00865     else
    00866     {
    00867         // SSID is not broadcasted
    00868         scan->ssid.length = 0;
    00869     }
    00870
    00871     // Get potential information about Multi-BSSID, in order to retrieve the SSIDs
    00872     scanu_get_multi_bssid_info(var_part_addr, var_part_len);
    00873
    00874     // Check if the found SSID matches the searched ones
    00875     if (!scanu_check_ssid(scan))
    00876         return KE_MSG_CONSUMED;
    00877
    00878     // retrieve the channel
    00879     elmt_addr = mac_ie_ds_find(var_part_addr, var_part_len);
    00880     if (elmt_addr != 0)
    00881     {
    00882         uint8_t ch_nbr = co_read8p(elmt_addr + MAC_DS_CHANNEL_OFT);
    00883         scan->chan = me_freq_to_chan_ptr(frame->band,
    00884                                          phy_channel_to_freq(frame->band, ch_nbr));
    00885         // check if the RSSI of the received beacon is greater than the previous one
    00886         if (frame->rssi > scan->rssi)
    00887         {
    00888             scan->rssi = frame->rssi;
    00889         }
    00890     }
    00891     else
    00892     {
    00893         // check if the RSSI of the received beacon is greater than the previous one
    00894         if (frame->rssi > scan->rssi)
    00895         {
    00896             scan->chan = me_freq_to_chan_ptr(frame->band, frame->center_freq);
    00897             scan->rssi = frame->rssi;
    00898         }
    00899     }
    00900
    00901     scanu_get_security_info(var_part_addr, var_part_len, frm->capa, scan);
    00902
    00903     // check if the element was already allocated
    00904     if (!scan->valid_flag)
    00905     {
    00906         // one more scan result is saved
    00907         scanu_env.result_cnt++;
    00908     }
    00909
    00910     // Set the valid_flag
    00911     scan->valid_flag = true;
    00912
    00913     // We have to do that after validating the scan element because this function
    00914     // may allocate new scan elements
    00915     scanu_store_multi_bssid_info(scan);
    00916
    00917     ke_msg_forward_and_change_id(frame, SCANU_RESULT_IND, TASK_API, TASK_SCANU);
    00918
    00919     return KE_MSG_NO_FREE;
    00920 }
    00921
    00922 void scanu_confirm(uint8_t status)
    00923 {
    00924     struct scanu_start_cfm* cfm;
    00925     // allocate message
    00926     if (scanu_env.joining)
    00927         cfm = KE_MSG_ALLOC(SCANU_JOIN_CFM, scanu_env.src_id, TASK_SCANU, scanu_start_cfm);
    00928     else
    00929     {
    00930         #if (NX_ANT_DIV)
    00931         ke_msg_send_basic(MM_ANT_DIV_UPDATE_REQ, TASK_MM, TASK_SCANU);
    00932         #endif //(NX_ANT_DIV)
    00933         cfm = KE_MSG_ALLOC(SCANU_START_CFM, scanu_env.src_id, TASK_SCANU, scanu_start_cfm);
    00934     }
    00935     // fill in the message parameters
    00936     cfm->vif_idx = scanu_env.param->vif_idx;
    00937     cfm->status = status;
    00938     cfm->result_cnt = scanu_env.result_cnt;
    00939
    00940     // Free the scan parameters structure
    00941     ke_msg_free(ke_param2msg(scanu_env.param));
    00942     scanu_env.param = NULL;
    00943
    00944     // send the message to the sender
    00945     ke_msg_send(cfm);
    00946
    00947     // move to IDLE state
    00948     ke_state_set(TASK_SCANU, SCANU_IDLE);
    00949 }
    00950
    00951 void scanu_init(void)
    00952 {
    00953     struct scanu_add_ie_tag *ie_desc = &scanu_add_ie;
    00954     struct hal_dma_desc_tag *gp_dma = &scanu_env.dma_desc;
    00955
    00956     // set the state of the task to default
    00957     ke_state_set(TASK_SCANU, SCANU_IDLE);
    00958
    00959     // reset the SCAN environment
    00960     memset(&scanu_env, 0, sizeof(scanu_env));
    00961
    00962     // Initialization of the GP DMA descriptor
    00963     gp_dma->cb = scanu_dma_cb;
    00964     gp_dma->env = NULL;
    00965     gp_dma->dma_desc = &ie_desc->dma_desc;
    00966
    00967     // Initialization of the HW DMA descriptor
    00968     ie_desc->dma_desc.dest = CPU2HW(ie_desc->buf);
    00969 }
    00970
    00971 int scanu_frame_handler(struct rxu_mgt_ind const *frame)
    00972 {
    00973     // Check if we are in a scanning process
    00974     if (ke_state_get(TASK_SCANU) != SCANU_SCANNING)
    00975         return KE_MSG_CONSUMED;
    00976
    00977     if (scanu_env.joining)
    00978         return scanu_join_frame_handler(frame);
    00979     else
    00980         return scanu_scan_frame_handler(frame);
    00981 }
    00982
    00983 struct mac_scan_result *scanu_find_result(struct mac_addr const *bssid_ptr,
    00984                                           bool allocate)
    00985 {
    00986     uint8_t i=0;
    00987     struct mac_scan_result* scan_rslt = NULL;
    00988
    00989     // search in the scan list using the MAC address
    00990     for (i = 0; i < SCANU_MAX_RESULTS; i++)
    00991     {
    00992         struct mac_scan_result *scan = &scanu_env.scan_result[i];
    00993
    00994         // if it is a valid BSS.
    00995         if (scan->valid_flag)
    00996         {
    00997             if (MAC_ADDR_CMP(&scan->bssid, bssid_ptr))
    00998             {
    00999                 // required BSS found
    01000                 scan_rslt = scan;
    01001                 break;
    01002             }
    01003         }
    01004         else if (allocate)
    01005         {
    01006             // empty entry: if allocation was requested, then return this pointer
    01007             scan_rslt = scan;
    01008             break;
    01009         }
    01010     }
    01011     return (scan_rslt);
    01012 }
    01013
    01014 struct mac_scan_result *scanu_search_by_bssid(struct mac_addr const *bssid)
    01015 {
    01016     return (scanu_find_result(bssid, false));
    01017 }
    01018
    01019 struct mac_scan_result *scanu_search_by_ssid(struct mac_ssid const *ssid)
    01020 {
    01021     uint8_t i=0;
    01022     int8_t rssi = ~0x7F;
    01023     struct mac_scan_result* scan_rslt = NULL;
    01024
    01025     do
    01026     {
    01027         // Check if the SSID is valid
    01028         if (!ssid->length)
    01029             break;
    01030
    01031         // Search in the scan list using the SSID. If several BSSes share the same SSID,
    01032         // the one with the highest RSSI will be returned.
    01033         for (i = 0; i < SCANU_MAX_RESULTS; i++)
    01034         {
    01035             struct mac_scan_result *scan = &scanu_env.scan_result[i];
    01036
    01037             // Check if it is a valid BSS.
    01038             if (!scan->valid_flag)
    01039                 break;
    01040
    01041             // Check if the SSID is matching and if the RSSI is greater than the previous
    01042             // one that was found
    01043             if ((scan->rssi > rssi) && (MAC_SSID_CMP(&scan->ssid, ssid)))
    01044             {
    01045                 scan_rslt = scan;
    01046                 rssi = scan->rssi;
    01047             }
    01048         }
    01049     } while(0);
    01050
    01051     return (scan_rslt);
    01052 }
    01053
    01054 void scanu_start(void)
    01055 {
    01056     int i;
    01057
    01058     if (!scanu_env.joining)
    01059     {
    01060         // reset the scan results before starting a new scan
    01061         memset(scanu_env.scan_result, 0, sizeof(scanu_env.scan_result));
    01062         for (i = 0; i < SCANU_MAX_RESULTS; i++)
    01063         {
    01064             scanu_env.scan_result[i].rssi = ~0x7F;
    01065         }
    01066
    01067         // reset the valid result counter
    01068         scanu_env.result_cnt = 0;
    01069     }
    01070
    01071     #if (NX_P2P)
    01072     if ((scanu_env.param->ssid_cnt == 1) && (scanu_env.param->ssid[0].length == P2P_SSID_WILDCARD_LEN) &&
    01073          !memcmp(&scanu_env.param->ssid[0].array[0], P2P_SSID_WILDCARD, P2P_SSID_WILDCARD_LEN))
    01074     {
    01075         scanu_env.p2p_scan = true;
    01076     }
    01077     else
    01078     {
    01079         scanu_env.p2p_scan = false;
    01080     }
    01081     #endif //(NX_P2P)
    01082
    01083     // move to SCANNING state (done before scanu_next because it could reset the state)
    01084     ke_state_set(TASK_SCANU, SCANU_SCANNING);
    01085
    01086     // Download the additional IE if available
    01087     scanu_ie_download();
    01088 }
    01089
    01090 void scanu_scan_next(void)
    01091 {
    01092     int i;
    01093     struct scanu_start_req const *param = scanu_env.param;
    01094     struct scan_start_req *req;
    01095
    01096     do
    01097     {
    01098         // Check if we scanned all the requested bands
    01099         if (scanu_env.band > PHY_BAND_5G)
    01100             break;
    01101
    01102         // Go through the list of channels to find the first channel to be scanned
    01103         for (i = 0; i < param->chan_cnt; i++)
    01104         {
    01105             if (param->chan[i].band == scanu_env.band)
    01106                 break;
    01107         }
    01108
    01109         // Check if we have at least one channel to scan
    01110         if (i == param->chan_cnt)
    01111         {
    01112             scanu_env.band++;
    01113             continue;
    01114         }
    01115
    01116         // Allocate the scan request for the LMAC
    01117         req = KE_MSG_ALLOC(SCAN_START_REQ, TASK_SCAN, TASK_SCANU, scan_start_req);
    01118
    01119         // Fill-in the request
    01120         req->vif_idx = param->vif_idx;
    01121         req->bssid = param->bssid;
    01122         req->ssid_cnt = param->ssid_cnt;
    01123         req->no_cck = param->no_cck;
    01124
    01125         // Prepare the channel list
    01126         for (; i < param->chan_cnt; i++)
    01127         {
    01128             // Check if the current channel is on the band we have to scan
    01129             if (param->chan[i].band == scanu_env.band)
    01130             {
    01131                 req->chan[req->chan_cnt] = param->chan[i];
    01132                 req->chan_cnt++;
    01133             }
    01134         }
    01135         // Prepare the SSIDs
    01136         for (i = 0; i < param->ssid_cnt; i++)
    01137         {
    01138             req->ssid[i] = param->ssid[i];
    01139         }
    01140
    01141         // Prepare the IE buffer
    01142         req->add_ie_len = scanu_build_ie();
    01143         req->add_ies = 0;
    01144
    01145         // send a scan start request
    01146         ke_msg_send(req);
    01147
    01148         return;
    01149     } while(1);
    01150
    01151     // Scan is done
    01152     scanu_confirm(CO_OK);
    01153 }
    01154
    01156