int32_t ath_net80211_aow_update_ie(ieee80211_handle_t ieee, u_int8_t* data, u_int32_t len, u_int32_t action) { struct ieee80211com *ic = NET80211_HANDLE(ieee); if (action) { return ieee80211_update_aow_ie(ic, data, len); }else{ return ieee80211_delete_aow_ie(ic); } }
void ath_net80211_uapsd_creditupdate(ieee80211_handle_t ieee) { #ifdef MAGPIE_HIF_GMAC struct ieee80211com *ic = NET80211_HANDLE(ieee); struct ath_softc_net80211 *scn = ATH_SOFTC_NET80211(ic); ieee80211_iterate_node(ic, ath_net80211_drain_uapsd, scn); #endif }
void ath_htc_wmm_update(ieee80211_handle_t ieee) { struct ieee80211com *ic = NET80211_HANDLE(ieee); /* Because we change the callback function for wme_update, we can't use ic->ic_wme.wme_update for WMM paramter delay update, or we might get problems */ ath_htc_wmm_update_params(ic); }
wbuf_t ath_net80211_uapsd_allocqosnullframe(ieee80211_handle_t ieee) { wbuf_t wbuf; struct ieee80211com *ic = NET80211_HANDLE(ieee); wbuf = wbuf_alloc(ic->ic_osdev, WBUF_TX_MGMT, sizeof(struct ieee80211_qosframe)); if (wbuf != NULL) wbuf_push(wbuf, sizeof(struct ieee80211_qosframe)); return wbuf; }
void ath_net80211_uapsd_process_uapsd_trigger(ieee80211_handle_t ieee, struct ieee80211_node *ni, bool enforce_max_sp, bool *sent_eosp) { struct ieee80211com *ic = NET80211_HANDLE(ieee); struct ath_softc_net80211 *scn = ATH_SOFTC_NET80211(ic); if (enforce_max_sp) { scn->sc_ops->process_uapsd_trigger(scn->sc_dev, ATH_NODE_NET80211(ni)->an_sta, ni->ni_uapsd_maxsp, 0, 0, sent_eosp, WME_UAPSD_NODE_MAXQDEPTH); } else { scn->sc_ops->process_uapsd_trigger(scn->sc_dev, ATH_NODE_NET80211(ni)->an_sta, WME_UAPSD_NODE_MAXQDEPTH, 0, 1, sent_eosp, WME_UAPSD_NODE_MAXQDEPTH); } return; }
int32_t ath_net80211_aow_send_to_host(ieee80211_handle_t ieee, u_int8_t* data, u_int32_t len, u_int16_t type, u_int16_t subtype, u_int8_t* addr) { struct ieee80211com *ic = NET80211_HANDLE(ieee); return ieee80211_aow_send_to_host(ic, data, len, type, subtype, NULL); }
int16_t ath_net80211_aow_apktindex(ieee80211_handle_t ieee, wbuf_t wbuf) { struct ieee80211com *ic = NET80211_HANDLE(ieee); return ieee80211_aow_apktindex(ic, wbuf); }
int ath_net80211_aow_consume_audio_data(ieee80211_handle_t ieee, u_int64_t tsf) { struct ieee80211com *ic = NET80211_HANDLE(ieee); return ieee80211_consume_audio_data( ic, tsf); }
u_int32_t ath_net80211_i2s_write_interrupt(ieee80211_handle_t ieee) { struct ieee80211com *ic = NET80211_HANDLE(ieee); return ieee80211_i2s_write_interrupt(ic); }
int32_t ath_net80211_aow_update_volume(ieee80211_handle_t ieee, u_int8_t* data, u_int32_t len) { struct ieee80211com *ic = NET80211_HANDLE(ieee); return ieee80211_aow_update_volume(ic, data, len); }
int32_t ath_net80211_aow_request_version(ieee80211_handle_t ieee) { struct ieee80211com *ic = NET80211_HANDLE(ieee); return ieee80211_aow_request_version(ic); }
/* * This function determines whether the received frame is a valid UAPSD trigger. * Called from interrupt context or DPC context depending on parameter isr_context. */ bool ath_net80211_check_uapsdtrigger(ieee80211_handle_t ieee, struct ieee80211_qosframe *qwh, u_int16_t keyix, bool isr_context) { struct ieee80211com *ic = NET80211_HANDLE(ieee); struct ath_softc_net80211 *scn = ATH_SOFTC_NET80211(ic); struct ieee80211_node *ni; int tid, ac; u_int16_t frame_seq; int queue_depth; bool isapsd = false; /* * Locate the node for sender */ IEEE80211_KEYMAP_LOCK(scn); ni = (keyix != HAL_RXKEYIX_INVALID) ? scn->sc_keyixmap[keyix] : NULL; if (ni == NULL) { IEEE80211_KEYMAP_UNLOCK(scn); /* * No key index or no entry, do a lookup */ if (isr_context) { ni = ieee80211_find_rxnode_nolock(ic, (struct ieee80211_frame_min *)qwh); } else { ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min *)qwh); } if (ni == NULL) { return isapsd; } } else { ieee80211_ref_node(ni); IEEE80211_KEYMAP_UNLOCK(scn); } if (!(ni->ni_flags & IEEE80211_NODE_UAPSD)) goto end; if (ni->ni_flags & IEEE80211_NODE_UAPSD_SP) goto end; /* * Must deal with change of state here, since otherwise there would * be a race (on two quick frames from STA) between this code and the * tasklet where we would: * - miss a trigger on entry to PS if we're already trigger hunting * - generate spurious SP on exit (due to frame following exit frame) */ if ((((qwh->i_fc[1] & IEEE80211_FC1_PWR_MGT) == IEEE80211_FC1_PWR_MGT) ^ ((ni->ni_flags & IEEE80211_NODE_UAPSD_TRIG) == IEEE80211_NODE_UAPSD_TRIG))) { ni->ni_flags &= ~IEEE80211_NODE_UAPSD_SP; if (qwh->i_fc[1] & IEEE80211_FC1_PWR_MGT) { WME_UAPSD_NODE_TRIGSEQINIT(ni); ni->ni_stats.ns_uapsd_triggerenabled++; ni->ni_flags |= IEEE80211_NODE_UAPSD_TRIG; } else { /* * Node transitioned from UAPSD -> Active state. Flush out UAPSD frames */ ni->ni_stats.ns_uapsd_active++; ni->ni_flags &= ~IEEE80211_NODE_UAPSD_TRIG; scn->sc_ops->process_uapsd_trigger(scn->sc_dev, ATH_NODE_NET80211(ni)->an_sta, WME_UAPSD_NODE_MAXQDEPTH, 0, 1, WME_UAPSD_NODE_MAXQDEPTH); } goto end; } /* * Check for a valid trigger frame i.e. QoS Data or QoS NULL */ if ( ((qwh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_DATA ) || !(qwh->i_fc[0] & IEEE80211_FC0_SUBTYPE_QOS) ) { goto end; } if (((qwh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_DATA) && (((qwh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == IEEE80211_FC0_SUBTYPE_QOS) || ((qwh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == IEEE80211_FC0_SUBTYPE_QOS_NULL))) { tid = qwh->i_qos[0] & IEEE80211_QOS_TID; ac = TID_TO_WME_AC(tid); isapsd = true; if (WME_UAPSD_AC_CAN_TRIGGER(ac, ni)) { /* * Detect duplicate triggers and drop if so. */ frame_seq = le16toh(*(u_int16_t *)qwh->i_seq); if ((qwh->i_fc[1] & IEEE80211_FC1_RETRY) && frame_seq == ni->ni_uapsd_trigseq[ac]) { ni->ni_stats.ns_uapsd_duptriggers++; goto end; } /* * SP in progress for this node, discard trigger. */ if (ni->ni_flags & IEEE80211_NODE_UAPSD_SP) { ni->ni_stats.ns_uapsd_ignoretriggers++; goto end; } /* start the SP */ ni->ni_stats.ns_uapsd_triggers++; ni->ni_flags |= IEEE80211_NODE_UAPSD_SP; ni->ni_uapsd_trigseq[ac] = frame_seq; queue_depth = scn->sc_ops->process_uapsd_trigger(scn->sc_dev, ATH_NODE_NET80211(ni)->an_sta, ni->ni_uapsd_maxsp, ac, 0, WME_UAPSD_NODE_MAXQDEPTH); if (!queue_depth && (ni->ni_vap->iv_set_tim != NULL) && IEEE80211_NODE_UAPSD_USETIM(ni)) { ni->ni_vap->iv_set_tim(ni, 0); } } } end: ieee80211_free_node(ni); return isapsd; }
/* * This function is called for each frame received on the high priority queue. * If the hardware has classified this frame as a UAPSD trigger, we locate the node * and deliver data. * For non-trigger frames, we check for PM transition. * Called from interrupt context. */ void ath_net80211_uapsd_deliverdata(ieee80211_handle_t ieee, struct ieee80211_qosframe *qwh, u_int16_t keyix, u_int8_t is_trig, bool isr_context) { struct ieee80211com *ic = NET80211_HANDLE(ieee); struct ath_softc_net80211 *scn = ATH_SOFTC_NET80211(ic); struct ieee80211_node *ni; int tid, ac; u_int16_t frame_seq; int queue_depth; bool sent_eosp = false; UNREFERENCED_PARAMETER(isr_context); /* * Locate the node for sender */ IEEE80211_KEYMAP_LOCK(scn); ni = (keyix != HAL_RXKEYIX_INVALID) ? scn->sc_keyixmap[keyix] : NULL; IEEE80211_KEYMAP_UNLOCK(scn); if (ni == NULL) { /* * No key index or no entry, do a lookup */ ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min *)qwh); if (ni == NULL) { return; } } else { ieee80211_ref_node(ni); } if (!(ni->ni_flags & IEEE80211_NODE_UAPSD) || (ni->ni_flags & IEEE80211_NODE_ATH_PAUSED)) goto end; /* We cannot have a PM state change if this is a trigger frame */ if (!is_trig) { /* * Must deal with change of state here, since otherwise there would * be a race (on two quick frames from STA) between this code and the * tasklet where we would: * - miss a trigger on entry to PS if we're already trigger hunting * - generate spurious SP on exit (due to frame following exit frame) */ if ((((qwh->i_fc[1] & IEEE80211_FC1_PWR_MGT) == IEEE80211_FC1_PWR_MGT) ^ ((ni->ni_flags & IEEE80211_NODE_UAPSD_TRIG) == IEEE80211_NODE_UAPSD_TRIG))) { ni->ni_flags &= ~IEEE80211_NODE_UAPSD_SP; if (qwh->i_fc[1] & IEEE80211_FC1_PWR_MGT) { WME_UAPSD_NODE_TRIGSEQINIT(ni); ni->ni_stats.ns_uapsd_triggerenabled++; ni->ni_flags |= IEEE80211_NODE_UAPSD_TRIG; } else { /* * Node transitioned from UAPSD -> Active state. Flush out UAPSD frames */ ni->ni_stats.ns_uapsd_active++; ni->ni_flags &= ~IEEE80211_NODE_UAPSD_TRIG; scn->sc_ops->process_uapsd_trigger(scn->sc_dev, ATH_NODE_NET80211(ni)->an_sta, WME_UAPSD_NODE_MAXQDEPTH, 0, 1, &sent_eosp, WME_UAPSD_NODE_MAXQDEPTH); } goto end; } } else { /* Is UAPSD trigger */ tid = qwh->i_qos[0] & IEEE80211_QOS_TID; ac = TID_TO_WME_AC(tid); if (WME_UAPSD_AC_CAN_TRIGGER(ac, ni)) { /* * Detect duplicate triggers and drop if so. */ frame_seq = le16toh(*(u_int16_t *)qwh->i_seq); if ((qwh->i_fc[1] & IEEE80211_FC1_RETRY) && frame_seq == ni->ni_uapsd_trigseq[ac]) { ni->ni_stats.ns_uapsd_duptriggers++; DPRINTF(scn, ATH_DEBUG_UAPSD, "%s : Drop duplicate trigger\n", __func__); goto end; } if (IEEE80211_IS_TDLS_NODE(ni)) { /* * TDLS defines any QoS frame with EOSP * set to be a non-trigger frame. Therefore, * ignore trigger. */ if(qwh->i_qos[0] & IEEE80211_QOS_EOSP) { ni->ni_stats.ns_uapsd_ignoretriggers++; DPRINTF(scn, ATH_DEBUG_UAPSD, "%s : TDLS QOS frame with EOSP; ignore trigger\n", __func__); goto end; } } /* * SP in progress for this node, discard trigger. */ if (ni->ni_flags & IEEE80211_NODE_UAPSD_SP) { ni->ni_stats.ns_uapsd_ignoretriggers++; DPRINTF(scn, ATH_DEBUG_UAPSD, "%s : SP in-progress; ignore trigger\n", __func__); goto end; } ni->ni_stats.ns_uapsd_triggers++; DPRINTF(scn, ATH_DEBUG_UAPSD, "%s : Start SP\n", __func__); queue_depth = scn->sc_ops->process_uapsd_trigger(scn->sc_dev, ATH_NODE_NET80211(ni)->an_sta, ni->ni_uapsd_maxsp, ac, 0, &sent_eosp, WME_UAPSD_NODE_MAXQDEPTH); if (queue_depth == -1) goto end; /* start the SP */ ni->ni_flags |= IEEE80211_NODE_UAPSD_SP; ni->ni_uapsd_trigseq[ac] = frame_seq; if (IEEE80211_IS_TDLS_NODE(ni)) { if (sent_eosp) { ni->ni_flags &= ~IEEE80211_NODE_UAPSD_SP; DPRINTF(scn, ATH_DEBUG_UAPSD, "%s : TDLS; End SP\n", __func__); } } else { if (!queue_depth && (ni->ni_vap->iv_set_tim != NULL) && IEEE80211_NODE_UAPSD_USETIM(ni)) { ni->ni_vap->iv_set_tim(ni, 0, isr_context); } } } } end: ieee80211_free_node(ni); return; }