static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
struct tid_ampdu_rx *tid_agg_rx,
struct sk_buff *skb,
+ struct ieee80211_rx_status *status,
u16 mpdu_seq_num,
int bar_req);
/*
if (status->flag & RX_FLAG_TSFT)
len += 8;
- if (local->hw.flags & IEEE80211_HW_SIGNAL_DB ||
- local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
+ if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
len += 1;
if (local->hw.flags & IEEE80211_HW_NOISE_DBM)
len += 1;
/* IEEE80211_RADIOTAP_FLAGS */
if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS)
*pos |= IEEE80211_RADIOTAP_F_FCS;
+ if (status->flag & (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC))
+ *pos |= IEEE80211_RADIOTAP_F_BADFCS;
if (status->flag & RX_FLAG_SHORTPRE)
*pos |= IEEE80211_RADIOTAP_F_SHORTPRE;
pos++;
*/
*pos = 0;
} else {
- rthdr->it_present |= (1 << IEEE80211_RADIOTAP_RATE);
+ rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_RATE);
*pos = rate->bitrate / 5;
}
pos++;
*pos = status->antenna;
pos++;
- /* IEEE80211_RADIOTAP_DB_ANTSIGNAL */
- if (local->hw.flags & IEEE80211_HW_SIGNAL_DB) {
- *pos = status->signal;
- rthdr->it_present |=
- cpu_to_le32(1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL);
- pos++;
- }
-
/* IEEE80211_RADIOTAP_DB_ANTNOISE is not used */
/* IEEE80211_RADIOTAP_RX_FLAGS */
/* ensure 2 byte alignment for the 2 byte field as required */
if ((pos - (unsigned char *)rthdr) & 1)
pos++;
- /* FIXME: when radiotap gets a 'bad PLCP' flag use it here */
- if (status->flag & (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC))
- *(__le16 *)pos |= cpu_to_le16(IEEE80211_RADIOTAP_F_RX_BADFCS);
+ if (status->flag & RX_FLAG_FAILED_PLCP_CRC)
+ *(__le16 *)pos |= cpu_to_le16(IEEE80211_RADIOTAP_F_RX_BADPLCP);
pos += 2;
}
return result;
}
+static ieee80211_rx_result debug_noinline
+ieee80211_rx_h_check_more_data(struct ieee80211_rx_data *rx)
+{
+ struct ieee80211_local *local;
+ struct ieee80211_hdr *hdr;
+ struct sk_buff *skb;
+
+ local = rx->local;
+ skb = rx->skb;
+ hdr = (struct ieee80211_hdr *) skb->data;
+
+ if (!local->pspolling)
+ return RX_CONTINUE;
+
+ if (!ieee80211_has_fromds(hdr->frame_control))
+ /* this is not from AP */
+ return RX_CONTINUE;
+
+ if (!ieee80211_is_data(hdr->frame_control))
+ return RX_CONTINUE;
+
+ if (!ieee80211_has_moredata(hdr->frame_control)) {
+ /* AP has no more frames buffered for us */
+ local->pspolling = false;
+ return RX_CONTINUE;
+ }
+
+ /* more data bit is set, let's request a new frame from the AP */
+ ieee80211_send_pspoll(local, rx->sdata);
+
+ return RX_CONTINUE;
+}
+
static void ap_sta_ps_start(struct sta_info *sta)
{
struct ieee80211_sub_if_data *sdata = sta->sdata;
if (rx->sdata->vif.type == NL80211_IFTYPE_ADHOC) {
u8 *bssid = ieee80211_get_bssid(hdr, rx->skb->len,
NL80211_IFTYPE_ADHOC);
- if (compare_ether_addr(bssid, rx->sdata->u.sta.bssid) == 0)
+ if (compare_ether_addr(bssid, rx->sdata->u.ibss.bssid) == 0)
sta->last_rx = jiffies;
} else
if (!is_multicast_ether_addr(hdr->addr1) ||
* Mesh beacons will update last_rx when if they are found to
* match the current local configuration when processed.
*/
- sta->last_rx = jiffies;
+ if (rx->sdata->vif.type == NL80211_IFTYPE_STATION &&
+ ieee80211_is_beacon(hdr->frame_control)) {
+ rx->sdata->u.mgd.last_beacon = jiffies;
+ } else
+ sta->last_rx = jiffies;
}
if (!(rx->flags & IEEE80211_RX_RA_MATCH))
return RX_CONTINUE;
+ if (rx->sdata->vif.type == NL80211_IFTYPE_STATION)
+ ieee80211_sta_rx_notify(rx->sdata, hdr);
+
sta->rx_fragments++;
sta->rx_bytes += rx->skb->len;
sta->last_signal = rx->status->signal;
switch (hdr->frame_control &
cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) {
- case __constant_cpu_to_le16(IEEE80211_FCTL_TODS):
+ case cpu_to_le16(IEEE80211_FCTL_TODS):
if (unlikely(sdata->vif.type != NL80211_IFTYPE_AP &&
sdata->vif.type != NL80211_IFTYPE_AP_VLAN))
return -1;
break;
- case __constant_cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS):
+ case cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS):
if (unlikely(sdata->vif.type != NL80211_IFTYPE_WDS &&
sdata->vif.type != NL80211_IFTYPE_MESH_POINT))
return -1;
}
}
break;
- case __constant_cpu_to_le16(IEEE80211_FCTL_FROMDS):
+ case cpu_to_le16(IEEE80211_FCTL_FROMDS):
if (sdata->vif.type != NL80211_IFTYPE_STATION ||
(is_multicast_ether_addr(dst) &&
!compare_ether_addr(src, dev->dev_addr)))
return -1;
break;
- case __constant_cpu_to_le16(0):
+ case cpu_to_le16(0):
if (sdata->vif.type != NL80211_IFTYPE_ADHOC)
return -1;
break;
* mac80211. That also explains the __skb_push()
* below.
*/
- align = (unsigned long)skb->data & 4;
+ align = (unsigned long)skb->data & 3;
if (align) {
if (WARN_ON(skb_headroom(skb) < 3)) {
dev_kfree_skb(skb);
start_seq_num = le16_to_cpu(bar->start_seq_num) >> 4;
/* reset session timer */
- if (tid_agg_rx->timeout) {
- unsigned long expires =
- jiffies + (tid_agg_rx->timeout / 1000) * HZ;
- mod_timer(&tid_agg_rx->session_timer, expires);
- }
+ if (tid_agg_rx->timeout)
+ mod_timer(&tid_agg_rx->session_timer,
+ TU_TO_EXP_TIME(tid_agg_rx->timeout));
/* manage reordering buffer according to requested */
/* sequence number */
rcu_read_lock();
- ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, NULL,
+ ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, NULL, NULL,
start_seq_num, 1);
rcu_read_unlock();
return RX_DROP_UNUSABLE;
return RX_CONTINUE;
}
-void ieee80211_process_sa_query_req(struct ieee80211_sub_if_data *sdata,
- struct ieee80211_mgmt *mgmt,
- size_t len)
+static void ieee80211_process_sa_query_req(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_mgmt *mgmt,
+ size_t len)
{
struct ieee80211_local *local = sdata->local;
struct sk_buff *skb;
return;
}
- if (compare_ether_addr(mgmt->sa, sdata->u.sta.bssid) != 0 ||
- compare_ether_addr(mgmt->bssid, sdata->u.sta.bssid) != 0) {
+ if (compare_ether_addr(mgmt->sa, sdata->u.mgd.bssid) != 0 ||
+ compare_ether_addr(mgmt->bssid, sdata->u.mgd.bssid) != 0) {
/* Not from the current AP. */
return;
}
- if (sdata->u.sta.state == IEEE80211_STA_MLME_ASSOCIATE) {
+ if (sdata->u.mgd.state == IEEE80211_STA_MLME_ASSOCIATE) {
/* Association in progress; ignore SA Query */
return;
}
memset(resp, 0, 24);
memcpy(resp->da, mgmt->sa, ETH_ALEN);
memcpy(resp->sa, sdata->dev->dev_addr, ETH_ALEN);
- memcpy(resp->bssid, sdata->u.sta.bssid, ETH_ALEN);
+ memcpy(resp->bssid, sdata->u.mgd.bssid, ETH_ALEN);
resp->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
IEEE80211_STYPE_ACTION);
skb_put(skb, 1 + sizeof(resp->u.action.u.sa_query));
{
struct ieee80211_local *local = rx->local;
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev);
- struct ieee80211_if_sta *ifsta = &sdata->u.sta;
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data;
struct ieee80211_bss *bss;
int len = rx->skb->len;
switch (mgmt->u.action.category) {
case WLAN_CATEGORY_BACK:
+ /*
+ * The aggregation code is not prepared to handle
+ * anything but STA/AP due to the BSSID handling;
+ * IBSS could work in the code but isn't supported
+ * by drivers or the standard.
+ */
+ if (sdata->vif.type != NL80211_IFTYPE_STATION &&
+ sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
+ sdata->vif.type != NL80211_IFTYPE_AP)
+ return RX_DROP_MONITOR;
+
switch (mgmt->u.action.u.addba_req.action_code) {
case WLAN_ACTION_ADDBA_REQ:
if (len < (IEEE80211_MIN_ACTION_SIZE +
case WLAN_CATEGORY_SPECTRUM_MGMT:
if (local->hw.conf.channel->band != IEEE80211_BAND_5GHZ)
return RX_DROP_MONITOR;
+
+ if (sdata->vif.type != NL80211_IFTYPE_STATION)
+ return RX_DROP_MONITOR;
+
switch (mgmt->u.action.u.measurement.action_code) {
case WLAN_ACTION_SPCT_MSR_REQ:
if (len < (IEEE80211_MIN_ACTION_SIZE +
sizeof(mgmt->u.action.u.chan_switch)))
return RX_DROP_MONITOR;
- if (memcmp(mgmt->bssid, ifsta->bssid, ETH_ALEN) != 0)
+ if (memcmp(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN))
return RX_DROP_MONITOR;
- bss = ieee80211_rx_bss_get(local, ifsta->bssid,
+ bss = ieee80211_rx_bss_get(local, sdata->u.mgd.bssid,
local->hw.conf.channel->center_freq,
- ifsta->ssid, ifsta->ssid_len);
+ sdata->u.mgd.ssid,
+ sdata->u.mgd.ssid_len);
if (!bss)
return RX_DROP_MONITOR;
if (ieee80211_vif_is_mesh(&sdata->vif))
return ieee80211_mesh_rx_mgmt(sdata, rx->skb, rx->status);
- if (sdata->vif.type != NL80211_IFTYPE_STATION &&
- sdata->vif.type != NL80211_IFTYPE_ADHOC)
- return RX_DROP_MONITOR;
+ if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
+ return ieee80211_ibss_rx_mgmt(sdata, rx->skb, rx->status);
- if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME)
- return RX_DROP_MONITOR;
+ if (sdata->vif.type == NL80211_IFTYPE_STATION)
+ return ieee80211_sta_rx_mgmt(sdata, rx->skb, rx->status);
- ieee80211_sta_rx_mgmt(sdata, rx->skb, rx->status);
- return RX_QUEUED;
+ return RX_DROP_MONITOR;
}
static void ieee80211_rx_michael_mic_report(struct net_device *dev,
CALL_RXH(ieee80211_rx_h_passive_scan)
CALL_RXH(ieee80211_rx_h_check)
CALL_RXH(ieee80211_rx_h_decrypt)
+ CALL_RXH(ieee80211_rx_h_check_more_data)
CALL_RXH(ieee80211_rx_h_sta_process)
CALL_RXH(ieee80211_rx_h_defragment)
CALL_RXH(ieee80211_rx_h_ps_poll)
/* main receive path */
static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
- u8 *bssid, struct ieee80211_rx_data *rx,
+ struct ieee80211_rx_data *rx,
struct ieee80211_hdr *hdr)
{
+ u8 *bssid = ieee80211_get_bssid(hdr, rx->skb->len, sdata->vif.type);
int multicast = is_multicast_ether_addr(hdr->addr1);
switch (sdata->vif.type) {
case NL80211_IFTYPE_STATION:
if (!bssid)
return 0;
- if (!ieee80211_bssid_match(bssid, sdata->u.sta.bssid)) {
+ if (!ieee80211_bssid_match(bssid, sdata->u.mgd.bssid)) {
if (!(rx->flags & IEEE80211_RX_IN_SCAN))
return 0;
rx->flags &= ~IEEE80211_RX_RA_MATCH;
if (ieee80211_is_beacon(hdr->frame_control)) {
return 1;
}
- else if (!ieee80211_bssid_match(bssid, sdata->u.sta.bssid)) {
+ else if (!ieee80211_bssid_match(bssid, sdata->u.ibss.bssid)) {
if (!(rx->flags & IEEE80211_RX_IN_SCAN))
return 0;
rx->flags &= ~IEEE80211_RX_RA_MATCH;
int prepares;
struct ieee80211_sub_if_data *prev = NULL;
struct sk_buff *skb_new;
- u8 *bssid;
hdr = (struct ieee80211_hdr *)skb->data;
memset(&rx, 0, sizeof(rx));
if (sdata->vif.type == NL80211_IFTYPE_MONITOR)
continue;
- bssid = ieee80211_get_bssid(hdr, skb->len, sdata->vif.type);
rx.flags |= IEEE80211_RX_RA_MATCH;
- prepares = prepare_for_handlers(sdata, bssid, &rx, hdr);
+ prepares = prepare_for_handlers(sdata, &rx, hdr);
if (!prepares)
continue;
static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
struct tid_ampdu_rx *tid_agg_rx,
struct sk_buff *skb,
+ struct ieee80211_rx_status *rxstatus,
u16 mpdu_seq_num,
int bar_req)
{
/* put the frame in the reordering buffer */
tid_agg_rx->reorder_buf[index] = skb;
+ memcpy(tid_agg_rx->reorder_buf[index]->cb, rxstatus,
+ sizeof(*rxstatus));
tid_agg_rx->stored_mpdu_num++;
/* release the buffer until next missing frame */
index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn)
}
static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local,
- struct sk_buff *skb)
+ struct sk_buff *skb,
+ struct ieee80211_rx_status *status)
{
struct ieee80211_hw *hw = &local->hw;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
/* new un-ordered ampdu frame - process it */
/* reset session timer */
- if (tid_agg_rx->timeout) {
- unsigned long expires =
- jiffies + (tid_agg_rx->timeout / 1000) * HZ;
- mod_timer(&tid_agg_rx->session_timer, expires);
- }
+ if (tid_agg_rx->timeout)
+ mod_timer(&tid_agg_rx->session_timer,
+ TU_TO_EXP_TIME(tid_agg_rx->timeout));
/* if this mpdu is fragmented - terminate rx aggregation session */
sc = le16_to_cpu(hdr->seq_ctrl);
/* according to mpdu sequence number deal with reordering buffer */
mpdu_seq_num = (sc & IEEE80211_SCTL_SEQ) >> 4;
- ret = ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb,
+ ret = ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb, status,
mpdu_seq_num, 0);
end_reorder:
return ret;
return;
}
- if (!ieee80211_rx_reorder_ampdu(local, skb))
+ if (!ieee80211_rx_reorder_ampdu(local, skb, status))
__ieee80211_rx_handle_packet(hw, skb, status, rate);
rcu_read_unlock();