- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

# /space/home/slher/rel/Beken/v6_4_5/macsw/ip/lmac/src/p2p/p2p.c

Go to the documentation of this file.

    00001
    00019 /*
    00020  * INCLUDE FILES
    00021  ****************************************************************************************
    00022  */
    00023
    00024 #include "p2p.h"
    00025
    00026 #if (NX_P2P)
    00027
    00028 #include "mac_ie.h"
    00029 #include "ps.h"
    00030 #include "mm.h"
    00031 #include "mm_bcn.h"
    00032 #include "vif_mgmt.h"
    00033
    00034 #if (NX_P2P_GO)
    00035 #include "td.h"
    00036 #endif //(NX_P2P_GO)
    00037
    00038 /*
    00039  * GLOBAL VARIABLES DECLARATION
    00040  ****************************************************************************************
    00041  */
    00042
    00043 #if (NX_P2P_GO)
    00044 struct p2p_env_tag p2p_env;
    00045 #endif //(NX_P2P_GO)
    00046
    00047 struct p2p_info_tag p2p_info_tab[NX_P2P_VIF_MAX];
    00048
    00049 /*
    00050  * PRIVATE FUNCTIONS DECLARATION
    00051  ****************************************************************************************
    00052  */
    00053
    00054 __INLINE void p2p_go_noa_get_intv_cnt(struct p2p_noa_info_tag *noa);
    00055 static void p2p_cli_noa_cancel(struct p2p_noa_info_tag *noa);
    00056
    00057 /*
    00058  * PRIVATE FUNCTIONS
    00059  ****************************************************************************************
    00060  */
    00061
    00071 static inline uint32_t p2p_local_2_peer_time(struct vif_info_tag *vif, uint32_t local_time)
    00072 {
    00073     ASSERT_ERR(vif->type == VIF_STA);
    00074     return local_time + vif->u.sta.last_tsf_offset;
    00075 }
    00076
    00086 static inline uint32_t p2p_peer_2_local_time(struct vif_info_tag *vif, uint32_t peer_time)
    00087 {
    00088     ASSERT_ERR(vif->type == VIF_STA);
    00089     return peer_time - vif->u.sta.last_tsf_offset;
    00090 }
    00091
    00104 static uint32_t p2p_att_find(uint32_t ie_addr, uint16_t ie_total_len, uint8_t att_id)
    00105 {
    00106     uint32_t ie_end = ie_addr + ie_total_len;
    00107
    00108     // Loop as long as we do not go beyond the frame size
    00109     while (ie_addr < ie_end)
    00110     {
    00111         // Check if the current Attrbute ID is the one looked for
    00112         if (att_id == co_read8p(ie_addr))
    00113         {
    00114             // The Attribute ID matches, return the address of the element
    00115             return (ie_addr);
    00116         }
    00117
    00118         // Move on to the next attribute
    00119         ie_addr += co_read16p(ie_addr + P2P_ATT_LEN_OFT) + P2P_ATT_BODY_OFT;
    00120     }
    00121
    00122     return (0);
    00123 }
    00124
    00130 static void p2p_goto_idle_cb(void)
    00131 {
    00132     TRACE_P2P(PS, "HW is now in IDLE, can flush TX/RX queues");
    00133
    00134     // Flush all the TX and RX queues
    00135     mm_force_idle_req();
    00136
    00137     // Go back to ACTIVE state
    00138     mm_active();
    00139 }
    00140
    00153 static bool p2p_noa_wait_end_abs(struct p2p_info_tag *p2p, uint8_t *low_noa_count)
    00154 {
    00155     uint8_t noa_idx;
    00156     bool wait_end_abs = false;
    00157     *low_noa_count = 255;
    00158
    00159     for (noa_idx = 0; noa_idx < P2P_NOA_NB_MAX; noa_idx++)
    00160     {
    00161         struct p2p_noa_info_tag *noa = &p2p->noa[noa_idx];
    00162         if ((noa->noa_status == P2P_NOA_TIMER_WAIT_END_ABS)
    00163             #if (NX_P2P_GO)
    00164             && !(p2p->noa_paused && noa->dyn_noa && (noa->noa_type == P2P_NOA_TYPE_NORMAL))
    00165             #endif //(NX_P2P_GO)
    00166             )
    00167         {
    00168             wait_end_abs = true;
    00169             if (noa->noa_init_counter < *low_noa_count)
    00170             {
    00171                 *low_noa_count = noa->noa_init_counter;
    00172             }
    00173         }
    00174     }
    00175
    00176     return (wait_end_abs);
    00177 }
    00178
    00190 static void p2p_update_noa_presence_date(struct p2p_info_tag *p2p)
    00191 {
    00192     bool first_noa = true;
    00193     bool no_next_absent = true;
    00194     uint32_t in_progress = 0;
    00195     uint32_t next_present = 0;
    00196     uint32_t next_absent = 0;
    00197     struct p2p_noa_info_tag *noa;
    00198     uint32_t absent, present;
    00199
    00200     // First pass only active NOA with counter == 1
    00201     for (noa = &p2p->noa[0]; noa < &p2p->noa[P2P_NOA_NB_MAX]; noa++)
    00202     {
    00203         if ((noa->noa_status != P2P_NOA_TIMER_WAIT_END_ABS) || (noa->noa_counter > 1)
    00204             #if (NX_P2P_GO)
    00205             || (p2p->noa_paused && noa->dyn_noa && (noa->noa_type == P2P_NOA_TYPE_NORMAL))
    00206             #endif //(NX_P2P_GO)
    00207             )
    00208             continue;
    00209
    00210         present = noa->noa_timer.time;
    00211
    00212         if (first_noa)
    00213         {
    00214             next_present = present;
    00215             first_noa = false;
    00216         }
    00217         else if (hal_machw_time_cmp(next_present, present))
    00218         {
    00219             next_present = present;
    00220         }
    00221         in_progress++;
    00222     }
    00223
    00224     // second pass only active periodic NOA
    00225     for (noa = &p2p->noa[0]; noa < &p2p->noa[P2P_NOA_NB_MAX]; noa++)
    00226     {
    00227         if ((noa->noa_status != P2P_NOA_TIMER_WAIT_END_ABS) || (noa->noa_counter <= 1)
    00228             #if (NX_P2P_GO)
    00229             || (p2p->noa_paused && noa->dyn_noa && (noa->noa_type == P2P_NOA_TYPE_NORMAL))
    00230             #endif //(NX_P2P_GO)
    00231             )
    00232             continue;
    00233
    00234         present = noa->noa_timer.time;
    00235         absent = present + noa->noa_intv_us - noa->noa_dur_us;
    00236
    00237         if (first_noa)
    00238         {
    00239             next_present = present;
    00240             next_absent = absent;
    00241             no_next_absent = false;
    00242             first_noa = false;
    00243         }
    00244         else
    00245         {
    00246             int counter = noa->noa_counter;
    00247             while (hal_machw_time_cmp(absent, next_present) && --counter)
    00248             {
    00249                 absent += noa->noa_intv_us;
    00250                 present += noa->noa_intv_us;
    00251             }
    00252             if (!counter)
    00253                 continue;
    00254
    00255             if (hal_machw_time_cmp(next_present, present))
    00256                 next_present = present;
    00257
    00258             if ((counter > 1) &&
    00259                 (no_next_absent || hal_machw_time_cmp(absent, next_absent)))
    00260             {
    00261                 next_absent = absent;
    00262                 no_next_absent = false;
    00263             }
    00264         }
    00265         in_progress++;
    00266     }
    00267
    00268     // last pass non active NOA
    00269     for (noa = &p2p->noa[0]; noa < &p2p->noa[P2P_NOA_NB_MAX]; noa++)
    00270     {
    00271         if (noa->noa_status != P2P_NOA_TIMER_WAIT_NEXT_ABS)
    00272             continue;
    00273
    00274         absent = noa->noa_timer.time;
    00275         present = absent + noa->noa_dur_us;
    00276
    00277         if (first_noa)
    00278         {
    00279             next_present = present;
    00280             next_absent = absent;
    00281             no_next_absent = false;
    00282             first_noa = false;
    00283         }
    00284         else if (in_progress)
    00285         {
    00286             // Merge active NOA and non active NOA
    00287             int counter = noa->noa_counter;
    00288             while (hal_machw_time_cmp(present, next_present) && counter--)
    00289             {
    00290                 absent += noa->noa_intv_us;
    00291                 present += noa->noa_intv_us;
    00292             }
    00293             if (counter < 0)
    00294                 continue;
    00295
    00296             if (no_next_absent)
    00297             {
    00298                 if (hal_machw_time_cmp(next_present, absent))
    00299                 {
    00300                     next_absent = absent;
    00301                     no_next_absent = false;
    00302                 }
    00303                 else
    00304                 {
    00305                     next_present = present;
    00306                     if (counter > 0)
    00307                     {
    00308                         next_absent = absent + noa->noa_intv_us;
    00309                         no_next_absent = false;
    00310                     }
    00311                 }
    00312             }
    00313             else if (hal_machw_time_cmp(next_absent, absent))
    00314             {
    00315                 // nothing to update
    00316             }
    00317             else if (hal_machw_time_cmp(next_present, absent))
    00318             {
    00319                 next_absent = absent;
    00320             }
    00321             else if (hal_machw_time_cmp(present, next_absent))
    00322             {
    00323                 next_present = present;
    00324                 absent += noa->noa_intv_us;
    00325                 if ((counter > 1) &&
    00326                     hal_machw_time_cmp(absent, next_absent))
    00327                     next_absent = absent;
    00328             }
    00329             else
    00330             {
    00331                 // This NOA overlap current [next_present .. next_absent] interval
    00332                 // Would need a new pass to find correct next_present/next_absent
    00333                 ASSERT_WARN(0);
    00334                 next_present = present;
    00335                 next_absent = absent + noa->noa_intv_us;
    00336             }
    00337         }
    00338         else
    00339         {
    00340             // Merge only non active NOA.
    00341             if (hal_machw_time_cmp(present, next_absent))
    00342             {
    00343                 // This NOA ends before current [next_absent .. next_present] interval
    00344                 next_present = present;
    00345                 next_absent = absent;
    00346             }
    00347             else if (hal_machw_time_cmp(next_present, absent))
    00348             {
    00349                 // nothing to update, as this NOA starts after curretn interval
    00350             }
    00351             else
    00352             {
    00353                 // NOA overlap with current [next_absent .. next_present] interval
    00354                 if (hal_machw_time_cmp(absent, next_absent))
    00355                     next_absent = absent;
    00356                 if (hal_machw_time_cmp(next_present, present))
    00357                     next_present = present;
    00358             }
    00359         }
    00360     }
    00361
    00362     p2p->next_present = next_present;
    00363     if (no_next_absent)
    00364         p2p->next_absent = next_present + 10;
    00365     else
    00366         p2p->next_absent = next_absent;
    00367 }
    00368
    00379 static void p2p_update_go_ps_state(struct p2p_info_tag *p2p)
    00380 {
    00381     bool is_go_present = true;
    00382     bool tbtt_in_noa = false;
    00383     uint8_t low_noa_count;
    00384
    00385     if (p2p_noa_wait_end_abs(p2p, &low_noa_count))
    00386     {
    00387         // At least one NOA is in progress,
    00388         // The order of precedence for determining P2P Group Owner power save state shall
    00389         // be as follow:
    00390         //   Highest 1 - Absence due to a non-periodic Notice of Absence (Count = 1)
    00391         //           2 - Presence from TBTT until the end of Beacon frame transmission
    00392         //           3 - Presence during the CTWindow
    00393         //    Lowest 4 - Absence for a periodic Notice of Absence (Count > 1)
    00394         if ((low_noa_count == 1) ||                                // non-periodic NoA or
    00395             (!p2p->is_waiting_bcn &&                               // ( not in TBTT and
    00396              (p2p->oppps_status != P2P_OPPPS_TIMER_WAIT_END_CTW))) //   not in CTwindow )
    00397         {
    00398             is_go_present = false;
    00399         }
    00400         else if (p2p->is_waiting_bcn)
    00401         {
    00402             tbtt_in_noa = true;
    00403         }
    00404     }
    00405     else
    00406     {
    00407         // No NoA is progress, still GO may be absent if oppPS is enabled
    00408         do
    00409         {
    00410             // Check if Opportunistic PS is supported
    00411             if (p2p->oppps_ctw == 0)
    00412             {
    00413                 // Go is present
    00414                 break;
    00415             }
    00416
    00417             // Check if the CTWindow is opened
    00418             if (p2p->oppps_status == P2P_OPPPS_TIMER_WAIT_END_CTW)
    00419             {
    00420                 // Go is present
    00421                 break;
    00422             }
    00423
    00424             #if (NX_P2P_GO)
    00425             if (p2p->role == P2P_ROLE_GO)
    00426             {
    00427                 // As GO we now have to check if all peer P2P client are in sleep mode.
    00428                 // In that case, we can enter in sleep mode until the next TBTT.
    00429                 struct vif_info_tag *vif = &vif_info_tab[p2p->vif_index];
    00430
    00431                 if (vif->u.ap.ps_sta_cnt != vif->p2p_link_nb)
    00432                 {
    00433                      break;
    00434                 }
    00435             }
    00436             else
    00437             #endif //(NX_P2P_GO)
    00438             {
    00439                 // As CLI, consider the GO as absent only if PS mode is ON and not PAUSED
    00440                 #if (NX_POWERSAVE)
    00441                 if (!ps_env.ps_on || (ps_env.prevent_sleep & PS_PSM_PAUSED))
    00442                 {
    00443                     break;
    00444                 }
    00445                 #endif //(NX_POWERSAVE)
    00446             }
    00447
    00448             is_go_present = false;
    00449         } while (0);
    00450     }
    00451
    00452     // Check if presence status has been modified
    00453     if (is_go_present != p2p->is_go_present)
    00454     {
    00455         #if (NX_CHNL_CTXT)
    00456         struct vif_info_tag *vif = &vif_info_tab[p2p->vif_index];
    00457         #endif //(NX_CHNL_CTXT)
    00458
    00459         // We have to inform the driver in order to avoid sending of data during absence
    00460         struct mm_p2p_vif_ps_change_ind *ind = KE_MSG_ALLOC(MM_P2P_VIF_PS_CHANGE_IND,
    00461                                                               TASK_API, TASK_MM,
    00462                                                               mm_p2p_vif_ps_change_ind);
    00463
    00464         ind->vif_index = p2p->vif_index;
    00465         ind->ps_state  = (is_go_present) ? PS_MODE_OFF : PS_MODE_ON;
    00466
    00467         TRACE_P2P(NOA_DET, "{VIF-%d} GO is present = %d", p2p->vif_index, is_go_present);
    00468
    00469         // Send the indication
    00470         ke_msg_send(ind);
    00471
    00472         // Store new status
    00473         p2p->is_go_present = is_go_present;
    00474
    00475         #if (NX_CHNL_CTXT)
    00476         // Notify chan module about the P2P state update
    00477         chan_p2p_absence_update(vif->chan_ctxt, !is_go_present);
    00478         #endif //(NX_CHNL_CTXT)
    00479
    00480         #if (NX_UAPSD)
    00481         // Notify the PS module about the P2P state update
    00482         ps_p2p_absence_update(vif, !is_go_present);
    00483         #endif //(NX_UAPSD)
    00484
    00485         if (!is_go_present)
    00486         {
    00487             PROF_P2P_ABSENCE_SET();
    00488
    00489             // Update prevent_sleep state
    00490             #if (NX_P2P_GO)
    00491             if (vif->type == VIF_AP)
    00492             {
    00493                 #if (NX_POWERSAVE)
    00494                 // Allow to enter in doze mode
    00495                 vif->prevent_sleep &= ~PS_VIF_P2P_GO_PRESENT;
    00496                 #endif //(NX_POWERSAVE)
    00497                 if (mm_bcn_transmitting())
    00498                 {
    00499                     GLOBAL_INT_DISABLE();
    00500                     txl_cntrl_halt_ac(AC_BCN);
    00501                     txl_cntrl_flush_ac(AC_BCN, DESC_DONE_SW_TX_BIT);
    00502                     GLOBAL_INT_RESTORE();
    00503                 }
    00504             }
    00505             #endif //(NX_P2P_GO)
    00506
    00507             // Require to enter to idle state in order to flush current TX packets
    00508             struct mm_force_idle_req *req = KE_MSG_ALLOC(MM_FORCE_IDLE_REQ,
    00509                                                          TASK_MM, TASK_NONE,
    00510                                                          mm_force_idle_req);
    00511
    00512             // Set the request parameters
    00513             req->cb = p2p_goto_idle_cb;
    00514
    00515             // Send the request
    00516             ke_msg_send(req);
    00517         }
    00518         else
    00519         {
    00520             PROF_P2P_ABSENCE_CLR();
    00521
    00522             // Update prevent_sleep state
    00523             #if (NX_P2P_GO && NX_POWERSAVE)
    00524             if (vif->type == VIF_AP)
    00525             {
    00526                 // Disallow to enter in doze mode
    00527                 vif->prevent_sleep |= PS_VIF_P2P_GO_PRESENT;
    00528             }
    00529             #endif //(NX_P2P_GO && NX_POWERSAVE)
    00530         }
    00531     }
    00532
    00533     if ((p2p->role == P2P_ROLE_CLIENT) && is_go_present && !tbtt_in_noa)
    00534     {
    00535         // GO is present, send postponed traffic unless it is present only to send its beacon.
    00536         vif_mgmt_send_postponed_frame(&vif_info_tab[p2p->vif_index]);
    00537     }
    00538 }
    00539
    00549 static void p2p_noa_timer_prog(struct p2p_noa_info_tag *noa, uint32_t time)
    00550 {
    00551     TRACE_P2P(NOA_DET, "{VIF-%d} Set NOA-%d timer %t",
    00552               p2p_info_tab[noa->p2p_index].vif_index, noa->noa_inst, TR_32(time));
    00553
    00554     mm_timer_set(&noa->noa_timer, time);
    00555 }
    00556
    00565 static void p2p_noa_timer_end(void *env)
    00566 {
    00567     struct p2p_noa_info_tag *noa = (struct p2p_noa_info_tag *)env;
    00568     struct p2p_info_tag *p2p = &p2p_info_tab[noa->p2p_index];
    00569     struct vif_info_tag *vif = &vif_info_tab[p2p->vif_index];
    00570     uint8_t next_noa_status = noa->noa_status;
    00571     uint32_t next_time;
    00572
    00573     TRACE_P2P(NOA_DET, "{VIF-%d} NOA-%d timer expire status=%d",
    00574               p2p->vif_index, noa->noa_inst, noa->noa_status);
    00575
    00576     #if NX_P2P_GO
    00577     if (p2p->role == P2P_ROLE_GO)
    00578     {
    00579         // Directly use timer time
    00580         next_time = noa->noa_timer.time;
    00581     }
    00582     else
    00583     #endif /* NX_P2P_GO */
    00584     {
    00585         // Get time based on peer TSF value.
    00586         next_time = p2p_peer_2_local_time(vif, noa->peer_next_noa_time);
    00587     }
    00588
    00589     // Loop in order to avoid programming in the past
    00590     do
    00591     {
    00592         // React based on the current NOA status
    00593         switch (next_noa_status)
    00594         {
    00595             case (P2P_NOA_TIMER_WAIT_NEXT_ABS):
    00596             {
    00597                 PROF_P2P_NOA_ABS_SET(noa->noa_inst);
    00598
    00599                 next_noa_status = P2P_NOA_TIMER_WAIT_END_ABS;
    00600                 next_time      += (noa->noa_dur_us);
    00601             } break;
    00602
    00603             case (P2P_NOA_TIMER_WAIT_END_ABS):
    00604             {
    00605                 PROF_P2P_NOA_ABS_CLR(noa->noa_inst);
    00606
    00607                 // Decrement number of remaining absences if not continuous
    00608                 if (noa->noa_counter != P2P_NOA_CONTINUOUS_COUNTER)
    00609                 {
    00610                     noa->noa_counter--;
    00611                 }
    00612
    00613                 // Check if another absence is scheduled
    00614                 if (noa->noa_counter)
    00615                 {
    00616                     next_noa_status = P2P_NOA_TIMER_WAIT_NEXT_ABS;
    00617                     next_time      += (noa->noa_intv_us - noa->noa_dur_us);
    00618
    00619                     #if (NX_P2P_GO)
    00620                     // If GO, update start time
    00621                     if ((p2p->role == P2P_ROLE_GO) && p2p->is_noa_bcn)
    00622                     {
    00623                         // Next start time
    00624                         noa->noa_start_time += noa->noa_intv_us;
    00625                         // Decrement start time update counter
    00626                         noa->noa_time_upd_cnt--;
    00627
    00628                         if (!noa->noa_time_upd_cnt)
    00629                         {
    00630                             // Update NOA Init Counter
    00631                             noa->noa_init_counter = noa->noa_counter;
    00632
    00633                             // Recompute start time update counter
    00634                             p2p_go_noa_get_intv_cnt(noa);
    00635
    00636                             // Update the beacon
    00637                             mm_bcn_update_p2p_noa(vif->index, P2P_BCN_UPD_OP_NOA_UPD);
    00638                         }
    00639                     }
    00640                     #endif //(NX_P2P_GO)
    00641                 }
    00642                 else
    00643                 {
    00644                     next_noa_status = P2P_NOA_TIMER_NOT_STARTED;
    00645
    00646                     #if (NX_P2P_GO)
    00647                     // Stop the NOA
    00648                     if (p2p->role == P2P_ROLE_GO)
    00649                     {
    00650                         p2p_go_noa_stop(vif, noa->noa_inst, false);
    00651                     }
    00652                     else
    00653                     #endif //(NX_P2P_GO)
    00654                     {
    00655                         p2p_cli_noa_cancel(noa);
    00656                     }
    00657                 }
    00658             } break;
    00659
    00660             default:
    00661             {
    00662                 // Should not happen
    00663                 ASSERT_ERR(0);
    00664             }
    00665         }
    00666     } while (hal_machw_time_cmp(next_time, ke_time() + P2P_NOA_TIMER_MARGIN) &&
    00667              (next_noa_status != P2P_NOA_TIMER_NOT_STARTED));
    00668
    00669     // Reprogram NOA timer if needed
    00670     if (next_noa_status != P2P_NOA_TIMER_NOT_STARTED)
    00671     {
    00672         if (p2p->role == P2P_ROLE_CLIENT)
    00673         {
    00674             // Keep the next time based on peer TSF
    00675             noa->peer_next_noa_time = p2p_local_2_peer_time(vif, next_time);
    00676         }
    00677
    00678         p2p_noa_timer_prog(noa, next_time);
    00679
    00680         // Update the NOA status
    00681         noa->noa_status = next_noa_status;
    00682     }
    00683
    00684     p2p_update_noa_presence_date(p2p);
    00685
    00686     // Update GO presence status
    00687     p2p_update_go_ps_state(p2p);
    00688
    00689     #if (NX_P2P_GO && NX_POWERSAVE)
    00690     /*
    00691      * When doze mode is used while we are AP, TBTT interrupts are no more generated.
    00692      * Hence to be sure to not be in Doze mode at this time, set P2P_GO_PRESENT bit at the
    00693      * end of the NOA absence (occurs few us before the interrupt)
    00694      */
    00695     if ((vif->type == VIF_AP) &&
    00696         (next_noa_status == P2P_NOA_TIMER_WAIT_NEXT_ABS))
    00697     {
    00698         vif->prevent_sleep |= PS_VIF_P2P_GO_PRESENT;
    00699     }
    00700     #endif //(NX_P2P_GO && NX_POWERSAVE)
    00701 }
    00702
    00716 static void p2p_oppps_timer_end(void *env)
    00717 {
    00718     struct p2p_info_tag *p2p = (struct p2p_info_tag *)env;
    00719
    00720     TRACE_P2P(PS, "{VIF-%d} oppPS timer end status=%d", p2p->vif_index, p2p->oppps_status);
    00721
    00722     if (p2p->oppps_status == P2P_OPPPS_TIMER_WAIT_END_CTW)
    00723     {
    00724         PROF_P2P_CTW_CLR();
    00725         p2p->oppps_status = P2P_OPPPS_TIMER_NOT_STARTED;
    00726         p2p_update_go_ps_state(p2p);
    00727     }
    00728     else if (p2p->oppps_status == P2P_OPPPS_TIMER_WAIT_START_CTW)
    00729     {
    00730         PROF_P2P_CTW_SET();
    00731         p2p->oppps_status = P2P_OPPPS_TIMER_WAIT_END_CTW;
    00732         mm_timer_set(&p2p->oppps_timer, p2p->oppps_ctw_end);
    00733         p2p_update_go_ps_state(p2p);
    00734     }
    00735 }
    00736
    00737 #if (NX_P2P_GO)
    00738
    00747 static void p2p_go_send_noa_upd_ind(struct p2p_info_tag *p2p, uint8_t noa_instance)
    00748 {
    00749     struct p2p_noa_info_tag *noa = &p2p->noa[noa_instance];
    00750     struct mm_p2p_noa_upd_ind *ind = KE_MSG_ALLOC(MM_P2P_NOA_UPD_IND, TASK_API,
    00751                                                     TASK_MM, mm_p2p_noa_upd_ind);
    00752
    00753     ind->vif_index = p2p->vif_index;
    00754     ind->noa_inst_nb = noa_instance;
    00755     ind->count = (noa->noa_status != P2P_NOA_TIMER_NOT_STARTED) ? noa->noa_init_counter : 0;
    00756
    00757     if (ind->count)
    00758     {
    00759         ind->noa_type = noa->noa_type;
    00760         ind->duration_us = noa->noa_dur_us;
    00761         ind->interval_us = noa->noa_intv_us;
    00762         ind->start_time = noa->noa_start_time;
    00763     }
    00764
    00765     // Send the message
    00766     ke_msg_send(ind);
    00767 }
    00768
    00778 static uint8_t p2p_go_get_noa_inst(struct p2p_info_tag *p2p)
    00779 {
    00780     uint8_t noa_idx;
    00781
    00782     for (noa_idx = 0; noa_idx < P2P_NOA_NB_MAX; noa_idx++)
    00783     {
    00784         struct p2p_noa_info_tag *noa = &p2p->noa[noa_idx];
    00785
    00786         // Check if the NOA timer is active
    00787         if (noa->noa_status == P2P_NOA_TIMER_NOT_STARTED)
    00788         {
    00789             break;
    00790         }
    00791     }
    00792
    00793     return (noa_idx);
    00794 }
    00795
    00806 __INLINE void p2p_go_noa_get_intv_cnt(struct p2p_noa_info_tag *noa)
    00807 {
    00808     if (noa->noa_intv_us == 0)
    00809         return;
    00810
    00811     // "The P2P Group Owner shall update the Start Time field [...] every 2^31us"
    00812     // Compute number of absences before next start time update.
    00813     // Update the start time one absence before.
    00814     noa->noa_time_upd_cnt = ((1 << 31) / noa->noa_intv_us) - 1;
    00815 }
    00816 #endif //(NX_P2P_GO)
    00817
    00833 static uint32_t p2p_cli_noa_get_abs_time(struct p2p_noa_info_tag *noa, uint8_t vif_index,
    00834                                          uint32_t start_time, uint32_t tsf_peer)
    00835 {
    00836     struct vif_info_tag *vif = &vif_info_tab[vif_index];
    00837     uint32_t absence_time;
    00838     uint32_t missed_intv;
    00839
    00840     if (tsf_peer >= start_time)
    00841     {
    00842         // If only one absence is scheduled it is too late.
    00843         if (noa->noa_counter == 1)
    00844         {
    00845             return (0);
    00846         }
    00847
    00848         // Need to know how many absences have been missed since start_time (on peer side)
    00849         missed_intv = ((tsf_peer - start_time) / noa->noa_intv_us) + 1;
    00850     }
    00851     else
    00852     {
    00853         missed_intv = 0;
    00854     }
    00855
    00856     TRACE_P2P(NOA_DET, "{VIF-%d} NoA startime=%ld, Peer's TSF=%ld => miss %d iteration",
    00857               vif->index, TR_32(start_time), TR_32(tsf_peer), missed_intv);
    00858
    00859     // Compute next absence time in Peer and local Time
    00860     noa->peer_next_noa_time = start_time + (missed_intv * noa->noa_intv_us);
    00861     absence_time = p2p_peer_2_local_time(vif, noa->peer_next_noa_time);
    00862
    00863     if (noa->noa_counter != P2P_NOA_CONTINUOUS_COUNTER)
    00864     {
    00865         noa->noa_counter -= co_min(missed_intv, noa->noa_counter);
    00866     }
    00867
    00868     // Check that computed time is not in the past
    00869     while (hal_machw_time_past(absence_time) && noa->noa_counter)
    00870     {
    00871         absence_time += noa->noa_intv_us;
    00872
    00873         if (noa->noa_counter != P2P_NOA_CONTINUOUS_COUNTER)
    00874         {
    00875             // Decrease number of remaining absences
    00876             noa->noa_counter--;
    00877         }
    00878     }
    00879
    00880     if (!noa->noa_counter)
    00881     {
    00882         // No more absence are coming
    00883         return (0);
    00884     }
    00885
    00886     TRACE_P2P(NOA_DET, "Next NOA iteration starts %t (TSF offset=%ld)",
    00887               TR_32(absence_time), TR_32(vif->u.sta.last_tsf_offset));
    00888
    00889     return (absence_time);
    00890 }
    00891
    00904 static bool p2p_cli_noa_start(struct p2p_noa_info_tag *noa, uint8_t vif_index,
    00905                               uint32_t start_time, uint32_t tsf_peer)
    00906 {
    00907     uint32_t first_abs_time;
    00908     TRACE_P2P(NOA, "{VIF-%d} start NOA-%d: count=%d intv=%ld us, dur=%ld us",
    00909               vif_index, noa->noa_inst, noa->noa_counter,
    00910               TR_32(noa->noa_intv_us), TR_32(noa->noa_dur_us));
    00911
    00912     first_abs_time = p2p_cli_noa_get_abs_time(noa, vif_index, start_time, tsf_peer);
    00913     if (first_abs_time)
    00914     {
    00915         // Program the noa timer with the computed time
    00916         p2p_noa_timer_prog(noa, first_abs_time);
    00917         // And Update the NOA status
    00918         noa->noa_status = P2P_NOA_TIMER_WAIT_NEXT_ABS;
    00919     }
    00920
    00921     return ((bool)first_abs_time);
    00922 }
    00923
    00931 static void p2p_cli_noa_cancel(struct p2p_noa_info_tag *noa)
    00932 {
    00933     TRACE_P2P(NOA, "{VIF-%d} Cancel NOA-%d",
    00934               p2p_info_tab[noa->p2p_index].vif_index, noa->noa_inst);
    00935
    00936     if (noa->noa_status != P2P_NOA_TIMER_NOT_STARTED)
    00937     {
    00938         // Stop NOA timer
    00939         mm_timer_clear(&noa->noa_timer);
    00940
    00941         // Reset NOA status
    00942         noa->noa_status = P2P_NOA_TIMER_NOT_STARTED;
    00943
    00944         PROF_P2P_NOA_ABS_CLR(noa->noa_inst);
    00945     }
    00946 }
    00947
    00957 static void p2p_cli_noa_handle_att(uint8_t p2p_index,
    00958                                    uint32_t a_noa_att,
    00959                                    uint32_t tsf_peer)
    00960 {
    00961     struct p2p_info_tag *p2p = &p2p_info_tab[p2p_index];
    00962     uint8_t noa_idx;
    00963
    00964     TRACE_P2P(NOA_DET, "{VIF-%d} NOA attribute present=%d", p2p->vif_index, (a_noa_att != 0));
    00965
    00966     if (a_noa_att)
    00967     {
    00968         uint8_t nb_noa_desc;
    00969         uint8_t noa_index = co_read8p(a_noa_att + P2P_NOA_ATT_INDEX_OFT);
    00970         uint16_t length;
    00971         uint8_t ctw_oppps;
    00972
    00973         TRACE_P2P(NOA_DET, "index=%d, last index=%d", noa_index, p2p->noa_index);
    00974
    00975         // Check if a one of the NOA fields has been updated since last beacon
    00976         if (p2p->is_noa_bcn && (p2p->noa_index == noa_index))
    00977         {
    00978             // Nothing changed, skip this one
    00979             return;
    00980         }
    00981
    00982         // Keep in mind that NOA attribute was part of last received Beacon
    00983         p2p->is_noa_bcn = true;
    00984         p2p->noa_index = noa_index;
    00985
    00986         // Check if a NOA procedure is already known and in progress
    00987         if (p2p->noa_nb)
    00988         {
    00989             for (noa_idx = 0; noa_idx < P2P_NOA_NB_MAX; noa_idx++)
    00990             {
    00991                 // Cancel NOA procedure
    00992                 p2p_cli_noa_cancel(&p2p->noa[noa_idx]);
    00993                 p2p->noa_nb = 0;
    00994             }
    00995
    00996             // Update Go PS state
    00997             p2p_update_go_ps_state(p2p);
    00998         }
    00999
    01000         // Compute number of NoA Descriptor from length of NoA attribute
    01001         length = co_read16p(a_noa_att + P2P_ATT_LEN_OFT);
    01002         nb_noa_desc = (length - 2) / P2P_NOA_DESC_LENGTH;
    01003
    01004         for (noa_idx = 0; noa_idx < nb_noa_desc; noa_idx++)
    01005         {
    01006             struct p2p_noa_info_tag *noa = &p2p->noa[noa_idx];
    01007             // Get address of NoA descriptor in the memory
    01008             uint32_t a_noa_desc = a_noa_att + P2P_NOA_ATT_NOA_DESC_OFT
    01009                 + (noa_idx * P2P_NOA_DESC_LENGTH);
    01010
    01011             // Extract NOA Counter
    01012             noa->noa_init_counter = co_read8p(a_noa_desc + P2P_NOA_DESC_COUNT_OFT);
    01013
    01014             // Check if GO is using NOA
    01015             if (noa->noa_init_counter != 0)
    01016             {
    01017                 // Read absence interval
    01018                 uint32_t noa_intv = co_read32p(a_noa_desc + P2P_NOA_DESC_INTV_OFT);
    01019
    01020                 // Verify that interval is not 0 if count different than 1
    01021                 if ((noa->noa_init_counter > 1) && !noa_intv)
    01022                 {
    01023                     continue;
    01024                 }
    01025
    01026                 // Extract NOA parameters
    01027                 noa->noa_dur_us  = co_read32p(a_noa_desc + P2P_NOA_DESC_DUR_OFT);
    01028                 noa->noa_intv_us = noa_intv;
    01029                 noa->noa_counter = noa->noa_init_counter;
    01030
    01031                 // Restart NOA procedure
    01032                 if (p2p_cli_noa_start(noa, p2p->vif_index,
    01033                                       co_read32p(a_noa_desc + P2P_NOA_DESC_START_OFT),
    01034                                       tsf_peer))
    01035                 {
    01036                     p2p->noa_nb++;
    01037                 }
    01038             }
    01039         }
    01040
    01041         ctw_oppps = co_read8p(a_noa_att + P2P_NOA_ATT_CTW_OPPPS_OFT);
    01042
    01043         // Check if GO is using OppPS
    01044         if ((ctw_oppps & P2P_OPPPS_MASK) == P2P_OPPPS_MASK)
    01045         {
    01046             // Extract CTWindow
    01047             p2p->oppps_ctw = ctw_oppps & P2P_CTWINDOW_MASK;
    01048             TRACE_P2P(PS, "{VIF-%d} P2P GO configured a CTW of %d TU",
    01049                       p2p->vif_index, p2p->oppps_ctw)
    01050         }
    01051         else
    01052         {
    01053             // 0 value will indicate that the OppPS is not used
    01054             p2p->oppps_ctw = 0;
    01055         }
    01056     }
    01057     else
    01058     {
    01059         p2p->is_noa_bcn = false;
    01060
    01061         // Check if a NOA procedure is already known and in progress
    01062         if (p2p->noa_nb)
    01063         {
    01064             for (noa_idx = 0; noa_idx < P2P_NOA_NB_MAX; noa_idx++)
    01065             {
    01066                 // Cancel NOA procedure
    01067                 p2p_cli_noa_cancel(&p2p->noa[noa_idx]);
    01068                 p2p->noa_nb = 0;
    01069             }
    01070
    01071             p2p_update_go_ps_state(p2p);
    01072         }
    01073
    01074         // Stop OppPS procedure
    01075         p2p->oppps_ctw = 0;
    01076     }
    01077 }
    01078
    01079 /*
    01080  * PUBLIC FUNCTIONS
    01081  ****************************************************************************************
    01082  */
    01083
    01084 void p2p_init(void)
    01085 {
    01086     uint8_t counter;
    01087
    01088     TRACE_P2P(ITF, "P2P init");
    01089
    01090     #if (NX_P2P_GO)
    01091     memset(&p2p_env, 0, sizeof(struct p2p_env_tag));
    01092     #endif //(NX_P2P_GO)
    01093
    01094     // Initialize all vif_index to INVALID_VIF_IDX in order to indicate that the p2p
    01095     // structure is unused
    01096     for (counter = 0; counter < NX_P2P_VIF_MAX; counter++)
    01097     {
    01098         struct p2p_info_tag *p2p = &p2p_info_tab[counter];
    01099         p2p->vif_index = INVALID_VIF_IDX;
    01100     }
    01101 }
    01102
    01103 uint8_t p2p_create(uint8_t vif_index, uint8_t role)
    01104 {
    01105     uint8_t p2p_index = P2P_INVALID_IDX;
    01106     uint8_t p2p_idx;
    01107
    01108     // Look for an available P2P Entry structure
    01109     for (p2p_idx = 0; p2p_idx < NX_P2P_VIF_MAX; p2p_idx++)
    01110     {
    01111         struct p2p_info_tag *p2p = &p2p_info_tab[p2p_idx];
    01112
    01113         if (p2p->vif_index == INVALID_VIF_IDX)
    01114         {
    01115             uint8_t noa_idx;
    01116
    01117             // Initialize content
    01118             memset(p2p, 0, sizeof(struct p2p_info_tag));
    01119
    01120             // Return current index
    01121             p2p_index = p2p_idx;
    01122
    01123             // Store the provided vif index and the role
    01124             p2p->vif_index = vif_index;
    01125             p2p->role      = role;
    01126
    01127             #if (NX_P2P_GO)
    01128             if (p2p->role == P2P_ROLE_GO)
    01129             {
    01130                 p2p_env.nb_p2p_go++;
    01131             }
    01132             #endif //(NX_P2P_GO)
    01133
    01134             // Pre-configure NOA timers
    01135             for (noa_idx = 0; noa_idx < P2P_NOA_NB_MAX; noa_idx++)
    01136             {
    01137                 struct p2p_noa_info_tag *noa = &p2p->noa[noa_idx];
    01138
    01139                 noa->noa_timer.cb  = p2p_noa_timer_end;
    01140                 noa->noa_timer.env = noa;
    01141                 noa->p2p_index = p2p_idx;
    01142                 noa->noa_inst = noa_idx;
    01143             }
    01144
    01145             // Pre-configure OPPPS timer
    01146             p2p->oppps_timer.cb  = p2p_oppps_timer_end;
    01147             p2p->oppps_timer.env = p2p;
    01148
    01149             // Initiate GO present status, will be present (no noa or oppps yet)
    01150             p2p_update_go_ps_state(p2p);
    01151
    01152             // Stop looping
    01153             break;
    01154         }
    01155     }
    01156
    01157     TRACE_P2P(ITF, "CREATE: {VIF-%d} role=%d, p2p_idx=%d", vif_index, role, p2p_index);
    01158
    01159     return (p2p_index);
    01160 }
    01161
    01162 void p2p_cancel(uint8_t p2p_index, bool vif_del)
    01163 {
    01164     struct p2p_info_tag *p2p = &p2p_info_tab[p2p_index];
    01165
    01166     TRACE_P2P(ITF, "DELETE: {VIF-%d} p2p_idx=%d", p2p->vif_index, p2p_index);
    01167
    01168     // Verify that the structure is used
    01169     if (p2p->vif_index != INVALID_VIF_IDX)
    01170     {
    01171         // Cancel Beacon Timeout Timer if needed
    01172         if (p2p->is_waiting_bcn)
    01173         {
    01174             PROF_P2P_WAIT_BCN_CLR();
    01175         }
    01176
    01177         #if (NX_P2P_GO)
    01178         if (p2p->role == P2P_ROLE_GO)
    01179         {
    01180             p2p_env.nb_p2p_go--;
    01181         }
    01182         #endif //(NX_P2P_GO)
    01183
    01184         if (vif_del)
    01185         {
    01186             // Reset VIF index
    01187             p2p->vif_index = INVALID_VIF_IDX;
    01188         }
    01189     }
    01190 }
    01191
    01192 void p2p_set_vif_state(struct vif_info_tag *vif, bool active)
    01193 {
    01194     struct p2p_info_tag *p2p;
    01195
    01196     if (!vif->p2p)
    01197     {
    01198         return;
    01199     }
    01200
    01201     TRACE_P2P(ITF, "{VIF-%d} active=%d", vif->index, active);
    01202
    01203     p2p = &p2p_info_tab[vif->p2p_index];
    01204
    01205     if (vif->type == VIF_STA)
    01206     {
    01207         if (!active)
    01208         {
    01209             for (int noa_idx = 0; noa_idx < P2P_NOA_NB_MAX; noa_idx++)
    01210             {
    01211                 p2p_cli_noa_cancel(&p2p->noa[noa_idx]);
    01212             }
    01213
    01214             p2p->oppps_ctw = 0;
    01215             p2p->noa_index = 0;
    01216             p2p->is_noa_bcn = false;
    01217
    01218             // Cancel OppPS timer if needed
    01219             if (p2p->oppps_status != P2P_OPPPS_TIMER_NOT_STARTED)
    01220             {
    01221                 mm_timer_clear(&p2p->oppps_timer);
    01222                 p2p->oppps_status = P2P_OPPPS_TIMER_NOT_STARTED;
    01223                 PROF_P2P_CTW_CLR();
    01224             }
    01225             p2p_update_go_ps_state(p2p);
    01226         }
    01227     }
    01228 }
    01229
    01230 bool p2p_is_present(uint8_t p2p_index)
    01231 {
    01232     struct p2p_info_tag *p2p = &p2p_info_tab[p2p_index];
    01233     return (p2p->is_go_present);
    01234 }
    01235
    01236 bool p2p_go_get_next_NOA_date(struct vif_info_tag *vif,
    01237                               uint32_t *next_p2p_present,
    01238                               uint32_t *next_p2p_absent)
    01239 {
    01240     struct p2p_info_tag *p2p;
    01241     ASSERT_ERR(vif->p2p);
    01242
    01243     p2p = &p2p_info_tab[vif->p2p_index];
    01244     *next_p2p_present = p2p->next_present;
    01245     *next_p2p_absent = p2p->next_absent;
    01246
    01247     return hal_machw_time_cmp(*next_p2p_absent, *next_p2p_present);
    01248 }
    01249
    01250 uint32_t p2p_go_get_next_noa_end_date(struct vif_info_tag *vif,
    01251                                       uint8_t noa_inst)
    01252 {
    01253     struct p2p_info_tag *p2p;
    01254     struct p2p_noa_info_tag *noa;
    01255     ASSERT_ERR(vif->p2p && (noa_inst < P2P_NOA_NB_MAX));
    01256
    01257     p2p = &p2p_info_tab[vif->p2p_index];
    01258     noa = &p2p->noa[noa_inst];
    01259
    01260     switch (noa->noa_status)
    01261     {
    01262         case P2P_NOA_TIMER_WAIT_END_ABS:
    01263             return noa->noa_timer.time;
    01264         case P2P_NOA_TIMER_WAIT_NEXT_ABS:
    01265             return noa->noa_timer.time + noa->noa_dur_us;
    01266         default:
    01267             ASSERT_WARN(0);
    01268     }
    01269
    01270     return 0;
    01271 }
    01272
    01273 void p2p_tbtt_handle(struct vif_info_tag *vif, uint32_t tbtt_time)
    01274 {
    01275     struct p2p_info_tag *p2p;
    01276
    01277     if (!vif->p2p)
    01278     {
    01279         return;
    01280     }
    01281     TRACE_P2P(TBTT, "{VIF-%d} TBTT starts", vif->index);
    01282
    01283     p2p = &p2p_info_tab[vif->p2p_index];
    01284
    01285     PROF_P2P_WAIT_BCN_SET();
    01286
    01287     // Keep in mind we are waiting for a beacon
    01288     p2p->is_waiting_bcn = true;
    01289     #if (NX_POWERSAVE)
    01290     vif->prevent_sleep &= ~(PS_VIF_P2P_WAIT_TBTT);
    01291     #endif //(NX_POWERSAVE)
    01292
    01293     // Check if Opportunistic Power Save mode is used -> Start timer monitoring the CTWindow
    01294     if (p2p->oppps_ctw)
    01295     {
    01296         // Compute end time of CT Window (oppps_ctw is in TUs)
    01297         uint32_t ctw_end = tbtt_time + (p2p->oppps_ctw << 10);
    01298
    01299         if (p2p->role == P2P_ROLE_CLIENT)
    01300         {
    01301             tbtt_time += 300; // For CLI take extra margin
    01302             if (hal_machw_time_cmp(ke_time() + 50, tbtt_time))
    01303             {
    01304                 // ctw really start at tbtt_time (which is more than 50us away) so delay update
    01305                 // of P2P GO presence update until then
    01306                 p2p->oppps_status = P2P_OPPPS_TIMER_WAIT_START_CTW;
    01307                 p2p->oppps_ctw_end = ctw_end;
    01308                 mm_timer_set(&p2p->oppps_timer, tbtt_time);
    01309                 return;
    01310             }
    01311         }
    01312
    01313         p2p->oppps_status = P2P_OPPPS_TIMER_WAIT_END_CTW;
    01314         mm_timer_set(&p2p->oppps_timer, ctw_end);
    01315         PROF_P2P_CTW_SET();
    01316     }
    01317
    01318     // Update GO Power Save state
    01319     p2p_update_go_ps_state(p2p);
    01320 }
    01321
    01322 void p2p_bcn_evt_handle(struct vif_info_tag *vif)
    01323 {
    01324     struct p2p_info_tag *p2p = &p2p_info_tab[vif->p2p_index];
    01325
    01326     TRACE_P2P(TBTT, "{VIF-%d} TBTT ends", vif->index);
    01327     PROF_P2P_WAIT_BCN_CLR();
    01328
    01329     // Update beacon reception status
    01330     p2p->is_waiting_bcn = false;
    01331
    01332     // Update GO Power Save state
    01333     p2p_update_go_ps_state(p2p);
    01334 }
    01335
    01336 uint32_t p2p_cli_bcn_check_noa(struct vif_info_tag *vif,
    01337                                struct rx_pbd *pyld_desc, struct rx_dmadesc *dma_hdrdesc)
    01338 {
    01339     uint32_t noa_pos = 0;
    01340     uint32_t rd_addr;
    01341     uint32_t end_addr;
    01342     struct bcn_frame *bcn;
    01343
    01344     // Check vif is P2P client
    01345     if ((!vif->p2p) || (vif->type != VIF_STA))
    01346     {
    01347         return noa_pos;
    01348     }
    01349
    01350     ASSERT_ERR(vif->p2p_index < NX_P2P_VIF_MAX);
    01351     TRACE_P2P(NOA_DET, "{VIF-%d} Check for NOA attribute in beacon", vif->index);
    01352
    01353     rd_addr  = pyld_desc->datastartptr + MAC_BEACON_VARIABLE_PART_OFT;
    01354     end_addr = rd_addr + dma_hdrdesc->hd.frmlen - MAC_BEACON_VARIABLE_PART_OFT;
    01355
    01356     // Look for P2P IE(s)
    01357     while (rd_addr < end_addr)
    01358     {
    01359         // Keep the current address before computing the next one
    01360         uint32_t addr = rd_addr;
    01361
    01362         rd_addr += co_read8p(addr + MAC_INFOELT_LEN_OFT) + MAC_INFOELT_INFO_OFT;
    01363
    01364         // Check if the current IE is the one we are looking for
    01365         if (co_read8p(addr) != P2P_ELMT_ID)
    01366         {
    01367             // Move on to the next IE
    01368             continue;
    01369         }
    01370
    01371         // Check if OUI type is P2P
    01372         if (co_read8p(addr + P2P_IE_OUI_TYPE_OFT) != P2P_OUI_TYPE_P2P)
    01373         {
    01374             // Move on to the next IE
    01375             continue;
    01376         }
    01377
    01378         // Look for NOA attribute
    01379         noa_pos = p2p_att_find(addr + P2P_IE_ATT_OFT,
    01380                                co_read8p(addr + P2P_IE_LEN_OFT) - 4,
    01381                                P2P_ATT_ID_NOTICE_OF_ABSENCE);
    01382
    01383         if (!noa_pos)
    01384         {
    01385             // NOA has not been found, continue. Another P2P element could contain NOA
    01386             continue;
    01387         }
    01388
    01389         break;
    01390     }
    01391
    01392     // Get beacon data
    01393     bcn = (struct bcn_frame *)HW2CPU(
    01394         ((struct rx_pbd *)HW2CPU(dma_hdrdesc->hd.first_pbd_ptr))->datastartptr);
    01395
    01396     p2p_cli_noa_handle_att(vif->p2p_index, noa_pos, bcn->tsf);
    01397
    01398     return (noa_pos);
    01399 }
    01400
    01401 void p2p_cli_handle_action(struct vif_info_tag *vif, uint32_t a_frame, uint16_t length,
    01402                            uint32_t rx_tsf)
    01403 {
    01404     uint32_t addr = a_frame + MAC_SHORT_MAC_HDR_LEN;
    01405     uint16_t len = length - MAC_SHORT_MAC_HDR_LEN;
    01406
    01407     TRACE_P2P(NOA_DET, "{VIF-%d} check for NOA attribute in P2P action frame", vif->index);
    01408
    01409     // Check Category Code, should be Vendor Specific (127)
    01410     if (co_read8p(addr + MAC_ACTION_CATEGORY_OFT) != MAC_VENDOR_ACTION_CATEGORY)
    01411     {
    01412         return;
    01413     }
    01414
    01415     // Read P2P Action Subtype and react accordingly
    01416     if (co_read8p(addr + MAC_ACTION_P2P_ACTION_OFT) == MAC_P2P_ACTION_NOA_SUBTYPE)
    01417     {
    01418         // Move to the tagged parameters
    01419         addr += MAC_ACTION_P2P_TAGGED_OFT;
    01420         len -= MAC_ACTION_P2P_TAGGED_OFT;
    01421
    01422         // Check if the current IE is the one we are looking for
    01423         if (co_read8p(addr + P2P_IE_ID_OFT) != P2P_ELMT_ID)
    01424         {
    01425             return;
    01426         }
    01427
    01428         // Check if OUI type is P2P
    01429         if (co_read8p(addr + P2P_IE_OUI_TYPE_OFT) != P2P_OUI_TYPE_P2P)
    01430         {
    01431             return;
    01432         }
    01433
    01434         if (co_read8p(addr + P2P_IE_ATT_OFT) != P2P_ATT_ID_NOTICE_OF_ABSENCE)
    01435         {
    01436             return;
    01437         }
    01438
    01439         // Handle the NoA Attribute
    01440         p2p_cli_noa_handle_att(vif->p2p_index, addr + P2P_IE_ATT_OFT,
    01441                                p2p_local_2_peer_time(vif, rx_tsf));
    01442     }
    01443 }
    01444
    01445 /*
    01446  * --------------------------------------------------------------------------
    01447  * |           FUNCTION TO BE USED FOR P2P GO BEACON MANAGEMENT             |
    01448  * --------------------------------------------------------------------------
    01449  */
    01450
    01451 #if (NX_P2P_GO)
    01452 #if (NX_POWERSAVE)
    01453 bool p2p_go_check_ps_mode(void)
    01454 {
    01455     // Check if P2P module authorizes the system to enter in deep sleep when GO.
    01456     // Note that if we are here, it is considered that ps_env.ps_on value is false
    01457     // meaning that Legacy Power Save mode is disabled.
    01458     // If ps_env.ps_on is true, P2P_GO_PRESENT bit in vif_mgmt_tag prevent sleep
    01459     // value is enough.
    01460     struct vif_info_tag *vif;
    01461
    01462     // Check if we have a GO VIF
    01463     if (!p2p_env.nb_p2p_go)
    01464     {
    01465         return false;
    01466     }
    01467
    01468     // Check if we have at least one STA VIFs or several VIF AP
    01469     #if (NX_MULTI_ROLE)
    01470     if (vif_mgmt_env.vif_sta_cnt || (vif_mgmt_env.vif_ap_cnt > 1))
    01471     {
    01472         return false;
    01473     }
    01474     #endif //(NX_MULTI_ROLE)
    01475
    01476     vif = (struct vif_info_tag *)co_list_pick(&vif_mgmt_env.used_list);
    01477
    01478     while (vif)
    01479     {
    01480         if ((vif->type == VIF_AP) && vif->p2p)
    01481         {
    01482             struct p2p_info_tag *p2p = &p2p_info_tab[vif->p2p_index];
    01483
    01484             // Can go to deep sleep if GO is not present
    01485             return ! p2p->is_go_present;
    01486         }
    01487
    01488         vif = (struct vif_info_tag *)vif_mgmt_next(vif);
    01489     }
    01490
    01491     return false;
    01492 }
    01493 #endif //(NX_POWERSAVE)
    01494
    01495 void p2p_go_td_evt(uint8_t vif_index, uint8_t new_status)
    01496 {
    01497     struct vif_info_tag *vif = &vif_info_tab[vif_index];
    01498
    01499     if (vif->p2p && (vif->type == VIF_AP))
    01500     {
    01501         struct p2p_info_tag *p2p = &p2p_info_tab[vif->p2p_index];
    01502
    01503         if (new_status)
    01504         {
    01505             PROF_P2P_PS_PAUSED_SET();
    01506             p2p->noa_paused = true;
    01507         }
    01508         else
    01509         {
    01510             PROF_P2P_PS_PAUSED_CLR();
    01511             p2p->noa_paused = false;
    01512         }
    01513
    01514         if (p2p->is_noa_bcn)
    01515         {
    01516             // Update the NoA IE in the Beacon
    01517             mm_bcn_update_p2p_noa(p2p->vif_index, P2P_BCN_UPD_OP_NOA_UPD);
    01518         }
    01519
    01520         p2p_update_go_ps_state(p2p);
    01521     }
    01522 }
    01523
    01524 void p2p_go_oppps_start(struct vif_info_tag *vif, uint8_t ctw)
    01525 {
    01526     struct p2p_info_tag *p2p = &p2p_info_tab[vif->p2p_index];
    01527
    01528     TRACE_P2P(PS, "{VIF-%d} start oppPS CTW=%d TU", vif->index, ctw);
    01529
    01530     // Initialize OPPPS parameters
    01531     p2p->oppps_ctw = ctw;
    01532     // Consider the CTW as opened before next TBTT
    01533     p2p->oppps_status = P2P_OPPPS_TIMER_WAIT_END_CTW;
    01534
    01535     // Update the NOA attribute, will be added in the beacon (see p2p_go_bcn_op_done)
    01536     mm_bcn_update_p2p_noa(p2p->vif_index, P2P_BCN_UPD_OP_NOA_UPD);
    01537
    01538     // Update GO PS state
    01539     p2p_update_go_ps_state(p2p);
    01540 }
    01541
    01542 void p2p_go_oppps_stop(struct vif_info_tag *vif)
    01543 {
    01544     struct p2p_info_tag *p2p = &p2p_info_tab[vif->p2p_index];
    01545
    01546     TRACE_P2P(PS, "{VIF-%d} stop oppPS", vif->index);
    01547
    01548     // Reset OPPPS parameters and stop time if needed
    01549     p2p->oppps_ctw = 0;
    01550     if (p2p->oppps_status != P2P_OPPPS_TIMER_NOT_STARTED)
    01551     {
    01552         mm_timer_clear(&p2p->oppps_timer);
    01553         p2p->oppps_status = P2P_OPPPS_TIMER_NOT_STARTED;
    01554         PROF_P2P_CTW_CLR();
    01555     }
    01556     p2p_update_go_ps_state(p2p);
    01557
    01558     if (!p2p->noa_nb)
    01559     {
    01560         // If NOA is not used, remove NOA part of the Beacon
    01561         mm_bcn_update_p2p_noa(p2p->vif_index, P2P_BCN_UPD_OP_NOA_RMV);
    01562     }
    01563     else
    01564     {
    01565         // Update NOA attribute content
    01566         mm_bcn_update_p2p_noa(p2p->vif_index, P2P_BCN_UPD_OP_NOA_UPD);
    01567     }
    01568 }
    01569
    01570 void p2p_go_ps_state_update(struct vif_info_tag *vif)
    01571 {
    01572     if (!vif->p2p)
    01573     {
    01574         return;
    01575     }
    01576
    01577     TRACE_P2P(PS, "{VIF-%d} update GO PS state", vif->index);
    01578     p2p_update_go_ps_state(&p2p_info_tab[vif->p2p_index]);
    01579 }
    01580
    01581 uint8_t p2p_go_noa_start(struct vif_info_tag *vif, bool concurrent, bool dyn_noa,
    01582                          uint8_t counter, uint32_t intv_us, uint32_t dur_us,
    01583                          uint32_t start_time)
    01584 {
    01585     struct p2p_info_tag *p2p = &p2p_info_tab[vif->p2p_index];
    01586     struct p2p_noa_info_tag *noa;
    01587     uint8_t noa_inst = P2P_NOA_NB_MAX;
    01588
    01589     if (p2p->role != P2P_ROLE_GO)
    01590         return P2P_INVALID_IDX;
    01591
    01592     noa_inst = p2p_go_get_noa_inst(p2p);
    01593
    01594     TRACE_P2P(NOA, "{VIF-%d} start NOA-%d: count=%d, intv=%ld us, dur=%ld us, start %t",
    01595               vif->index, noa_inst, counter, TR_32(intv_us), TR_32(dur_us),
    01596               TR_32(start_time));
    01597
    01598     if (noa_inst >= P2P_NOA_NB_MAX)
    01599         return P2P_INVALID_IDX;
    01600
    01601     noa = &p2p->noa[noa_inst];
    01602
    01603     // Initialize NOA parameters
    01604     noa->noa_counter      = counter;
    01605     noa->noa_init_counter = counter;
    01606     noa->noa_intv_us      = intv_us;
    01607     noa->noa_dur_us       = dur_us;
    01608     noa->noa_start_time   = start_time;
    01609     noa->dyn_noa          = dyn_noa;
    01610     noa->noa_type         = (concurrent) ? P2P_NOA_TYPE_CONCURRENT : P2P_NOA_TYPE_NORMAL;
    01611
    01612     p2p->noa_nb++;
    01613
    01614     if (concurrent)
    01615     {
    01616         p2p->noa_cm_nb++;
    01617     }
    01618
    01619     // Compute number of absence periods before start time update
    01620     p2p_go_noa_get_intv_cnt(noa);
    01621
    01622     // Program the noa timer with the computed start time
    01623     p2p_noa_timer_prog(noa, noa->noa_start_time);
    01624     // And Update the NOA status
    01625     noa->noa_status = P2P_NOA_TIMER_WAIT_NEXT_ABS;
    01626
    01627     // Update the NOA attribute, will be added in the beacon (see p2p_go_bcn_op_done)
    01628     mm_bcn_update_p2p_noa(p2p->vif_index, P2P_BCN_UPD_OP_NOA_UPD);
    01629
    01630     // Inform the host about the newly created NoA
    01631     p2p_go_send_noa_upd_ind(p2p, noa_inst);
    01632
    01633     p2p_update_noa_presence_date(p2p);
    01634
    01635     // Update Go PS state
    01636     p2p_update_go_ps_state(p2p);
    01637
    01638     return noa_inst;
    01639 }
    01640
    01641 uint8_t p2p_go_noa_stop(struct vif_info_tag *vif, uint8_t noa_inst, bool host_req)
    01642 {
    01643     struct p2p_info_tag *p2p = &p2p_info_tab[vif->p2p_index];
    01644     struct p2p_noa_info_tag *noa;
    01645
    01646     if ((p2p->role != P2P_ROLE_GO) || (noa_inst >= P2P_NOA_NB_MAX))
    01647     {
    01648         return CO_FAIL;
    01649     }
    01650
    01651     TRACE_P2P(NOA, "{VIF-%d} stop NOA-%d (host_req=%d)", vif->index, noa_inst, host_req);
    01652
    01653     noa = &p2p->noa[noa_inst];
    01654     if ((noa->noa_status == P2P_NOA_TIMER_NOT_STARTED) ||
    01655         (host_req && (noa->noa_type == P2P_NOA_TYPE_CONCURRENT)))
    01656     {
    01657         return CO_FAIL;
    01658     }
    01659
    01660     // Stop NOA
    01661     PROF_P2P_NOA_ABS_CLR(noa->noa_inst);
    01662     mm_timer_clear(&noa->noa_timer);
    01663     noa->noa_status = P2P_NOA_TIMER_NOT_STARTED;
    01664     p2p_update_noa_presence_date(p2p);
    01665     p2p_update_go_ps_state(p2p);
    01666     p2p->noa_nb--;
    01667     if (noa->noa_type == P2P_NOA_TYPE_NORMAL)
    01668     {
    01669         p2p->noa_cm_nb--;
    01670     }
    01671
    01672     if ((p2p->oppps_ctw == 0) && (p2p->noa_nb == 0))
    01673     {
    01674         // If OppPS is not used, remove NOA part of the Beacon
    01675         mm_bcn_update_p2p_noa(p2p->vif_index, P2P_BCN_UPD_OP_NOA_RMV);
    01676     }
    01677     else
    01678     {
    01679         // otherwise update NOA attribute content
    01680         mm_bcn_update_p2p_noa(p2p->vif_index, P2P_BCN_UPD_OP_NOA_UPD);
    01681     }
    01682
    01683     // Inform the host that a NoA has been stopped
    01684     p2p_go_send_noa_upd_ind(p2p, noa_inst);
    01685
    01686     return CO_OK;
    01687 }
    01688
    01689 #if (NX_CHNL_CTXT)
    01690 void p2p_go_noa_concurrent_move(struct vif_info_tag *vif, int32_t offset)
    01691 {
    01692     struct p2p_info_tag *p2p = &p2p_info_tab[vif->p2p_index];
    01693     bool update_date = false;
    01694     uint8_t noa_idx;
    01695
    01696     for (noa_idx = 0; noa_idx < P2P_NOA_NB_MAX; noa_idx++)
    01697     {
    01698         struct p2p_noa_info_tag *noa = &p2p->noa[noa_idx];
    01699         if ((noa->noa_type == P2P_NOA_TYPE_CONCURRENT) &&
    01700             (noa->noa_status != P2P_NOA_TIMER_NOT_STARTED))
    01701         {
    01702             p2p_noa_timer_prog(noa, noa->noa_timer.time + offset);
    01703             update_date = true;
    01704         }
    01705     }
    01706
    01707     if (update_date)
    01708         p2p_update_noa_presence_date(p2p);
    01709 }
    01710 #endif //(NX_CHNL_CTXT)
    01711
    01712 uint8_t p2p_go_bcn_get_noa_len(uint8_t p2p_index)
    01713 {
    01714     struct p2p_info_tag *p2p = &p2p_info_tab[p2p_index];
    01715     uint8_t noa_ie_len = 0;
    01716
    01717     if ((p2p->vif_index != INVALID_VIF_IDX) && p2p->is_noa_bcn)
    01718     {
    01719         noa_ie_len = P2P_IE_NOA_NO_NOA_DESC_LENGTH
    01720                        + p2p->noa_in_bcn_nb * P2P_NOA_DESC_LENGTH;
    01721     }
    01722
    01723     return (noa_ie_len);
    01724 }
    01725
    01726 void p2p_go_bcn_init_noa_pyld(uint32_t a_noa_ie_elt)
    01727 {
    01728     co_write8p(a_noa_ie_elt + P2P_IE_ID_OFT, P2P_ELMT_ID);
    01729     co_write8p(a_noa_ie_elt + P2P_IE_OUI_OFT, P2P_OUI_WIFI_ALL_BYTE0);
    01730     co_write8p(a_noa_ie_elt + P2P_IE_OUI_OFT + 1, P2P_OUI_WIFI_ALL_BYTE1);
    01731     co_write8p(a_noa_ie_elt + P2P_IE_OUI_OFT + 2, P2P_OUI_WIFI_ALL_BYTE2);
    01732     co_write8p(a_noa_ie_elt + P2P_IE_OUI_TYPE_OFT, P2P_OUI_TYPE_P2P);
    01733     co_write8p(a_noa_ie_elt + P2P_IE_ATT_OFT, P2P_ATT_ID_NOTICE_OF_ABSENCE);
    01734 }
    01735
    01736 void p2p_go_bcn_upd_noa_pyld(uint8_t p2p_index, uint32_t a_noa_ie_elt)
    01737 {
    01738     struct p2p_info_tag *p2p = &p2p_info_tab[p2p_index];
    01739     uint8_t noa_idx, noa_proc_nb = 0;
    01740     uint16_t att_length;
    01741
    01742     TRACE_P2P(NOA_DET, "{VIF-%d} update NOA payload in beacon", p2p->vif_index);
    01743
    01744     co_write8p(a_noa_ie_elt + P2P_IE_ATT_OFT + P2P_NOA_ATT_INDEX_OFT, p2p->noa_index);
    01745
    01746     // Increment NOA index
    01747     p2p->noa_index++;
    01748
    01749     if (p2p->oppps_ctw)
    01750     {
    01751         // If CTWindow is not zero, opportunistic PS is used
    01752         co_write8p(a_noa_ie_elt + P2P_IE_ATT_OFT + P2P_NOA_ATT_CTW_OPPPS_OFT,
    01753                    p2p->oppps_ctw | P2P_OPPPS_MASK);
    01754     }
    01755     else
    01756     {
    01757         co_write8p(a_noa_ie_elt + P2P_IE_ATT_OFT + P2P_NOA_ATT_CTW_OPPPS_OFT, 0);
    01758     }
    01759
    01760     for (noa_idx = 0; noa_idx < P2P_NOA_NB_MAX; noa_idx++)
    01761     {
    01762         struct p2p_noa_info_tag *noa = &p2p->noa[noa_idx];
    01763
    01764         // Check if the NoA instance is active
    01765         // Do not insert non concurrent mode noa if paused due to traffic.
    01766         if ((noa->noa_status != P2P_NOA_TIMER_NOT_STARTED) &&
    01767             !(p2p->noa_paused && noa->dyn_noa && (noa->noa_type == P2P_NOA_TYPE_NORMAL)))
    01768         {
    01769             uint32_t a_noa_desc = a_noa_ie_elt + P2P_IE_ATT_OFT + P2P_NOA_ATT_NOA_DESC_OFT
    01770                                                + (P2P_NOA_DESC_LENGTH * noa_idx);
    01771
    01772             noa_proc_nb++;
    01773
    01774             co_write8p(a_noa_desc + P2P_NOA_DESC_COUNT_OFT, noa->noa_init_counter);
    01775             co_write32p(a_noa_desc + P2P_NOA_DESC_DUR_OFT, noa->noa_dur_us);
    01776             co_write32p(a_noa_desc + P2P_NOA_DESC_INTV_OFT, noa->noa_intv_us);
    01777
    01778
    01779             // Stored start time value is based on Monoatomic counter, value sent within
    01780             // the beacon is a TSF value.
    01781             co_write32p(a_noa_desc + P2P_NOA_DESC_START_OFT,
    01782                         noa->noa_start_time - (ke_time() - nxmac_tsf_lo_get()));
    01783         }
    01784     }
    01785
    01786     // Keep number of NoA in the beacon
    01787     p2p->noa_in_bcn_nb = noa_proc_nb;
    01788
    01789     // Update the length fields
    01790     att_length = 2 + noa_proc_nb * P2P_NOA_DESC_LENGTH;
    01791
    01792     co_write16p(a_noa_ie_elt + P2P_IE_ATT_OFT + P2P_ATT_LEN_OFT, att_length);
    01793     co_write8p(a_noa_ie_elt + P2P_IE_LEN_OFT, 7 + (uint8_t)att_length);
    01794 }
    01795
    01796 void p2p_go_bcn_op_done(uint8_t p2p_index, uint8_t operation)
    01797 {
    01798     struct p2p_info_tag *p2p = &p2p_info_tab[p2p_index];
    01799
    01800     TRACE_P2P(NOA_DET, "{VIF-%d} Beacon updated operation=%d",
    01801               p2p->vif_index, operation);
    01802
    01803     switch (operation)
    01804     {
    01805         case (P2P_BCN_UPD_OP_NOA_ADD):
    01806         {
    01807             p2p->is_noa_bcn = true;
    01808         } break;
    01809
    01810         case (P2P_BCN_UPD_OP_NOA_RMV):
    01811         {
    01812             p2p->is_noa_bcn = false;
    01813         } break;
    01814
    01815         case (P2P_BCN_UPD_OP_NOA_UPD):
    01816         {
    01817             // If the NOA attribute is not part of the beacon, insert it
    01818             if (!p2p->is_noa_bcn)
    01819             {
    01820                 mm_bcn_update_p2p_noa(p2p->vif_index, P2P_BCN_UPD_OP_NOA_ADD);
    01821             }
    01822             // else nothing to do
    01823         } break;
    01824
    01825         default:
    01826         {
    01827             ASSERT_ERR(0);
    01828         }
    01829     }
    01830 }
    01831
    01832 #if (NX_POWERSAVE)
    01833 void p2p_go_pre_tbtt(struct vif_info_tag *vif)
    01834 {
    01835     // Check if VIF is still active
    01836     if (vif->p2p && vif->active)
    01837     {
    01838         // Set bit in order to be sure to be awoken for AP_TBTT interrupt
    01839         // Don't use PS_VIF_P2P_GO_PRESENT has is some corner case P2P GO may become
    01840         // absent between here and the actual AP_TBTT interrupt
    01841         vif->prevent_sleep |= PS_VIF_P2P_WAIT_TBTT;
    01842     }
    01843 }
    01844 #endif //(NX_POWERSAVE)
    01845 #endif //(NX_P2P_GO)
    01846
    01847 #endif //(NX_P2P)
    01848