u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len, enum nl80211_iftype type) { __le16 fc = hdr->frame_control; /* drop ACK/CTS frames and incorrect hdr len (ctrl) */ if (len < 16) return NULL; if (ieee80211_is_data(fc)) { if (len < 24) /* drop incorrect hdr len (data) */ return NULL; if (ieee80211_has_a4(fc)) return NULL; if (ieee80211_has_tods(fc)) return hdr->addr1; if (ieee80211_has_fromds(fc)) return hdr->addr2; return hdr->addr3; } if (ieee80211_is_mgmt(fc)) { if (len < 24) /* drop incorrect hdr len (mgmt) */ return NULL; return hdr->addr3; } if (ieee80211_is_ctl(fc)) { if(ieee80211_is_pspoll(fc)) return hdr->addr1; if (ieee80211_is_back_req(fc)) { switch (type) { case NL80211_IFTYPE_STATION: return hdr->addr2; case NL80211_IFTYPE_AP: case NL80211_IFTYPE_AP_VLAN: return hdr->addr1; default: break; /* fall through to the return */ } } } return NULL; }
static void mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb) { struct mt76_rx_status *status = (struct mt76_rx_status *) skb->cb; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; struct ieee80211_sta *sta; struct mt76_wcid *wcid = status->wcid; bool ps; int i; if (ieee80211_is_pspoll(hdr->frame_control) && !wcid) { sta = ieee80211_find_sta_by_ifaddr(dev->hw, hdr->addr2, NULL); if (sta) wcid = status->wcid = (struct mt76_wcid *) sta->drv_priv; } if (!wcid || !wcid->sta) return; sta = container_of((void *) wcid, struct ieee80211_sta, drv_priv); if (status->signal <= 0) ewma_signal_add(&wcid->rssi, -status->signal); wcid->inactive_count = 0; if (!test_bit(MT_WCID_FLAG_CHECK_PS, &wcid->flags)) return; if (ieee80211_is_pspoll(hdr->frame_control)) { ieee80211_sta_pspoll(sta); return; } if (ieee80211_has_morefrags(hdr->frame_control) || !(ieee80211_is_mgmt(hdr->frame_control) || ieee80211_is_data(hdr->frame_control))) return; ps = ieee80211_has_pm(hdr->frame_control); if (ps && (ieee80211_is_data_qos(hdr->frame_control) || ieee80211_is_qos_nullfunc(hdr->frame_control))) ieee80211_sta_uapsd_trigger(sta, status->tid); if (!!test_bit(MT_WCID_FLAG_PS, &wcid->flags) == ps) return; if (ps) set_bit(MT_WCID_FLAG_PS, &wcid->flags); else clear_bit(MT_WCID_FLAG_PS, &wcid->flags); dev->drv->sta_ps(dev, sta, ps); ieee80211_sta_ps_transition(sta, ps); if (ps) return; for (i = 0; i < ARRAY_SIZE(sta->txq); i++) { struct mt76_txq *mtxq; if (!sta->txq[i]) continue; mtxq = (struct mt76_txq *) sta->txq[i]->drv_priv; if (!skb_queue_empty(&mtxq->retry_q)) ieee80211_schedule_txq(dev->hw, sta->txq[i]); } }