From 1dbcfdaf2f52ee208a7ee88f09f0642dbdb6c882 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 10 Nov 2009 19:27:19 +0000 Subject: mac80211: implement wds sta support (wds ap support work in progress, needs hostapd changes) SVN-Revision: 18356 --- package/mac80211/files/lib/wifi/mac80211.sh | 5 +- package/mac80211/patches/500-nl80211_4addr.patch | 69 ++++++ .../mac80211/patches/510-mac80211_4addr_vlan.patch | 260 +++++++++++++++++++++ 3 files changed, 333 insertions(+), 1 deletion(-) create mode 100644 package/mac80211/patches/500-nl80211_4addr.patch create mode 100644 package/mac80211/patches/510-mac80211_4addr_vlan.patch (limited to 'package/mac80211') diff --git a/package/mac80211/files/lib/wifi/mac80211.sh b/package/mac80211/files/lib/wifi/mac80211.sh index ccd4d2c389..027749e578 100644 --- a/package/mac80211/files/lib/wifi/mac80211.sh +++ b/package/mac80211/files/lib/wifi/mac80211.sh @@ -104,6 +104,7 @@ enable_mac80211() { config_get enc "$vif" encryption config_get mode "$vif" mode config_get ssid "$vif" ssid + config_get_bool wds "$vif" wds 0 # It is far easier to delete and create the desired interface case "$mode" in @@ -123,7 +124,9 @@ enable_mac80211() { iw phy "$phy" interface add "$ifname" type monitor ;; sta) - iw phy "$phy" interface add "$ifname" type managed + local wdsflag + [ "$wds" -gt 0 ] && wdsflag="wds on" + iw phy "$phy" interface add "$ifname" type managed $wdsflag ;; esac diff --git a/package/mac80211/patches/500-nl80211_4addr.patch b/package/mac80211/patches/500-nl80211_4addr.patch new file mode 100644 index 0000000000..de3b78fdbb --- /dev/null +++ b/package/mac80211/patches/500-nl80211_4addr.patch @@ -0,0 +1,69 @@ +--- a/include/linux/nl80211.h ++++ b/include/linux/nl80211.h +@@ -584,6 +584,8 @@ enum nl80211_commands { + * changed then the list changed and the dump should be repeated + * completely from scratch. + * ++ * @NL80211_ATTR_4ADDR: Use 4-address frames on a virtual interface ++ * + * @NL80211_ATTR_MAX: highest attribute number currently defined + * @__NL80211_ATTR_AFTER_LAST: internal use + */ +@@ -714,6 +716,8 @@ enum nl80211_attrs { + + NL80211_ATTR_PID, + ++ NL80211_ATTR_4ADDR, ++ + /* add attributes here, update the policy in nl80211.c */ + + __NL80211_ATTR_AFTER_LAST, +--- a/include/net/cfg80211.h ++++ b/include/net/cfg80211.h +@@ -207,10 +207,12 @@ struct ieee80211_supported_band { + * struct vif_params - describes virtual interface parameters + * @mesh_id: mesh ID to use + * @mesh_id_len: length of the mesh ID ++ * @use_4addr: use 4-address frames + */ + struct vif_params { + u8 *mesh_id; + int mesh_id_len; ++ int use_4addr; + }; + + /** +--- a/net/wireless/nl80211.c ++++ b/net/wireless/nl80211.c +@@ -140,6 +140,7 @@ static struct nla_policy nl80211_policy[ + [NL80211_ATTR_CIPHER_SUITE_GROUP] = { .type = NLA_U32 }, + [NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 }, + [NL80211_ATTR_PID] = { .type = NLA_U32 }, ++ [NL80211_ATTR_4ADDR] = { .type = NLA_U8 }, + }; + + /* policy for the attributes */ +@@ -989,6 +990,13 @@ static int nl80211_set_interface(struct + change = true; + } + ++ if (info->attrs[NL80211_ATTR_4ADDR]) { ++ params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]); ++ change = true; ++ } else { ++ params.use_4addr = -1; ++ } ++ + if (info->attrs[NL80211_ATTR_MNTR_FLAGS]) { + if (ntype != NL80211_IFTYPE_MONITOR) { + err = -EINVAL; +@@ -1055,6 +1063,9 @@ static int nl80211_new_interface(struct + params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); + } + ++ if (info->attrs[NL80211_ATTR_4ADDR]) ++ params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]); ++ + err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? + info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL, + &flags); diff --git a/package/mac80211/patches/510-mac80211_4addr_vlan.patch b/package/mac80211/patches/510-mac80211_4addr_vlan.patch new file mode 100644 index 0000000000..ac92fe54b1 --- /dev/null +++ b/package/mac80211/patches/510-mac80211_4addr_vlan.patch @@ -0,0 +1,260 @@ +--- a/net/mac80211/ieee80211_i.h ++++ b/net/mac80211/ieee80211_i.h +@@ -208,6 +208,9 @@ struct ieee80211_if_wds { + + struct ieee80211_if_vlan { + struct list_head list; ++ ++ /* used for all tx if the VLAN is configured to 4-addr mode */ ++ struct sta_info *sta; + }; + + struct mesh_stats { +@@ -457,6 +460,8 @@ struct ieee80211_sub_if_data { + int force_unicast_rateidx; /* forced TX rateidx for unicast frames */ + int max_ratectrl_rateidx; /* max TX rateidx for rate control */ + ++ bool use_4addr; /* use 4-address frames */ ++ + union { + struct ieee80211_if_ap ap; + struct ieee80211_if_wds wds; +--- a/net/mac80211/cfg.c ++++ b/net/mac80211/cfg.c +@@ -36,6 +36,24 @@ static bool nl80211_type_check(enum nl80 + } + } + ++static bool nl80211_params_check(enum nl80211_iftype type, ++ struct vif_params *params) ++{ ++ if (!nl80211_type_check(type)) ++ return false; ++ ++ if (params->use_4addr > 0) { ++ switch(type) { ++ case NL80211_IFTYPE_AP_VLAN: ++ case NL80211_IFTYPE_STATION: ++ break; ++ default: ++ return false; ++ } ++ } ++ return true; ++} ++ + static int ieee80211_add_iface(struct wiphy *wiphy, char *name, + enum nl80211_iftype type, u32 *flags, + struct vif_params *params) +@@ -45,7 +63,7 @@ static int ieee80211_add_iface(struct wi + struct ieee80211_sub_if_data *sdata; + int err; + +- if (!nl80211_type_check(type)) ++ if (!nl80211_params_check(type, params)) + return -EINVAL; + + err = ieee80211_if_add(local, name, &dev, type, params); +@@ -75,7 +93,7 @@ static int ieee80211_change_iface(struct + if (netif_running(dev)) + return -EBUSY; + +- if (!nl80211_type_check(type)) ++ if (!nl80211_params_check(type, params)) + return -EINVAL; + + sdata = IEEE80211_DEV_TO_SUB_IF(dev); +@@ -89,6 +107,9 @@ static int ieee80211_change_iface(struct + params->mesh_id_len, + params->mesh_id); + ++ if (params->use_4addr >= 0) ++ sdata->use_4addr = !!params->use_4addr; ++ + if (sdata->vif.type != NL80211_IFTYPE_MONITOR || !flags) + return 0; + +@@ -806,6 +827,13 @@ static int ieee80211_change_station(stru + return -EINVAL; + } + ++ if (vlansdata->use_4addr) { ++ if (vlansdata->u.vlan.sta) ++ return -EBUSY; ++ ++ rcu_assign_pointer(vlansdata->u.vlan.sta, sta); ++ } ++ + sta->sdata = vlansdata; + ieee80211_send_layer2_update(sta); + } +--- a/net/mac80211/sta_info.c ++++ b/net/mac80211/sta_info.c +@@ -489,6 +489,9 @@ static void __sta_info_unlink(struct sta + local->num_sta--; + local->sta_generation++; + ++ if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) ++ rcu_assign_pointer(sdata->u.vlan.sta, NULL); ++ + if (local->ops->sta_notify) { + if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) + sdata = container_of(sdata->bss, +--- a/net/mac80211/tx.c ++++ b/net/mac80211/tx.c +@@ -1046,7 +1046,10 @@ ieee80211_tx_prepare(struct ieee80211_su + + hdr = (struct ieee80211_hdr *) skb->data; + +- tx->sta = sta_info_get(local, hdr->addr1); ++ if ((sdata->vif.type == NL80211_IFTYPE_AP_VLAN) && sdata->use_4addr) ++ tx->sta = rcu_dereference(sdata->u.vlan.sta); ++ if (!tx->sta) ++ tx->sta = sta_info_get(local, hdr->addr1); + + if (tx->sta && ieee80211_is_data_qos(hdr->frame_control) && + (local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION)) { +@@ -1608,7 +1611,7 @@ netdev_tx_t ieee80211_subif_start_xmit(s + const u8 *encaps_data; + int encaps_len, skip_header_bytes; + int nh_pos, h_pos; +- struct sta_info *sta; ++ struct sta_info *sta = NULL; + u32 sta_flags = 0; + + if (unlikely(skb->len < ETH_HLEN)) { +@@ -1625,8 +1628,25 @@ netdev_tx_t ieee80211_subif_start_xmit(s + fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA); + + switch (sdata->vif.type) { +- case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_AP_VLAN: ++ rcu_read_lock(); ++ if (sdata->use_4addr) ++ sta = rcu_dereference(sdata->u.vlan.sta); ++ if (sta) { ++ fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS); ++ /* RA TA DA SA */ ++ memcpy(hdr.addr1, sta->sta.addr, ETH_ALEN); ++ memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN); ++ memcpy(hdr.addr3, skb->data, ETH_ALEN); ++ memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN); ++ hdrlen = 30; ++ sta_flags = get_sta_flags(sta); ++ } ++ rcu_read_unlock(); ++ if (sta) ++ break; ++ /* fall through */ ++ case NL80211_IFTYPE_AP: + fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS); + /* DA BSSID SA */ + memcpy(hdr.addr1, skb->data, ETH_ALEN); +@@ -1700,12 +1720,21 @@ netdev_tx_t ieee80211_subif_start_xmit(s + break; + #endif + case NL80211_IFTYPE_STATION: +- fc |= cpu_to_le16(IEEE80211_FCTL_TODS); +- /* BSSID SA DA */ + memcpy(hdr.addr1, sdata->u.mgd.bssid, ETH_ALEN); +- memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); +- memcpy(hdr.addr3, skb->data, ETH_ALEN); +- hdrlen = 24; ++ if (sdata->use_4addr && ethertype != ETH_P_PAE) { ++ fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS); ++ /* RA TA DA SA */ ++ memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN); ++ memcpy(hdr.addr3, skb->data, ETH_ALEN); ++ memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN); ++ hdrlen = 30; ++ } else { ++ fc |= cpu_to_le16(IEEE80211_FCTL_TODS); ++ /* BSSID SA DA */ ++ memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); ++ memcpy(hdr.addr3, skb->data, ETH_ALEN); ++ hdrlen = 24; ++ } + break; + case NL80211_IFTYPE_ADHOC: + /* DA SA BSSID */ +--- a/net/mac80211/iface.c ++++ b/net/mac80211/iface.c +@@ -772,6 +772,7 @@ int ieee80211_if_change_type(struct ieee + ieee80211_mandatory_rates(sdata->local, + sdata->local->hw.conf.channel->band); + sdata->drop_unencrypted = 0; ++ sdata->use_4addr = 0; + + return 0; + } +@@ -853,6 +854,9 @@ int ieee80211_if_add(struct ieee80211_lo + params->mesh_id_len, + params->mesh_id); + ++ if (params && params->use_4addr >= 0) ++ sdata->use_4addr = !!params->use_4addr; ++ + mutex_lock(&local->iflist_mtx); + list_add_tail_rcu(&sdata->list, &local->interfaces); + mutex_unlock(&local->iflist_mtx); +--- a/net/mac80211/rx.c ++++ b/net/mac80211/rx.c +@@ -1237,6 +1237,13 @@ __ieee80211_data_to_8023(struct ieee8021 + { + struct net_device *dev = rx->dev; + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); ++ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; ++ ++ if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN && !sdata->use_4addr && ++ ieee80211_has_a4(hdr->frame_control)) ++ return -1; ++ if (sdata->use_4addr && is_multicast_ether_addr(hdr->addr1)) ++ return -1; + + return ieee80211_data_to_8023(rx->skb, dev->dev_addr, sdata->vif.type); + } +@@ -1590,6 +1597,7 @@ ieee80211_rx_h_data(struct ieee80211_rx_ + { + struct net_device *dev = rx->dev; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; ++ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + __le16 fc = hdr->frame_control; + int err; + +@@ -1599,6 +1607,14 @@ ieee80211_rx_h_data(struct ieee80211_rx_ + if (unlikely(!ieee80211_is_data_present(hdr->frame_control))) + return RX_DROP_MONITOR; + ++ /* ++ * Allow the cooked monitor interface of an AP to see 4-addr frames so ++ * that a 4-addr station can be detected and moved into a separate VLAN ++ */ ++ if (ieee80211_has_a4(hdr->frame_control) && ++ sdata->vif.type == NL80211_IFTYPE_AP) ++ return RX_DROP_MONITOR; ++ + err = __ieee80211_data_to_8023(rx); + if (unlikely(err)) + return RX_DROP_UNUSABLE; +@@ -2039,7 +2055,7 @@ static int prepare_for_handlers(struct i + + switch (sdata->vif.type) { + case NL80211_IFTYPE_STATION: +- if (!bssid) ++ if (!bssid && !sdata->use_4addr) + return 0; + if (!multicast && + compare_ether_addr(sdata->dev->dev_addr, hdr->addr1) != 0) { +--- a/net/wireless/util.c ++++ b/net/wireless/util.c +@@ -320,7 +320,9 @@ int ieee80211_data_to_8023(struct sk_buf + break; + case cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS): + if (unlikely(iftype != NL80211_IFTYPE_WDS && +- iftype != NL80211_IFTYPE_MESH_POINT)) ++ iftype != NL80211_IFTYPE_MESH_POINT && ++ iftype != NL80211_IFTYPE_AP_VLAN && ++ iftype != NL80211_IFTYPE_STATION)) + return -1; + if (iftype == NL80211_IFTYPE_MESH_POINT) { + struct ieee80211s_hdr *meshdr = -- cgit v1.2.3