/* * Handler for add tspec request. */ int ieee80211_admctl_addts(struct ieee80211_node *ni, struct ieee80211_wme_tspec* tspec) { struct ieee80211vap *vap = ni->ni_vap; u_int8_t ac; struct ieee80211_admctl_tsentry *tsentry; struct ieee80211_admctl_priv *admctl_priv = ni->ni_admctl_priv; ieee80211_tspec_info ts; admctl_tspec_to_tsinfo(tspec, &ts); ac = TID_TO_WME_AC(ts.dot1Dtag); IEEE80211_DPRINTF(vap, IEEE80211_MSG_ACTION, "ADDTS requested for AC %d \n", ac); /* check ACM set for this accesscategory */ if (wlan_get_wmm_param(vap, WLAN_WME_ACM, 1, ac)) { IEEE80211_DPRINTF(vap, IEEE80211_MSG_ACTION, "%s \n", "Processing ADDTS Req"); /* admission control is required for this AC */ tsentry = ieee80211_find_tsentry(admctl_priv, ts.tid); if (!tsentry) { /* create the traffic stream */ tsentry = ieee80211_add_tsentry(admctl_priv, ac, ts.tid); /* copy the ts info */ OS_MEMCPY(&tsentry->ts_info, &ts, sizeof(ieee80211_tspec_info)); } else { } /* compute medium_time - in units of 32 us */ tsentry->ts_info.medium_time = admctl_compute_medium_time(ni, vap, &ts); if ((ts.direction == ADMCTL_TSPEC_UPLINK) || (ts.direction == ADMCTL_TSPEC_BIDI) ) { *((u_int16_t *) &tspec->ts_medium_time[0]) = htole16((u_int16_t)(tsentry->ts_info.medium_time)); } else { /* For downlink only TSPEC set the medium time to 0 */ *((u_int16_t *) &tspec->ts_medium_time[0]) = 0; } } else { /* Addmission control is not required. Ignoring addts req */ IEEE80211_DPRINTF(vap, IEEE80211_MSG_ACTION, "%s \n", "Ignoring ADDTS : ACM is not set"); } return IEEE80211_STATUS_SUCCESS; }
int ieee80211_admctl_send_delts(struct ieee80211vap *vap, u_int8_t *macaddr, u_int8_t tid) { int error = 0; u_int8_t ac; struct ieee80211_admctl_tsentry *tsentry; struct ieee80211_admctl_priv *admctl_priv; struct ieee80211_node *ni; ni = ieee80211_find_txnode(vap, macaddr); if (ni == NULL) { error = -EINVAL; return error; } admctl_priv = ni->ni_admctl_priv; /* Get tspec */ ac = TID_TO_WME_AC(tid); IEEE80211_DPRINTF(vap, IEEE80211_MSG_ACTION, "%s : DELTS requested for AC %d \n", __func__, ac); /* admission control is required for this AC */ tsentry = ieee80211_find_tsentry(admctl_priv, tid); if (!tsentry) { IEEE80211_DPRINTF(vap, IEEE80211_MSG_ACTION, "%s : could not find TS entry for AC %d \n", __func__, ac); return -EINVAL; } error = wlan_send_delts(vap, macaddr, &tsentry->ts_info); if (!error) { error = ieee80211_remove_tsentry(admctl_priv, tid); if (!error) { IEEE80211_DPRINTF(vap, IEEE80211_MSG_ACTION, "%s : could not remove the tsentry \n", __func__); return -EINVAL; } } else { IEEE80211_DPRINTF(vap, IEEE80211_MSG_ACTION, "%s : wlan_send_delts is failed \n", __func__); } ieee80211_free_node(ni); return error; }
/** * rsi_core_xmit() - This function transmits the packets received from mac80211 * @common: Pointer to the driver private structure. * @skb: Pointer to the socket buffer structure. * * Return: None. */ void rsi_core_xmit(struct rsi_common *common, struct sk_buff *skb) { struct rsi_hw *adapter = common->priv; struct ieee80211_tx_info *info; struct skb_info *tx_params; struct ieee80211_hdr *wh = NULL; struct ieee80211_vif *vif; u8 q_num, tid = 0; struct rsi_sta *rsta = NULL; if ((!skb) || (!skb->len)) { rsi_dbg(ERR_ZONE, "%s: Null skb/zero Length packet\n", __func__); goto xmit_fail; } if (common->fsm_state != FSM_MAC_INIT_DONE) { rsi_dbg(ERR_ZONE, "%s: FSM state not open\n", __func__); goto xmit_fail; } if (common->wow_flags & RSI_WOW_ENABLED) { rsi_dbg(ERR_ZONE, "%s: Blocking Tx_packets when WOWLAN is enabled\n", __func__); goto xmit_fail; } info = IEEE80211_SKB_CB(skb); tx_params = (struct skb_info *)info->driver_data; wh = (struct ieee80211_hdr *)&skb->data[0]; tx_params->sta_id = 0; vif = rsi_get_vif(adapter, wh->addr2); if (!vif) goto xmit_fail; tx_params->vif = vif; tx_params->vap_id = ((struct vif_priv *)vif->drv_priv)->vap_id; if ((ieee80211_is_mgmt(wh->frame_control)) || (ieee80211_is_ctl(wh->frame_control)) || (ieee80211_is_qos_nullfunc(wh->frame_control))) { if (ieee80211_is_assoc_req(wh->frame_control) || ieee80211_is_reassoc_req(wh->frame_control)) { struct ieee80211_bss_conf *bss = &vif->bss_conf; common->eapol4_confirm = false; rsi_hal_send_sta_notify_frame(common, RSI_IFTYPE_STATION, STA_CONNECTED, bss->bssid, bss->qos, bss->aid, 0, vif); } q_num = MGMT_SOFT_Q; skb->priority = q_num; if (rsi_prepare_mgmt_desc(common, skb)) { rsi_dbg(ERR_ZONE, "Failed to prepare desc\n"); goto xmit_fail; } } else { if (ieee80211_is_data_qos(wh->frame_control)) { u8 *qos = ieee80211_get_qos_ctl(wh); tid = *qos & IEEE80211_QOS_CTL_TID_MASK; skb->priority = TID_TO_WME_AC(tid); } else { tid = IEEE80211_NONQOS_TID; skb->priority = BE_Q; } q_num = skb->priority; tx_params->tid = tid; if (((vif->type == NL80211_IFTYPE_AP) || (vif->type == NL80211_IFTYPE_P2P_GO)) && (!is_broadcast_ether_addr(wh->addr1)) && (!is_multicast_ether_addr(wh->addr1))) { rsta = rsi_find_sta(common, wh->addr1); if (!rsta) goto xmit_fail; tx_params->sta_id = rsta->sta_id; } else { tx_params->sta_id = 0; } if (rsta) { /* Start aggregation if not done for this tid */ if (!rsta->start_tx_aggr[tid]) { rsta->start_tx_aggr[tid] = true; ieee80211_start_tx_ba_session(rsta->sta, tid, 0); } } if (skb->protocol == cpu_to_be16(ETH_P_PAE)) { q_num = MGMT_SOFT_Q; skb->priority = q_num; } if (rsi_prepare_data_desc(common, skb)) { rsi_dbg(ERR_ZONE, "Failed to prepare data desc\n"); goto xmit_fail; } } if ((q_num < MGMT_SOFT_Q) && ((skb_queue_len(&common->tx_queue[q_num]) + 1) >= DATA_QUEUE_WATER_MARK)) { rsi_dbg(ERR_ZONE, "%s: sw queue full\n", __func__); if (!ieee80211_queue_stopped(adapter->hw, WME_AC(q_num))) ieee80211_stop_queue(adapter->hw, WME_AC(q_num)); rsi_set_event(&common->tx_thread.event); goto xmit_fail; } rsi_core_queue_pkt(common, skb); rsi_dbg(DATA_TX_ZONE, "%s: ===> Scheduling TX thread <===\n", __func__); rsi_set_event(&common->tx_thread.event); return; xmit_fail: rsi_dbg(ERR_ZONE, "%s: Failed to queue packet\n", __func__); /* Dropping pkt here */ ieee80211_free_txskb(common->priv->hw, skb); }
/* * process the tspec request and fill in the tspec response */ int ieee80211_admctl_process_addts_req(struct ieee80211_node *ni, ieee80211_tspec_info* tsinfo, int dialog_token) { struct ieee80211vap *vap = ni->ni_vap; u_int8_t *macaddr = ni->ni_macaddr; u_int8_t ac; u_int16_t medium_time; struct ieee80211_admctl_tsentry *tsentry; struct ieee80211_admctl_priv *admctl_priv = ni->ni_admctl_priv; /* Get tspec */ ac = TID_TO_WME_AC(tsinfo->dot1Dtag); IEEE80211_DPRINTF(vap, IEEE80211_MSG_ACTION, "%s : ADDTS requested for AC %d \n", __func__, ac); /* check ACM set for this accesscategory */ IEEE80211_DPRINTF(vap, IEEE80211_MSG_ACTION, "%s \n", "Processing ADDTS Req"); /* compute medium_time */ medium_time = admctl_compute_medium_time(ni, vap, tsinfo); if (ieee80211_check_medium_time(vap, ni, medium_time)) { /* medium_time is not available */ IEEE80211_DPRINTF(vap, IEEE80211_MSG_ACTION, "%s \n", "ADDTS REFUSED - No available medium time "); wlan_send_addts_resp(vap, macaddr, tsinfo, ADMCTL_ADDTS_RESP_REFUSED, dialog_token); return 0; } /* admission control is required for this AC */ tsentry = ieee80211_find_tsentry(admctl_priv, tsinfo->tid); if (!tsentry) { tsentry = ieee80211_add_replace_tsentry(ni, ac, tsinfo); } else { if (tsentry->ts_ac == ac) { if (tsinfo->direction == tsentry->ts_info.direction) { u_int16_t old_mediumtime; /* replace tspec, but restore previous medium time */ old_mediumtime = tsentry->ts_info.medium_time; OS_MEMCPY(&tsentry->ts_info, tsinfo, sizeof(ieee80211_tspec_info)); ieee80211_parse_psb(ni, tsinfo->direction, tsinfo->psb, ac); tsentry->ts_info.medium_time = old_mediumtime; } else { ieee80211_remove_ac_tsentries(admctl_priv, ac); tsentry = ieee80211_add_tsentry(admctl_priv, ac, tsinfo->tid); OS_MEMCPY(&tsentry->ts_info, tsinfo, sizeof(ieee80211_tspec_info)); tsentry->ts_info.medium_time = 0; ieee80211_parse_psb(ni, tsinfo->direction, tsinfo->psb, ac); } } else { IEEE80211_DPRINTF(vap, IEEE80211_MSG_ACTION, "%s \n", "ADDTS REFUSED for INVALID PARAM"); wlan_send_addts_resp(vap, macaddr, tsinfo, ADMCTL_ADDTS_RESP_INVALID_PARAM, dialog_token); return 0; } } if (tsentry->ts_info.medium_time > medium_time) vap->iv_ic->ic_mediumtime_reserved -= tsentry->ts_info.medium_time - medium_time; else vap->iv_ic->ic_mediumtime_reserved += medium_time - tsentry->ts_info.medium_time; /* update medium_time */ tsentry->ts_info.medium_time = medium_time; if ((tsinfo->direction == ADMCTL_TSPEC_UPLINK) || (tsinfo->direction == ADMCTL_TSPEC_BIDI) ) { tsinfo->medium_time = tsentry->ts_info.medium_time; } else { /* For downlink only TSPEC set the medium time to 0 */ tsinfo->medium_time = 0; } if (wlan_get_wmm_param(vap, WLAN_WME_ACM, 1, ac) == 0) { tsinfo->medium_time = 0; } /* send addts response */ IEEE80211_DPRINTF(vap, IEEE80211_MSG_ACTION, "%s \n", "ADDTS Accepted"); wlan_send_addts_resp(vap, macaddr, tsinfo, 0, dialog_token); return 0; }
/* * 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; }
/* * Process a received frame. The node associated with the sender * should be supplied. If nothing was found in the node table then * the caller is assumed to supply a reference to ic_bss instead. * The RSSI and a timestamp are also supplied. The RSSI data is used * during AP scanning to select a AP to associate with; it can have * any units so long as values have consistent units and higher values * mean ``better signal''. The receive timestamp is currently not used * by the 802.11 layer. */ int ieee80211_input(ieee80211com_t *ic, mblk_t *mp, struct ieee80211_node *in, int32_t rssi, uint32_t rstamp) { struct ieee80211_frame *wh; struct ieee80211_key *key; uint8_t *bssid; int hdrspace; int len; uint16_t rxseq; uint8_t dir; uint8_t type; uint8_t subtype; uint8_t tid; uint8_t qos; if (mp->b_flag & M_AMPDU) { /* * Fastpath for A-MPDU reorder q resubmission. Frames * w/ M_AMPDU marked have already passed through here * but were received out of order and been held on the * reorder queue. When resubmitted they are marked * with the M_AMPDU flag and we can bypass most of the * normal processing. */ IEEE80211_LOCK(ic); wh = (struct ieee80211_frame *)mp->b_rptr; type = IEEE80211_FC0_TYPE_DATA; dir = wh->i_fc[1] & IEEE80211_FC1_DIR_MASK; subtype = IEEE80211_FC0_SUBTYPE_QOS; hdrspace = ieee80211_hdrspace(ic, wh); /* optimize */ /* clear driver/net80211 flags before passing up */ mp->b_flag &= ~M_AMPDU; goto resubmit_ampdu; } ASSERT(in != NULL); in->in_inact = in->in_inact_reload; type = (uint8_t)-1; /* undefined */ len = MBLKL(mp); if (len < sizeof (struct ieee80211_frame_min)) { ieee80211_dbg(IEEE80211_MSG_ANY, "ieee80211_input: " "too short (1): len %u", len); goto out; } /* * Bit of a cheat here, we use a pointer for a 3-address * frame format but don't reference fields past outside * ieee80211_frame_min w/o first validating the data is * present. */ wh = (struct ieee80211_frame *)mp->b_rptr; if ((wh->i_fc[0] & IEEE80211_FC0_VERSION_MASK) != IEEE80211_FC0_VERSION_0) { ieee80211_dbg(IEEE80211_MSG_ANY, "ieee80211_input: " "discard pkt with wrong version %x", wh->i_fc[0]); goto out; } dir = wh->i_fc[1] & IEEE80211_FC1_DIR_MASK; type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; IEEE80211_LOCK(ic); if (!(ic->ic_flags & IEEE80211_F_SCAN)) { switch (ic->ic_opmode) { case IEEE80211_M_STA: bssid = wh->i_addr2; if (!IEEE80211_ADDR_EQ(bssid, in->in_bssid)) goto out_exit_mutex; break; case IEEE80211_M_IBSS: case IEEE80211_M_AHDEMO: if (dir != IEEE80211_FC1_DIR_NODS) { bssid = wh->i_addr1; } else if (type == IEEE80211_FC0_TYPE_CTL) { bssid = wh->i_addr1; } else { if (len < sizeof (struct ieee80211_frame)) { ieee80211_dbg(IEEE80211_MSG_ANY, "ieee80211_input: too short(2):" "len %u\n", len); goto out_exit_mutex; } bssid = wh->i_addr3; } if (type != IEEE80211_FC0_TYPE_DATA) break; /* * Data frame, validate the bssid. */ if (!IEEE80211_ADDR_EQ(bssid, ic->ic_bss->in_bssid) && !IEEE80211_ADDR_EQ(bssid, wifi_bcastaddr)) { /* not interested in */ ieee80211_dbg(IEEE80211_MSG_INPUT, "ieee80211_input: not to bss %s\n", ieee80211_macaddr_sprintf(bssid)); goto out_exit_mutex; } /* * For adhoc mode we cons up a node when it doesn't * exist. This should probably done after an ACL check. */ if (in == ic->ic_bss && ic->ic_opmode != IEEE80211_M_HOSTAP && !IEEE80211_ADDR_EQ(wh->i_addr2, in->in_macaddr)) { /* * Fake up a node for this newly * discovered member of the IBSS. */ in = ieee80211_fakeup_adhoc_node(&ic->ic_sta, wh->i_addr2); if (in == NULL) { /* NB: stat kept for alloc failure */ goto out_exit_mutex; } } break; default: goto out_exit_mutex; } in->in_rssi = (uint8_t)rssi; in->in_rstamp = rstamp; if (!(type & IEEE80211_FC0_TYPE_CTL)) { if (IEEE80211_QOS_HAS_SEQ(wh)) { tid = ((struct ieee80211_qosframe *)wh)-> i_qos[0] & IEEE80211_QOS_TID; if (TID_TO_WME_AC(tid) >= WME_AC_VI) ic->ic_wme.wme_hipri_traffic++; tid++; } else { tid = IEEE80211_NONQOS_TID; } rxseq = LE_16(*(uint16_t *)wh->i_seq); if ((in->in_flags & IEEE80211_NODE_HT) == 0 && (wh->i_fc[1] & IEEE80211_FC1_RETRY) && (rxseq - in->in_rxseqs[tid]) <= 0) { /* duplicate, discard */ ieee80211_dbg(IEEE80211_MSG_INPUT, "ieee80211_input: duplicate", "seqno <%u,%u> fragno <%u,%u> tid %u", rxseq >> IEEE80211_SEQ_SEQ_SHIFT, in->in_rxseqs[tid] >> IEEE80211_SEQ_SEQ_SHIFT, rxseq & IEEE80211_SEQ_FRAG_MASK, in->in_rxseqs[tid] & IEEE80211_SEQ_FRAG_MASK, tid); ic->ic_stats.is_rx_dups++; goto out_exit_mutex; } in->in_rxseqs[tid] = rxseq; } }
/* * 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; }
if (eh->ether_type == __constant_htons(ETHERTYPE_IP)) { const struct iphdr *ip = (struct iphdr *) (wbuf->data + sizeof (struct ether_header)); ac = dscp_to_wmm(vap,(ip->tos >> 2)); } else if(eh->ether_type == __constant_htons(ETHERTYPE_IPV6)) { struct ipv6hdr * ipv6h = (struct ipv6hdr*)(wbuf->data + sizeof(struct ether_header)); unsigned char tos = 0; tos = ipv6h->priority; tos = tos << 4; tos |= (ipv6h->flow_lbl[0] >> 4); tid = dscp_to_wmm(vap,(tos >> 2)); ac = TID_TO_WME_AC(tid); } return ac; } /*return ac */ u_int8_t ieee80211_vlan_priv_to_wmm(struct ieee80211vap *vap,u_int8_t v_priv) { u_int8_t ac = WME_AC_BE; if( v_priv > 7){ vap->priv_wmm.vlan_to_wmm_error ++; return WME_AC_BE; }
/** * rsi_core_xmit() - This function transmits the packets received from mac80211 * @common: Pointer to the driver private structure. * @skb: Pointer to the socket buffer structure. * * Return: None. */ void rsi_core_xmit(struct rsi_common *common, struct sk_buff *skb) { struct rsi_hw *adapter = common->priv; struct ieee80211_tx_info *info; struct skb_info *tx_params; struct ieee80211_hdr *tmp_hdr = NULL; u8 q_num, tid = 0; if ((!skb) || (!skb->len)) { rsi_dbg(ERR_ZONE, "%s: Null skb/zero Length packet\n", __func__); goto xmit_fail; } info = IEEE80211_SKB_CB(skb); tx_params = (struct skb_info *)info->driver_data; tmp_hdr = (struct ieee80211_hdr *)&skb->data[0]; if (common->fsm_state != FSM_MAC_INIT_DONE) { rsi_dbg(ERR_ZONE, "%s: FSM state not open\n", __func__); goto xmit_fail; } if ((ieee80211_is_mgmt(tmp_hdr->frame_control)) || (ieee80211_is_ctl(tmp_hdr->frame_control)) || (ieee80211_is_qos_nullfunc(tmp_hdr->frame_control))) { q_num = MGMT_SOFT_Q; skb->priority = q_num; } else { if (ieee80211_is_data_qos(tmp_hdr->frame_control)) { tid = (skb->data[24] & IEEE80211_QOS_TID); skb->priority = TID_TO_WME_AC(tid); } else { tid = IEEE80211_NONQOS_TID; skb->priority = BE_Q; } q_num = skb->priority; tx_params->tid = tid; tx_params->sta_id = 0; } if ((q_num != MGMT_SOFT_Q) && ((skb_queue_len(&common->tx_queue[q_num]) + 1) >= DATA_QUEUE_WATER_MARK)) { rsi_dbg(ERR_ZONE, "%s: sw queue full\n", __func__); if (!ieee80211_queue_stopped(adapter->hw, WME_AC(q_num))) ieee80211_stop_queue(adapter->hw, WME_AC(q_num)); rsi_set_event(&common->tx_thread.event); goto xmit_fail; } rsi_core_queue_pkt(common, skb); rsi_dbg(DATA_TX_ZONE, "%s: ===> Scheduling TX thead <===\n", __func__); rsi_set_event(&common->tx_thread.event); return; xmit_fail: rsi_dbg(ERR_ZONE, "%s: Failed to queue packet\n", __func__); /* Dropping pkt here */ ieee80211_free_txskb(common->priv->hw, skb); }