else
rx->flags &= ~IEEE80211_RX_AMSDU;
} else {
- if (unlikely(ieee80211_is_mgmt(hdr->frame_control))) {
- /* Separate TID for management frames */
- tid = NUM_RX_DATA_QUEUES - 1;
- } else {
- /* no qos control present */
- tid = 0; /* 802.1d - Best Effort */
- }
+ /*
+ * IEEE 802.11-2007, 7.1.3.4.1 ("Sequence Number field"):
+ *
+ * Sequence numbers for management frames, QoS data
+ * frames with a broadcast/multicast address in the
+ * Address 1 field, and all non-QoS data frames sent
+ * by QoS STAs are assigned using an additional single
+ * modulo-4096 counter, [...]
+ *
+ * We also use that counter for non-QoS STAs.
+ */
+ tid = NUM_RX_DATA_QUEUES - 1;
}
rx->queue = tid;
sdata = sta->sdata;
- if (sdata->bss)
- atomic_inc(&sdata->bss->num_sta_ps);
+ atomic_inc(&sdata->bss->num_sta_ps);
set_and_clear_sta_flags(sta, WLAN_STA_PS, WLAN_STA_PSPOLL);
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
printk(KERN_DEBUG "%s: STA %s aid %d enters power save mode\n",
sdata = sta->sdata;
- if (sdata->bss)
- atomic_dec(&sdata->bss->num_sta_ps);
+ atomic_dec(&sdata->bss->num_sta_ps);
clear_sta_flags(sta, WLAN_STA_PS | WLAN_STA_PSPOLL);
sta->last_qual = rx->status->qual;
sta->last_noise = rx->status->noise;
- if (!ieee80211_has_morefrags(hdr->frame_control)) {
+ if (!ieee80211_has_morefrags(hdr->frame_control) &&
+ (rx->sdata->vif.type == IEEE80211_IF_TYPE_AP ||
+ rx->sdata->vif.type == IEEE80211_IF_TYPE_VLAN)) {
/* Change STA power saving mode only in the end of a frame
* exchange sequence */
if (test_sta_flags(sta, WLAN_STA_PS) &&
hdrlen = ieee80211_get_hdrlen(fc);
- if (ieee80211_vif_is_mesh(&sdata->vif)) {
- int meshhdrlen = ieee80211_get_mesh_hdrlen(
+ if (ieee80211_vif_is_mesh(&sdata->vif))
+ hdrlen += ieee80211_get_mesh_hdrlen(
(struct ieee80211s_hdr *) (skb->data + hdrlen));
- /* Copy on cb:
- * - mesh header: to be used for mesh forwarding
- * decision. It will also be used as mesh header template at
- * tx.c:ieee80211_subif_start_xmit() if interface
- * type is mesh and skb->pkt_type == PACKET_OTHERHOST
- * - ta: to be used if a RERR needs to be sent.
- */
- memcpy(skb->cb, skb->data + hdrlen, meshhdrlen);
- memcpy(MESH_PREQ(skb), hdr->addr2, ETH_ALEN);
- hdrlen += meshhdrlen;
- }
/* convert IEEE 802.11 header + possible LLC headers into Ethernet
* header
}
}
- /* Mesh forwarding */
- if (ieee80211_vif_is_mesh(&sdata->vif)) {
- u8 *mesh_ttl = &((struct ieee80211s_hdr *)skb->cb)->ttl;
- (*mesh_ttl)--;
-
- if (is_multicast_ether_addr(skb->data)) {
- if (*mesh_ttl > 0) {
- xmit_skb = skb_copy(skb, GFP_ATOMIC);
- if (xmit_skb)
- xmit_skb->pkt_type = PACKET_OTHERHOST;
- else if (net_ratelimit())
- printk(KERN_DEBUG "%s: failed to clone "
- "multicast frame\n", dev->name);
- } else
- IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.sta,
- dropped_frames_ttl);
- } else if (skb->pkt_type != PACKET_OTHERHOST &&
- compare_ether_addr(dev->dev_addr, skb->data) != 0) {
- if (*mesh_ttl == 0) {
- IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.sta,
- dropped_frames_ttl);
- dev_kfree_skb(skb);
- skb = NULL;
- } else {
- xmit_skb = skb;
- xmit_skb->pkt_type = PACKET_OTHERHOST;
- if (!(dev->flags & IFF_PROMISC))
- skb = NULL;
- }
- }
- }
-
if (skb) {
/* deliver to local stack */
skb->protocol = eth_type_trans(skb, dev);
return RX_QUEUED;
}
+static ieee80211_rx_result debug_noinline
+ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
+{
+ struct ieee80211_hdr *hdr;
+ struct ieee80211s_hdr *mesh_hdr;
+ unsigned int hdrlen;
+ struct sk_buff *skb = rx->skb, *fwd_skb;
+
+ hdr = (struct ieee80211_hdr *) skb->data;
+ hdrlen = ieee80211_hdrlen(hdr->frame_control);
+ mesh_hdr = (struct ieee80211s_hdr *) (skb->data + hdrlen);
+
+ if (!ieee80211_is_data(hdr->frame_control))
+ return RX_CONTINUE;
+
+ if (!mesh_hdr->ttl)
+ /* illegal frame */
+ return RX_DROP_MONITOR;
+
+ if (compare_ether_addr(rx->dev->dev_addr, hdr->addr3) == 0)
+ return RX_CONTINUE;
+
+ mesh_hdr->ttl--;
+
+ if (rx->flags & IEEE80211_RX_RA_MATCH) {
+ if (!mesh_hdr->ttl)
+ IEEE80211_IFSTA_MESH_CTR_INC(&rx->sdata->u.sta,
+ dropped_frames_ttl);
+ else {
+ struct ieee80211_hdr *fwd_hdr;
+ fwd_skb = skb_copy(skb, GFP_ATOMIC);
+
+ if (!fwd_skb && net_ratelimit())
+ printk(KERN_DEBUG "%s: failed to clone mesh frame\n",
+ rx->dev->name);
+
+ fwd_hdr = (struct ieee80211_hdr *) fwd_skb->data;
+ /*
+ * Save TA to addr1 to send TA a path error if a
+ * suitable next hop is not found
+ */
+ memcpy(fwd_hdr->addr1, fwd_hdr->addr2, ETH_ALEN);
+ memcpy(fwd_hdr->addr2, rx->dev->dev_addr, ETH_ALEN);
+ fwd_skb->dev = rx->local->mdev;
+ fwd_skb->iif = rx->dev->ifindex;
+ dev_queue_xmit(fwd_skb);
+ }
+ }
+
+ if (is_multicast_ether_addr(hdr->addr3) ||
+ rx->dev->flags & IFF_PROMISC)
+ return RX_CONTINUE;
+ else
+ return RX_DROP_MONITOR;
+}
+
+
static ieee80211_rx_result debug_noinline
ieee80211_rx_h_data(struct ieee80211_rx_data *rx)
{
rx->sdata = sdata;
rx->dev = sdata->dev;
-#define CALL_RXH(rxh) \
- res = rxh(rx); \
- if (res != RX_CONTINUE) \
- goto rxh_done;
+#define CALL_RXH(rxh) \
+ do { \
+ res = rxh(rx); \
+ if (res != RX_CONTINUE) \
+ goto rxh_done; \
+ } while (0);
CALL_RXH(ieee80211_rx_h_passive_scan)
CALL_RXH(ieee80211_rx_h_check)
/* must be after MMIC verify so header is counted in MPDU mic */
CALL_RXH(ieee80211_rx_h_remove_qos_control)
CALL_RXH(ieee80211_rx_h_amsdu)
+ if (ieee80211_vif_is_mesh(&sdata->vif))
+ CALL_RXH(ieee80211_rx_h_mesh_fwding);
CALL_RXH(ieee80211_rx_h_data)
CALL_RXH(ieee80211_rx_h_ctrl)
CALL_RXH(ieee80211_rx_h_mgmt)
return 0;
rx->flags &= ~IEEE80211_RX_RA_MATCH;
}
- if (sdata->dev == sdata->local->mdev &&
- !(rx->flags & IEEE80211_RX_IN_SCAN))
- /* do not receive anything via
- * master device when not scanning */
- return 0;
break;
case IEEE80211_IF_TYPE_WDS:
if (bssid || !ieee80211_is_data(hdr->frame_control))
tid_agg_rx = sta->ampdu_mlme.tid_rx[tid];
- /* null data frames are excluded */
- if (unlikely(ieee80211_is_nullfunc(hdr->frame_control)))
+ /* qos null data frames are excluded */
+ if (unlikely(hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_NULLFUNC)))
goto end_reorder;
/* new un-ordered ampdu frame - process it */