Since mesh interfaces are not yet using the sta_info structure, a couple of
changes in this patch are a bit ugly ("if mesh, ignore security"), but this will
be resolved when mesh peer link table and sta integration is achieved.
Signed-off-by: Luis Carlos Cobo <[email protected]>
---
net/mac80211/rx.c | 119 ++++++++++++++++++++++++++++++++++++++++++++++++++--
net/mac80211/tx.c | 51 ++++++++++++++++++++--
2 files changed, 160 insertions(+), 10 deletions(-)
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index beda1bf..40c8824 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -19,6 +19,7 @@
#include "ieee80211_i.h"
#include "ieee80211_led.h"
+#include "mesh.h"
#include "wep.h"
#include "wpa.h"
#include "tkip.h"
@@ -390,6 +391,8 @@ static ieee80211_txrx_result
ieee80211_rx_h_check(struct ieee80211_txrx_data *rx)
{
struct ieee80211_hdr *hdr;
+ int hdrlen = ieee80211_get_hdrlen(rx->fc);
+
hdr = (struct ieee80211_hdr *) rx->skb->data;
/* Drop duplicate 802.11 retransmissions (IEEE 802.11 Chap. 9.2.9) */
@@ -419,6 +422,54 @@ 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 (rx->sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) {
+ if ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) {
+ if (!((rx->fc & IEEE80211_FCTL_FROMDS) &&
+ (rx->fc & IEEE80211_FCTL_TODS)))
+ return TXRX_DROP;
+ if (memcmp(hdr->addr4,
+ rx->dev->dev_addr, ETH_ALEN) == 0)
+ return TXRX_DROP;
+ }
+
+ /* If there is not an established peer link and this is
+ * not a peer link establisment frame, beacon or probe,
+ * drop the frame.
+ */
+ if (!is_estab_plink(hdr->addr2, rx->dev)) {
+ if ((rx->fc & IEEE80211_FCTL_FTYPE) !=
+ IEEE80211_FTYPE_MGMT)
+ return TXRX_DROP;
+ else {
+ struct ieee80211_mgmt *mgmt;
+ switch (rx->fc & IEEE80211_FCTL_STYPE) {
+ case IEEE80211_STYPE_ACTION:
+ mgmt = (struct ieee80211_mgmt *)hdr;
+ if (mgmt->u.action.category !=
+ PLINK_CATEGORY)
+ return TXRX_DROP;
+ /* fall through on else */
+ case IEEE80211_STYPE_PROBE_REQ:
+ case IEEE80211_STYPE_PROBE_RESP:
+ case IEEE80211_STYPE_BEACON:
+ return TXRX_CONTINUE;
+ break;
+ default:
+ return TXRX_DROP;
+ }
+ }
+ } else if ((rx->fc & IEEE80211_FCTL_FTYPE)
+ == IEEE80211_FTYPE_DATA &&
+ (is_broadcast_ether_addr(hdr->addr1)) &&
+ mesh_rmc_check(hdr->addr4, (struct ieee80211s_hdr *)
+ (rx->skb->data + hdrlen), rx->dev))
+ return TXRX_DROP;
+
+ else
+ return TXRX_CONTINUE;
+ }
+
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)) &&
@@ -987,7 +1038,8 @@ ieee80211_rx_h_remove_qos_control(struct ieee80211_txrx_data *rx)
static int
ieee80211_802_1x_port_control(struct ieee80211_txrx_data *rx)
{
- if (unlikely(!rx->sta || !(rx->sta->flags & WLAN_STA_AUTHORIZED))) {
+ if (rx->sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT &&
+ (!rx->sta || !(rx->sta->flags & WLAN_STA_AUTHORIZED))) {
#ifdef CONFIG_MAC80211_DEBUG
if (net_ratelimit())
printk(KERN_DEBUG "%s: dropped frame "
@@ -1045,6 +1097,21 @@ ieee80211_data_to_8023(struct ieee80211_txrx_data *rx)
hdrlen = ieee80211_get_hdrlen(fc);
+ if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) {
+ 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:
@@ -1078,9 +1145,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),
@@ -1222,6 +1290,36 @@ ieee80211_deliver_skb(struct ieee80211_txrx_data *rx)
}
}
+ /* Mesh forwarding */
+ if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) {
+ 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
+ sdata->u.sta.mshstats.dropped_frames_ttl++;
+ } else if (skb->pkt_type != PACKET_OTHERHOST &&
+ compare_ether_addr(sdata->dev->dev_addr, skb->data)
+ != 0) {
+ if (*mesh_ttl == 0) {
+ sdata->u.sta.mshstats.dropped_frames_ttl++;
+ dev_kfree_skb(skb);
+ skb = NULL;
+ } else {
+ xmit_skb = skb;
+ xmit_skb->pkt_type = PACKET_OTHERHOST;
+ if (!(sdata->dev->flags & IFF_PROMISC))
+ skb = NULL;
+ }
+ }
+ }
+
if (skb) {
/* deliver to local stack */
skb->protocol = eth_type_trans(skb, dev);
@@ -1439,7 +1537,8 @@ ieee80211_rx_h_mgmt(struct ieee80211_txrx_data *rx)
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);
else
@@ -1626,6 +1725,16 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
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_TXRXD_RXRA_MATCH;
+ }
+ break;
case IEEE80211_IF_TYPE_VLAN:
case IEEE80211_IF_TYPE_AP:
if (!bssid) {
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 2b47464..58b026a 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -26,6 +26,7 @@
#include "ieee80211_i.h"
#include "ieee80211_led.h"
+#include "mesh.h"
#include "wep.h"
#include "wpa.h"
#include "wme.h"
@@ -249,6 +250,9 @@ ieee80211_tx_h_check_assoc(struct ieee80211_txrx_data *tx)
(tx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_PROBE_REQ))
return TXRX_DROP;
+ if (tx->sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT)
+ return TXRX_CONTINUE;
+
if (tx->flags & IEEE80211_TXRXD_TXPS_BUFFERED)
return TXRX_CONTINUE;
@@ -1388,8 +1392,9 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
struct ieee80211_tx_packet_data *pkt_data;
struct ieee80211_sub_if_data *sdata;
int ret = 1, head_need;
- u16 ethertype, hdrlen, fc;
+ u16 ethertype, hdrlen, meshhdrlen = 0, fc;
struct ieee80211_hdr hdr;
+ struct ieee80211s_hdr mesh_hdr;
const u8 *encaps_data;
int encaps_len, skip_header_bytes;
int nh_pos, h_pos;
@@ -1431,6 +1436,35 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN);
hdrlen = 30;
break;
+ case IEEE80211_IF_TYPE_MESH_POINT:
+ fc |= IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS;
+ /* RA TA DA SA */
+ if (is_multicast_ether_addr(skb->data))
+ memcpy(hdr.addr1, skb->data, ETH_ALEN);
+ else if (mesh_lookup_nexthop(hdr.addr1, skb, dev))
+ return 0;
+ memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN);
+ memcpy(hdr.addr3, skb->data, ETH_ALEN);
+ memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN);
+ if (skb->pkt_type == PACKET_OTHERHOST) {
+ /* Forwarded frame, keep mesh ttl and seqnum */
+ struct ieee80211s_hdr *prev_meshhdr;
+ prev_meshhdr = ((struct ieee80211s_hdr *)skb->cb);
+ meshhdrlen = ieee80211_get_mesh_hdrlen(prev_meshhdr);
+ memcpy(&mesh_hdr, prev_meshhdr, meshhdrlen);
+ sdata->u.sta.mshstats.fwded_frames++;
+ } else {
+ if (!sdata->u.sta.mshcfg.dot11MeshTTL) {
+ /* Do not send frames with mesh_ttl == 0 */
+ sdata->u.sta.mshstats.dropped_frames_ttl++;
+ ret = 0;
+ goto fail;
+ }
+ meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr,
+ sdata);
+ }
+ hdrlen = 30;
+ break;
case IEEE80211_IF_TYPE_STA:
fc |= IEEE80211_FCTL_TODS;
/* BSSID SA DA */
@@ -1474,9 +1508,10 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
* Drop unicast frames to unauthorised stations unless they are
* EAPOL frames from the local station.
*/
- if (unlikely(!is_multicast_ether_addr(hdr.addr1) &&
- !(sta_flags & WLAN_STA_AUTHORIZED) &&
- !(ethertype == ETH_P_PAE &&
+ if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT &&
+ (!is_multicast_ether_addr(hdr.addr1) &&
+ !(sta_flags & WLAN_STA_AUTHORIZED) &&
+ !(ethertype == ETH_P_PAE &&
compare_ether_addr(dev->dev_addr,
skb->data + ETH_ALEN) == 0))) {
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
@@ -1529,7 +1564,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
* build in headroom in __dev_alloc_skb() (linux/skbuff.h) and
* alloc_skb() (net/core/skbuff.c)
*/
- head_need = hdrlen + encaps_len + local->tx_headroom;
+ head_need = hdrlen + encaps_len + meshhdrlen + local->tx_headroom;
head_need -= skb_headroom(skb);
/* We are going to modify skb data, so make a copy of it if happens to
@@ -1563,6 +1598,12 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
h_pos += encaps_len;
}
+ if (meshhdrlen > 0) {
+ memcpy(skb_push(skb, meshhdrlen), &mesh_hdr, meshhdrlen);
+ nh_pos += meshhdrlen;
+ h_pos += meshhdrlen;
+ }
+
if (fc & IEEE80211_STYPE_QOS_DATA) {
__le16 *qos_control;
--
1.5.2.5
On Fri, 2008-02-08 at 16:36 -0800, Luis Carlos Cobo wrote:
> On Thu, 2008-02-07 at 01:53 +0100, Johannes Berg wrote:
> > > + if (!is_estab_plink(hdr->addr2, rx->dev)) {
> >
> > This would get to be something like
> >
> > if (sta->flags & STA_FLAG_MESH_LINK_ESTABLISHED)
> >
> > right?
>
> I probably can use just the AUTHORIZED flag.
Hm. The authorized flag basically says that it's possible to
send/receive non-eapol data frames to/from that station. I think you
shouldn't overload it, might not an implementation of secure peer links
need to be able to distinguish between different states? In any case,
adding a new flag is cheap and more self-explanatory imho.
> > I suppose you should be adding sta_info structs for each mesh peer and
> > set the AUTHORIZED flag on them. Is this what you were referring to in
> > the patch description?
>
> Right, and adding a pointer to a reduced mesh peer link structure with
> variables only needed for mesh (it would only be allocated for mesh
> interfaces).
Sounds good.
> Btw, I will also fix all the issues I'm not commenting on in this patch
> and the others. Thanks for you patience with me!
Well thanks for doing this work in the first place! :)
johannes
On Thu, 2008-02-07 at 01:53 +0100, Johannes Berg wrote:
> > + if (!is_estab_plink(hdr->addr2, rx->dev)) {
>
> This would get to be something like
>
> if (sta->flags & STA_FLAG_MESH_LINK_ESTABLISHED)
>
> right?
I probably can use just the AUTHORIZED flag.
> I suppose you should be adding sta_info structs for each mesh peer and
> set the AUTHORIZED flag on them. Is this what you were referring to in
> the patch description?
Right, and adding a pointer to a reduced mesh peer link structure with
variables only needed for mesh (it would only be allocated for mesh
interfaces).
> type == ETH_P_PAE &&
> > + if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT &&
> > + (!is_multicast_ether_addr(hdr.addr1) &&
> > + !(sta_flags & WLAN_STA_AUTHORIZED) &&
> > + !(ethertype == ETH_P_PAE &&
> > compare_ether_addr(dev->dev_addr,
> > skb->data + ETH_ALEN) == 0))) {
>
> That's also an artifact of not adding sta info structs, right?
Indeed, will be gone in the next round.
Btw, I will also fix all the issues I'm not commenting on in this patch
and the others. Thanks for you patience with me!
--
Luis Carlos Cobo Rus GnuPG ID: 44019B60
cozybit Inc.
On Thu, 2008-02-07 at 01:53 +0100, Johannes Berg wrote:
> > + if (rx->sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) {
> > + if ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) {
> > + if (!((rx->fc & IEEE80211_FCTL_FROMDS) &&
> > + (rx->fc & IEEE80211_FCTL_TODS)))
>
> It'd be shorter to write
>
> if (rx->fc ^ (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS))
>
> but I'm not sure that's easier to understand ;)
Would that work? For data frames rx->fc is 0xYY08 (with YY being the
flags, including fromDS/toDS), so they would always evaluate to true in
that if, regardless of the flags.
--
Luis Carlos Cobo Rus GnuPG ID: 44019B60
cozybit Inc.
> > It'd be shorter to write
> >
> > if (rx->fc ^ (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS))
> >
> > but I'm not sure that's easier to understand ;)
>
> Would that work? For data frames rx->fc is 0xYY08 (with YY being the
> flags, including fromDS/toDS), so they would always evaluate to true in
> that if, regardless of the flags.
Hah, you're right, sorry.
johannes
> + if (rx->sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) {
> + if ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) {
> + if (!((rx->fc & IEEE80211_FCTL_FROMDS) &&
> + (rx->fc & IEEE80211_FCTL_TODS)))
It'd be shorter to write
if (rx->fc ^ (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS))
but I'm not sure that's easier to understand ;)
> + /* If there is not an established peer link and this is
> + * not a peer link establisment frame, beacon or probe,
> + * drop the frame.
> + */
> + if (!is_estab_plink(hdr->addr2, rx->dev)) {
This would get to be something like
if (sta->flags & STA_FLAG_MESH_LINK_ESTABLISHED)
right?
> + if ((rx->fc & IEEE80211_FCTL_FTYPE) !=
> + IEEE80211_FTYPE_MGMT)
> + return TXRX_DROP;
All this deep indentation is pretty ugly. Can you create a new function
static void rx_result ieee80211_rx_check_mesh(...)
and in ieee80211_rx_h_check() simply do
if (rx->sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT)
return ieee80211_rx_check_mesh(...);
please?
> @@ -987,7 +1038,8 @@ ieee80211_rx_h_remove_qos_control(struct ieee80211_txrx_data *rx)
> static int
> ieee80211_802_1x_port_control(struct ieee80211_txrx_data *rx)
> {
> - if (unlikely(!rx->sta || !(rx->sta->flags & WLAN_STA_AUTHORIZED))) {
> + if (rx->sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT &&
> + (!rx->sta || !(rx->sta->flags & WLAN_STA_AUTHORIZED))) {
I suppose you should be adding sta_info structs for each mesh peer and
set the AUTHORIZED flag on them. Is this what you were referring to in
the patch description?
> @@ -1222,6 +1290,36 @@ ieee80211_deliver_skb(struct ieee80211_txrx_data *rx)
> }
> }
>
> + /* Mesh forwarding */
> + if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) {
Similarly here, I think this code could benefit from the outdenting
achieved by putting it into an own function, the compiler will inline it
anyway. Also that could simplify #ifdef'ing the mesh code if we want
that.
> @@ -1474,9 +1508,10 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
> * Drop unicast frames to unauthorised stations unless they are
> * EAPOL frames from the local station.
> */
> - if (unlikely(!is_multicast_ether_addr(hdr.addr1) &&
> - !(sta_flags & WLAN_STA_AUTHORIZED) &&
> - !(ethertype == ETH_P_PAE &&
> + if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT &&
> + (!is_multicast_ether_addr(hdr.addr1) &&
> + !(sta_flags & WLAN_STA_AUTHORIZED) &&
> + !(ethertype == ETH_P_PAE &&
> compare_ether_addr(dev->dev_addr,
> skb->data + ETH_ALEN) == 0))) {
That's also an artifact of not adding sta info structs, right?
johannes