aboutsummaryrefslogtreecommitdiff
path: root/net/mac80211/rx.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/rx.c')
-rw-r--r--net/mac80211/rx.c309
1 files changed, 210 insertions, 99 deletions
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 48574f6c0e7..644d2774469 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -20,6 +20,7 @@
#include "ieee80211_i.h"
#include "ieee80211_led.h"
+#include "mesh.h"
#include "wep.h"
#include "wpa.h"
#include "tkip.h"
@@ -250,7 +251,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
}
-static void ieee80211_parse_qos(struct ieee80211_txrx_data *rx)
+static void ieee80211_parse_qos(struct ieee80211_rx_data *rx)
{
u8 *data = rx->skb->data;
int tid;
@@ -261,9 +262,9 @@ static void ieee80211_parse_qos(struct ieee80211_txrx_data *rx)
/* frame has qos control */
tid = qc[0] & QOS_CONTROL_TID_MASK;
if (qc[0] & IEEE80211_QOS_CONTROL_A_MSDU_PRESENT)
- rx->flags |= IEEE80211_TXRXD_RX_AMSDU;
+ rx->flags |= IEEE80211_RX_AMSDU;
else
- rx->flags &= ~IEEE80211_TXRXD_RX_AMSDU;
+ rx->flags &= ~IEEE80211_RX_AMSDU;
} else {
if (unlikely((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT)) {
/* Separate TID for management frames */
@@ -279,13 +280,13 @@ static void ieee80211_parse_qos(struct ieee80211_txrx_data *rx)
if (rx->sta)
I802_DEBUG_INC(rx->sta->wme_rx_queue[tid]);
- rx->u.rx.queue = tid;
+ rx->queue = tid;
/* Set skb->priority to 1d tag if highest order bit of TID is not set.
* For now, set skb->priority to 0 for other cases. */
rx->skb->priority = (tid > 7) ? 0 : tid;
}
-static void ieee80211_verify_ip_alignment(struct ieee80211_txrx_data *rx)
+static void ieee80211_verify_ip_alignment(struct ieee80211_rx_data *rx)
{
#ifdef CONFIG_MAC80211_DEBUG_PACKET_ALIGNMENT
int hdrlen;
@@ -313,7 +314,7 @@ static void ieee80211_verify_ip_alignment(struct ieee80211_txrx_data *rx)
* to move the 802.11 header further back in that case.
*/
hdrlen = ieee80211_get_hdrlen(rx->fc);
- if (rx->flags & IEEE80211_TXRXD_RX_AMSDU)
+ if (rx->flags & IEEE80211_RX_AMSDU)
hdrlen += ETH_HLEN;
WARN_ON_ONCE(((unsigned long)(rx->skb->data + hdrlen)) & 3);
#endif
@@ -356,32 +357,32 @@ static u32 ieee80211_rx_load_stats(struct ieee80211_local *local,
/* rx handlers */
static ieee80211_rx_result
-ieee80211_rx_h_if_stats(struct ieee80211_txrx_data *rx)
+ieee80211_rx_h_if_stats(struct ieee80211_rx_data *rx)
{
if (rx->sta)
- rx->sta->channel_use_raw += rx->u.rx.load;
- rx->sdata->channel_use_raw += rx->u.rx.load;
+ rx->sta->channel_use_raw += rx->load;
+ rx->sdata->channel_use_raw += rx->load;
return RX_CONTINUE;
}
static ieee80211_rx_result
-ieee80211_rx_h_passive_scan(struct ieee80211_txrx_data *rx)
+ieee80211_rx_h_passive_scan(struct ieee80211_rx_data *rx)
{
struct ieee80211_local *local = rx->local;
struct sk_buff *skb = rx->skb;
if (unlikely(local->sta_hw_scanning))
- return ieee80211_sta_rx_scan(rx->dev, skb, rx->u.rx.status);
+ return ieee80211_sta_rx_scan(rx->dev, skb, rx->status);
if (unlikely(local->sta_sw_scanning)) {
/* drop all the other packets during a software scan anyway */
- if (ieee80211_sta_rx_scan(rx->dev, skb, rx->u.rx.status)
+ if (ieee80211_sta_rx_scan(rx->dev, skb, rx->status)
!= RX_QUEUED)
dev_kfree_skb(skb);
return RX_QUEUED;
}
- if (unlikely(rx->flags & IEEE80211_TXRXD_RXIN_SCAN)) {
+ if (unlikely(rx->flags & IEEE80211_RX_IN_SCAN)) {
/* scanning finished during invoking of handlers */
I802_DEBUG_INC(local->rx_handlers_drop_passive_scan);
return RX_DROP_UNUSABLE;
@@ -391,23 +392,75 @@ ieee80211_rx_h_passive_scan(struct ieee80211_txrx_data *rx)
}
static ieee80211_rx_result
-ieee80211_rx_h_check(struct ieee80211_txrx_data *rx)
+ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
+{
+ int hdrlen = ieee80211_get_hdrlen(rx->fc);
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data;
+
+#define msh_h_get(h, l) ((struct ieee80211s_hdr *) ((u8 *)h + l))
+
+ if ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) {
+ if (!((rx->fc & IEEE80211_FCTL_FROMDS) &&
+ (rx->fc & IEEE80211_FCTL_TODS)))
+ return RX_DROP_MONITOR;
+ if (memcmp(hdr->addr4, rx->dev->dev_addr, ETH_ALEN) == 0)
+ return RX_DROP_MONITOR;
+ }
+
+ /* If there is not an established peer link and this is not a peer link
+ * establisment frame, beacon or probe, drop the frame.
+ */
+
+ if (!rx->sta || sta_plink_state(rx->sta) != PLINK_ESTAB) {
+ struct ieee80211_mgmt *mgmt;
+
+ if ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT)
+ return RX_DROP_MONITOR;
+
+ switch (rx->fc & IEEE80211_FCTL_STYPE) {
+ case IEEE80211_STYPE_ACTION:
+ mgmt = (struct ieee80211_mgmt *)hdr;
+ if (mgmt->u.action.category != PLINK_CATEGORY)
+ return RX_DROP_MONITOR;
+ /* fall through on else */
+ case IEEE80211_STYPE_PROBE_REQ:
+ case IEEE80211_STYPE_PROBE_RESP:
+ case IEEE80211_STYPE_BEACON:
+ return RX_CONTINUE;
+ break;
+ default:
+ return RX_DROP_MONITOR;
+ }
+
+ } else if ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA &&
+ is_broadcast_ether_addr(hdr->addr1) &&
+ mesh_rmc_check(hdr->addr4, msh_h_get(hdr, hdrlen), rx->dev))
+ return RX_DROP_MONITOR;
+#undef msh_h_get
+
+ return RX_CONTINUE;
+}
+
+
+static ieee80211_rx_result
+ieee80211_rx_h_check(struct ieee80211_rx_data *rx)
{
struct ieee80211_hdr *hdr;
+
hdr = (struct ieee80211_hdr *) rx->skb->data;
/* Drop duplicate 802.11 retransmissions (IEEE 802.11 Chap. 9.2.9) */
if (rx->sta && !is_multicast_ether_addr(hdr->addr1)) {
if (unlikely(rx->fc & IEEE80211_FCTL_RETRY &&
- rx->sta->last_seq_ctrl[rx->u.rx.queue] ==
+ rx->sta->last_seq_ctrl[rx->queue] ==
hdr->seq_ctrl)) {
- if (rx->flags & IEEE80211_TXRXD_RXRA_MATCH) {
+ if (rx->flags & IEEE80211_RX_RA_MATCH) {
rx->local->dot11FrameDuplicateCount++;
rx->sta->num_duplicates++;
}
return RX_DROP_MONITOR;
} else
- rx->sta->last_seq_ctrl[rx->u.rx.queue] = hdr->seq_ctrl;
+ rx->sta->last_seq_ctrl[rx->queue] = hdr->seq_ctrl;
}
if (unlikely(rx->skb->len < 16)) {
@@ -423,6 +476,10 @@ ieee80211_rx_h_check(struct ieee80211_txrx_data *rx)
* deauth/disassoc frames when needed. In addition, hostapd is
* responsible for filtering on both auth and assoc states.
*/
+
+ if (ieee80211_vif_is_mesh(&rx->sdata->vif))
+ return ieee80211_rx_mesh_check(rx);
+
if (unlikely(((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA ||
((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL &&
(rx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)) &&
@@ -431,7 +488,7 @@ ieee80211_rx_h_check(struct ieee80211_txrx_data *rx)
if ((!(rx->fc & IEEE80211_FCTL_FROMDS) &&
!(rx->fc & IEEE80211_FCTL_TODS) &&
(rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)
- || !(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) {
+ || !(rx->flags & IEEE80211_RX_RA_MATCH)) {
/* Drop IBSS frames and frames for other hosts
* silently. */
return RX_DROP_MONITOR;
@@ -445,7 +502,7 @@ ieee80211_rx_h_check(struct ieee80211_txrx_data *rx)
static ieee80211_rx_result
-ieee80211_rx_h_decrypt(struct ieee80211_txrx_data *rx)
+ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data;
int keyidx;
@@ -486,7 +543,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_txrx_data *rx)
* No point in finding a key and decrypting if the frame is neither
* addressed to us nor a multicast frame.
*/
- if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH))
+ if (!(rx->flags & IEEE80211_RX_RA_MATCH))
return RX_CONTINUE;
if (rx->sta)
@@ -504,8 +561,8 @@ ieee80211_rx_h_decrypt(struct ieee80211_txrx_data *rx)
* we somehow allow the driver to tell us which key
* the hardware used if this flag is set?
*/
- if ((rx->u.rx.status->flag & RX_FLAG_DECRYPTED) &&
- (rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED))
+ if ((rx->status->flag & RX_FLAG_DECRYPTED) &&
+ (rx->status->flag & RX_FLAG_IV_STRIPPED))
return RX_CONTINUE;
hdrlen = ieee80211_get_hdrlen(rx->fc);
@@ -546,8 +603,8 @@ ieee80211_rx_h_decrypt(struct ieee80211_txrx_data *rx)
/* Check for weak IVs if possible */
if (rx->sta && rx->key->conf.alg == ALG_WEP &&
((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) &&
- (!(rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED) ||
- !(rx->u.rx.status->flag & RX_FLAG_DECRYPTED)) &&
+ (!(rx->status->flag & RX_FLAG_IV_STRIPPED) ||
+ !(rx->status->flag & RX_FLAG_DECRYPTED)) &&
ieee80211_wep_is_weak_iv(rx->skb, rx->key))
rx->sta->wep_weak_iv_count++;
@@ -564,7 +621,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_txrx_data *rx)
}
/* either the frame has been decrypted or will be dropped */
- rx->u.rx.status->flag |= RX_FLAG_DECRYPTED;
+ rx->status->flag |= RX_FLAG_DECRYPTED;
return result;
}
@@ -574,7 +631,7 @@ static void ap_sta_ps_start(struct net_device *dev, struct sta_info *sta)
struct ieee80211_sub_if_data *sdata;
DECLARE_MAC_BUF(mac);
- sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
+ sdata = sta->sdata;
if (sdata->bss)
atomic_inc(&sdata->bss->num_sta_ps);
@@ -595,7 +652,7 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta)
struct ieee80211_tx_packet_data *pkt_data;
DECLARE_MAC_BUF(mac);
- sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
+ sdata = sta->sdata;
if (sdata->bss)
atomic_dec(&sdata->bss->num_sta_ps);
@@ -634,7 +691,7 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta)
}
static ieee80211_rx_result
-ieee80211_rx_h_sta_process(struct ieee80211_txrx_data *rx)
+ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
{
struct sta_info *sta = rx->sta;
struct net_device *dev = rx->dev;
@@ -657,24 +714,26 @@ ieee80211_rx_h_sta_process(struct ieee80211_txrx_data *rx)
/* Update last_rx only for unicast frames in order to prevent
* the Probe Request frames (the only broadcast frames from a
* STA in infrastructure mode) from keeping a connection alive.
+ * 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->flags & IEEE80211_TXRXD_RXRA_MATCH))
+ if (!(rx->flags & IEEE80211_RX_RA_MATCH))
return RX_CONTINUE;
sta->rx_fragments++;
sta->rx_bytes += rx->skb->len;
- sta->last_rssi = rx->u.rx.status->ssi;
- sta->last_signal = rx->u.rx.status->signal;
- sta->last_noise = rx->u.rx.status->noise;
+ sta->last_rssi = rx->status->ssi;
+ sta->last_signal = rx->status->signal;
+ sta->last_noise = rx->status->noise;
if (!(rx->fc & IEEE80211_FCTL_MOREFRAGS)) {
/* Change STA power saving mode only in the end of a frame
* exchange sequence */
if ((sta->flags & WLAN_STA_PS) && !(rx->fc & IEEE80211_FCTL_PM))
- rx->u.rx.sent_ps_buffered += ap_sta_ps_end(dev, sta);
+ rx->sent_ps_buffered += ap_sta_ps_end(dev, sta);
else if (!(sta->flags & WLAN_STA_PS) &&
(rx->fc & IEEE80211_FCTL_PM))
ap_sta_ps_start(dev, sta);
@@ -779,7 +838,7 @@ ieee80211_reassemble_find(struct ieee80211_sub_if_data *sdata,
}
static ieee80211_rx_result
-ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx)
+ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
{
struct ieee80211_hdr *hdr;
u16 sc;
@@ -805,14 +864,14 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx)
if (frag == 0) {
/* This is the first fragment of a new frame. */
entry = ieee80211_reassemble_add(rx->sdata, frag, seq,
- rx->u.rx.queue, &(rx->skb));
+ rx->queue, &(rx->skb));
if (rx->key && rx->key->conf.alg == ALG_CCMP &&
(rx->fc & IEEE80211_FCTL_PROTECTED)) {
/* Store CCMP PN so that we can verify that the next
* fragment has a sequential PN value. */
entry->ccmp = 1;
memcpy(entry->last_pn,
- rx->key->u.ccmp.rx_pn[rx->u.rx.queue],
+ rx->key->u.ccmp.rx_pn[rx->queue],
CCMP_PN_LEN);
}
return RX_QUEUED;
@@ -822,7 +881,7 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx)
* fragment cache. Add this fragment to the end of the pending entry.
*/
entry = ieee80211_reassemble_find(rx->sdata, rx->fc, frag, seq,
- rx->u.rx.queue, hdr);
+ rx->queue, hdr);
if (!entry) {
I802_DEBUG_INC(rx->local->rx_handlers_drop_defrag);
return RX_DROP_MONITOR;
@@ -841,7 +900,7 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx)
if (pn[i])
break;
}
- rpn = rx->key->u.ccmp.rx_pn[rx->u.rx.queue];
+ rpn = rx->key->u.ccmp.rx_pn[rx->queue];
if (memcmp(pn, rpn, CCMP_PN_LEN) != 0) {
if (net_ratelimit())
printk(KERN_DEBUG "%s: defrag: CCMP PN not "
@@ -882,7 +941,7 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx)
}
/* Complete frame has been reassembled - process it now */
- rx->flags |= IEEE80211_TXRXD_FRAGMENTED;
+ rx->flags |= IEEE80211_RX_FRAGMENTED;
out:
if (rx->sta)
@@ -895,7 +954,7 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx)
}
static ieee80211_rx_result
-ieee80211_rx_h_ps_poll(struct ieee80211_txrx_data *rx)
+ieee80211_rx_h_ps_poll(struct ieee80211_rx_data *rx)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev);
struct sk_buff *skb;
@@ -905,7 +964,7 @@ ieee80211_rx_h_ps_poll(struct ieee80211_txrx_data *rx)
if (likely(!rx->sta ||
(rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_CTL ||
(rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_PSPOLL ||
- !(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)))
+ !(rx->flags & IEEE80211_RX_RA_MATCH)))
return RX_CONTINUE;
if ((sdata->vif.type != IEEE80211_IF_TYPE_AP) &&
@@ -949,7 +1008,7 @@ ieee80211_rx_h_ps_poll(struct ieee80211_txrx_data *rx)
if (no_pending_pkts)
sta_info_clear_tim_bit(rx->sta);
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
- } else if (!rx->u.rx.sent_ps_buffered) {
+ } else if (!rx->sent_ps_buffered) {
/*
* FIXME: This can be the result of a race condition between
* us expiring a frame and the station polling for it.
@@ -970,7 +1029,7 @@ ieee80211_rx_h_ps_poll(struct ieee80211_txrx_data *rx)
}
static ieee80211_rx_result
-ieee80211_rx_h_remove_qos_control(struct ieee80211_txrx_data *rx)
+ieee80211_rx_h_remove_qos_control(struct ieee80211_rx_data *rx)
{
u16 fc = rx->fc;
u8 *data = rx->skb->data;
@@ -990,7 +1049,7 @@ ieee80211_rx_h_remove_qos_control(struct ieee80211_txrx_data *rx)
}
static int
-ieee80211_802_1x_port_control(struct ieee80211_txrx_data *rx)
+ieee80211_802_1x_port_control(struct ieee80211_rx_data *rx)
{
if (unlikely(!rx->sta || !(rx->sta->flags & WLAN_STA_AUTHORIZED))) {
#ifdef CONFIG_MAC80211_DEBUG
@@ -1005,13 +1064,13 @@ ieee80211_802_1x_port_control(struct ieee80211_txrx_data *rx)
}
static int
-ieee80211_drop_unencrypted(struct ieee80211_txrx_data *rx)
+ieee80211_drop_unencrypted(struct ieee80211_rx_data *rx)
{
/*
* Pass through unencrypted frames if the hardware has
* decrypted them already.
*/
- if (rx->u.rx.status->flag & RX_FLAG_DECRYPTED)
+ if (rx->status->flag & RX_FLAG_DECRYPTED)
return 0;
/* Drop unencrypted frames if key is set. */
@@ -1028,7 +1087,7 @@ ieee80211_drop_unencrypted(struct ieee80211_txrx_data *rx)
}
static int
-ieee80211_data_to_8023(struct ieee80211_txrx_data *rx)
+ieee80211_data_to_8023(struct ieee80211_rx_data *rx)
{
struct net_device *dev = rx->dev;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data;
@@ -1050,6 +1109,21 @@ ieee80211_data_to_8023(struct ieee80211_txrx_data *rx)
hdrlen = ieee80211_get_hdrlen(fc);
+ if (ieee80211_vif_is_mesh(&sdata->vif)) {
+ int meshhdrlen = 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
* IEEE 802.11 address fields:
@@ -1083,9 +1157,10 @@ ieee80211_data_to_8023(struct ieee80211_txrx_data *rx)
memcpy(dst, hdr->addr3, ETH_ALEN);
memcpy(src, hdr->addr4, ETH_ALEN);
- if (unlikely(sdata->vif.type != IEEE80211_IF_TYPE_WDS)) {
- if (net_ratelimit())
- printk(KERN_DEBUG "%s: dropped FromDS&ToDS "
+ if (unlikely(sdata->vif.type != IEEE80211_IF_TYPE_WDS &&
+ sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT)) {
+ if (net_ratelimit())
+ printk(KERN_DEBUG "%s: dropped FromDS&ToDS "
"frame (RA=%s TA=%s DA=%s SA=%s)\n",
rx->dev->name,
print_mac(mac, hdr->addr1),
@@ -1160,7 +1235,7 @@ ieee80211_data_to_8023(struct ieee80211_txrx_data *rx)
/*
* requires that rx->skb is a frame with ethernet header
*/
-static bool ieee80211_frame_allowed(struct ieee80211_txrx_data *rx)
+static bool ieee80211_frame_allowed(struct ieee80211_rx_data *rx)
{
static const u8 pae_group_addr[ETH_ALEN]
= { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x03 };
@@ -1186,7 +1261,7 @@ static bool ieee80211_frame_allowed(struct ieee80211_txrx_data *rx)
* requires that rx->skb is a frame with ethernet header
*/
static void
-ieee80211_deliver_skb(struct ieee80211_txrx_data *rx)
+ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
{
struct net_device *dev = rx->dev;
struct ieee80211_local *local = rx->local;
@@ -1200,7 +1275,7 @@ ieee80211_deliver_skb(struct ieee80211_txrx_data *rx)
if (local->bridge_packets && (sdata->vif.type == IEEE80211_IF_TYPE_AP ||
sdata->vif.type == IEEE80211_IF_TYPE_VLAN) &&
- (rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) {
+ (rx->flags & IEEE80211_RX_RA_MATCH)) {
if (is_multicast_ether_addr(ehdr->h_dest)) {
/*
* send multicast frames both to higher layers in
@@ -1212,7 +1287,7 @@ ieee80211_deliver_skb(struct ieee80211_txrx_data *rx)
"multicast frame\n", dev->name);
} else {
dsta = sta_info_get(local, skb->data);
- if (dsta && dsta->dev == dev) {
+ if (dsta && dsta->sdata->dev == dev) {
/*
* The destination station is associated to
* this AP (in this VLAN), so send the frame
@@ -1222,8 +1297,38 @@ ieee80211_deliver_skb(struct ieee80211_txrx_data *rx)
xmit_skb = skb;
skb = NULL;
}
- if (dsta)
- sta_info_put(dsta);
+ }
+ }
+
+ /* 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 && net_ratelimit())
+ printk(KERN_DEBUG "%s: failed to clone "
+ "multicast frame\n", dev->name);
+ else
+ xmit_skb->pkt_type = PACKET_OTHERHOST;
+ } 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;
+ }
}
}
@@ -1244,7 +1349,7 @@ ieee80211_deliver_skb(struct ieee80211_txrx_data *rx)
}
static ieee80211_rx_result
-ieee80211_rx_h_amsdu(struct ieee80211_txrx_data *rx)
+ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx)
{
struct net_device *dev = rx->dev;
struct ieee80211_local *local = rx->local;
@@ -1264,7 +1369,7 @@ ieee80211_rx_h_amsdu(struct ieee80211_txrx_data *rx)
if (unlikely(!WLAN_FC_DATA_PRESENT(fc)))
return RX_DROP_MONITOR;
- if (!(rx->flags & IEEE80211_TXRXD_RX_AMSDU))
+ if (!(rx->flags & IEEE80211_RX_AMSDU))
return RX_CONTINUE;
err = ieee80211_data_to_8023(rx);
@@ -1361,7 +1466,7 @@ ieee80211_rx_h_amsdu(struct ieee80211_txrx_data *rx)
}
static ieee80211_rx_result
-ieee80211_rx_h_data(struct ieee80211_txrx_data *rx)
+ieee80211_rx_h_data(struct ieee80211_rx_data *rx)
{
struct net_device *dev = rx->dev;
u16 fc;
@@ -1392,7 +1497,7 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx)
}
static ieee80211_rx_result
-ieee80211_rx_h_ctrl(struct ieee80211_txrx_data *rx)
+ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx)
{
struct ieee80211_local *local = rx->local;
struct ieee80211_hw *hw = &local->hw;
@@ -1435,18 +1540,19 @@ ieee80211_rx_h_ctrl(struct ieee80211_txrx_data *rx)
}
static ieee80211_rx_result
-ieee80211_rx_h_mgmt(struct ieee80211_txrx_data *rx)
+ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx)
{
struct ieee80211_sub_if_data *sdata;
- if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH))
+ if (!(rx->flags & IEEE80211_RX_RA_MATCH))
return RX_DROP_MONITOR;
sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev);
if ((sdata->vif.type == IEEE80211_IF_TYPE_STA ||
- sdata->vif.type == IEEE80211_IF_TYPE_IBSS) &&
+ sdata->vif.type == IEEE80211_IF_TYPE_IBSS ||
+ sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) &&
!(sdata->flags & IEEE80211_SDATA_USERSPACE_MLME))
- ieee80211_sta_rx_mgmt(rx->dev, rx->skb, rx->u.rx.status);
+ ieee80211_sta_rx_mgmt(rx->dev, rx->skb, rx->status);
else
return RX_DROP_MONITOR;
@@ -1455,7 +1561,7 @@ ieee80211_rx_h_mgmt(struct ieee80211_txrx_data *rx)
static void ieee80211_rx_michael_mic_report(struct net_device *dev,
struct ieee80211_hdr *hdr,
- struct ieee80211_txrx_data *rx)
+ struct ieee80211_rx_data *rx)
{
int keyidx, hdrlen;
DECLARE_MAC_BUF(mac);
@@ -1525,7 +1631,8 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev,
rx->skb = NULL;
}
-static void ieee80211_rx_cooked_monitor(struct ieee80211_txrx_data *rx)
+/* TODO: use IEEE80211_RX_FRAGMENTED */
+static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx)
{
struct ieee80211_sub_if_data *sdata;
struct ieee80211_local *local = rx->local;
@@ -1538,9 +1645,9 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_txrx_data *rx)
} __attribute__ ((packed)) *rthdr;
struct sk_buff *skb = rx->skb, *skb2;
struct net_device *prev_dev = NULL;
- struct ieee80211_rx_status *status = rx->u.rx.status;
+ struct ieee80211_rx_status *status = rx->status;
- if (rx->flags & IEEE80211_TXRXD_RX_CMNTR_REPORTED)
+ if (rx->flags & IEEE80211_RX_CMNTR_REPORTED)
goto out_free_skb;
if (skb_headroom(skb) < sizeof(*rthdr) &&
@@ -1555,7 +1662,7 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_txrx_data *rx)
(1 << IEEE80211_RADIOTAP_RATE) |
(1 << IEEE80211_RADIOTAP_CHANNEL));
- rthdr->rate = rx->u.rx.rate->bitrate / 5;
+ rthdr->rate = rx->rate->bitrate / 5;
rthdr->chan_freq = cpu_to_le16(status->freq);
if (status->band == IEEE80211_BAND_5GHZ)
@@ -1598,14 +1705,14 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_txrx_data *rx)
} else
goto out_free_skb;
- rx->flags |= IEEE80211_TXRXD_RX_CMNTR_REPORTED;
+ rx->flags |= IEEE80211_RX_CMNTR_REPORTED;
return;
out_free_skb:
dev_kfree_skb(skb);
}
-typedef ieee80211_rx_result (*ieee80211_rx_handler)(struct ieee80211_txrx_data *);
+typedef ieee80211_rx_result (*ieee80211_rx_handler)(struct ieee80211_rx_data *);
static ieee80211_rx_handler ieee80211_rx_handlers[] =
{
ieee80211_rx_h_if_stats,
@@ -1629,7 +1736,7 @@ static ieee80211_rx_handler ieee80211_rx_handlers[] =
};
static void ieee80211_invoke_rx_handlers(struct ieee80211_sub_if_data *sdata,
- struct ieee80211_txrx_data *rx,
+ struct ieee80211_rx_data *rx,
struct sk_buff *skb)
{
ieee80211_rx_handler *handler;
@@ -1672,7 +1779,7 @@ static void ieee80211_invoke_rx_handlers(struct ieee80211_sub_if_data *sdata,
/* main receive path */
static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
- u8 *bssid, struct ieee80211_txrx_data *rx,
+ u8 *bssid, struct ieee80211_rx_data *rx,
struct ieee80211_hdr *hdr)
{
int multicast = is_multicast_ether_addr(hdr->addr1);
@@ -1682,15 +1789,15 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
if (!bssid)
return 0;
if (!ieee80211_bssid_match(bssid, sdata->u.sta.bssid)) {
- if (!(rx->flags & IEEE80211_TXRXD_RXIN_SCAN))
+ if (!(rx->flags & IEEE80211_RX_IN_SCAN))
return 0;
- rx->flags &= ~IEEE80211_TXRXD_RXRA_MATCH;
+ rx->flags &= ~IEEE80211_RX_RA_MATCH;
} else if (!multicast &&
compare_ether_addr(sdata->dev->dev_addr,
hdr->addr1) != 0) {
if (!(sdata->dev->flags & IFF_PROMISC))
return 0;
- rx->flags &= ~IEEE80211_TXRXD_RXRA_MATCH;
+ rx->flags &= ~IEEE80211_RX_RA_MATCH;
}
break;
case IEEE80211_IF_TYPE_IBSS:
@@ -1700,19 +1807,29 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
(rx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON)
return 1;
else if (!ieee80211_bssid_match(bssid, sdata->u.sta.bssid)) {
- if (!(rx->flags & IEEE80211_TXRXD_RXIN_SCAN))
+ if (!(rx->flags & IEEE80211_RX_IN_SCAN))
return 0;
- rx->flags &= ~IEEE80211_TXRXD_RXRA_MATCH;
+ rx->flags &= ~IEEE80211_RX_RA_MATCH;
} else if (!multicast &&
compare_ether_addr(sdata->dev->dev_addr,
hdr->addr1) != 0) {
if (!(sdata->dev->flags & IFF_PROMISC))
return 0;
- rx->flags &= ~IEEE80211_TXRXD_RXRA_MATCH;
+ rx->flags &= ~IEEE80211_RX_RA_MATCH;
} else if (!rx->sta)
rx->sta = ieee80211_ibss_add_sta(sdata->dev, rx->skb,
bssid, hdr->addr2);
break;
+ case IEEE80211_IF_TYPE_MESH_POINT:
+ if (!multicast &&
+ compare_ether_addr(sdata->dev->dev_addr,
+ hdr->addr1) != 0) {
+ if (!(sdata->dev->flags & IFF_PROMISC))
+ return 0;
+
+ rx->flags &= ~IEEE80211_RX_RA_MATCH;
+ }
+ break;
case IEEE80211_IF_TYPE_VLAN:
case IEEE80211_IF_TYPE_AP:
if (!bssid) {
@@ -1721,12 +1838,12 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
return 0;
} else if (!ieee80211_bssid_match(bssid,
sdata->dev->dev_addr)) {
- if (!(rx->flags & IEEE80211_TXRXD_RXIN_SCAN))
+ if (!(rx->flags & IEEE80211_RX_IN_SCAN))
return 0;
- rx->flags &= ~IEEE80211_TXRXD_RXRA_MATCH;
+ rx->flags &= ~IEEE80211_RX_RA_MATCH;
}
if (sdata->dev == sdata->local->mdev &&
- !(rx->flags & IEEE80211_TXRXD_RXIN_SCAN))
+ !(rx->flags & IEEE80211_RX_IN_SCAN))
/* do not receive anything via
* master device when not scanning */
return 0;
@@ -1763,7 +1880,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
struct ieee80211_local *local = hw_to_local(hw);
struct ieee80211_sub_if_data *sdata;
struct ieee80211_hdr *hdr;
- struct ieee80211_txrx_data rx;
+ struct ieee80211_rx_data rx;
u16 type;
int prepares;
struct ieee80211_sub_if_data *prev = NULL;
@@ -1775,9 +1892,9 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
rx.skb = skb;
rx.local = local;
- rx.u.rx.status = status;
- rx.u.rx.load = load;
- rx.u.rx.rate = rate;
+ rx.status = status;
+ rx.load = load;
+ rx.rate = rate;
rx.fc = le16_to_cpu(hdr->frame_control);
type = rx.fc & IEEE80211_FCTL_FTYPE;
@@ -1786,17 +1903,17 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
rx.sta = sta_info_get(local, hdr->addr2);
if (rx.sta) {
- rx.dev = rx.sta->dev;
- rx.sdata = IEEE80211_DEV_TO_SUB_IF(rx.dev);
+ rx.sdata = rx.sta->sdata;
+ rx.dev = rx.sta->sdata->dev;
}
if ((status->flag & RX_FLAG_MMIC_ERROR)) {
ieee80211_rx_michael_mic_report(local->mdev, hdr, &rx);
- goto end;
+ return;
}
if (unlikely(local->sta_sw_scanning || local->sta_hw_scanning))
- rx.flags |= IEEE80211_TXRXD_RXIN_SCAN;
+ rx.flags |= IEEE80211_RX_IN_SCAN;
ieee80211_parse_qos(&rx);
ieee80211_verify_ip_alignment(&rx);
@@ -1811,7 +1928,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
continue;
bssid = ieee80211_get_bssid(hdr, skb->len, sdata->vif.type);
- rx.flags |= IEEE80211_TXRXD_RXRA_MATCH;
+ rx.flags |= IEEE80211_RX_RA_MATCH;
prepares = prepare_for_handlers(sdata, bssid, &rx, hdr);
if (!prepares)
@@ -1851,10 +1968,6 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
ieee80211_invoke_rx_handlers(prev, &rx, skb);
} else
dev_kfree_skb(skb);
-
- end:
- if (rx.sta)
- sta_info_put(rx.sta);
}
#define SEQ_MODULO 0x1000
@@ -2031,7 +2144,7 @@ static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local,
/* if this mpdu is fragmented - terminate rx aggregation session */
sc = le16_to_cpu(hdr->seq_ctrl);
if (sc & IEEE80211_SCTL_FRAG) {
- ieee80211_sta_stop_rx_ba_session(sta->dev, sta->addr,
+ ieee80211_sta_stop_rx_ba_session(sta->sdata->dev, sta->addr,
tid, 0, WLAN_REASON_QSTA_REQUIRE_SETUP);
ret = 1;
goto end_reorder;
@@ -2041,9 +2154,7 @@ static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local,
mpdu_seq_num = (sc & IEEE80211_SCTL_SEQ) >> 4;
ret = ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb,
mpdu_seq_num, 0);
-end_reorder:
- if (sta)
- sta_info_put(sta);
+ end_reorder:
return ret;
}