summaryrefslogtreecommitdiff
path: root/package/mac80211/patches/023-mac80211-implement-sta.patch
diff options
context:
space:
mode:
Diffstat (limited to 'package/mac80211/patches/023-mac80211-implement-sta.patch')
-rw-r--r--package/mac80211/patches/023-mac80211-implement-sta.patch224
1 files changed, 224 insertions, 0 deletions
diff --git a/package/mac80211/patches/023-mac80211-implement-sta.patch b/package/mac80211/patches/023-mac80211-implement-sta.patch
new file mode 100644
index 0000000..0950676
--- /dev/null
+++ b/package/mac80211/patches/023-mac80211-implement-sta.patch
@@ -0,0 +1,224 @@
+Subject: mac80211: implement cfg80211's station handling
+
+This implements station handling from userspace via cfg80211
+in mac80211.
+
+Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
+
+---
+ net/mac80211/cfg.c | 192 +++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 192 insertions(+)
+
+--- everything.orig/net/mac80211/cfg.c 2007-11-08 17:11:52.351521702 +0100
++++ everything/net/mac80211/cfg.c 2007-11-08 17:15:51.801523493 +0100
+@@ -14,6 +14,7 @@
+ #include <net/cfg80211.h>
+ #include "ieee80211_i.h"
+ #include "cfg.h"
++#include "ieee80211_rate.h"
+
+ static enum ieee80211_if_types
+ nl80211_type_to_mac80211_type(enum nl80211_iftype type)
+@@ -428,6 +429,194 @@ static int ieee80211_del_beacon(struct w
+ return ieee80211_if_config_beacon(dev);
+ }
+
++/* Layer 2 Update frame (802.2 Type 1 LLC XID Update response) */
++struct iapp_layer2_update {
++ u8 da[ETH_ALEN]; /* broadcast */
++ u8 sa[ETH_ALEN]; /* STA addr */
++ __be16 len; /* 6 */
++ u8 dsap; /* 0 */
++ u8 ssap; /* 0 */
++ u8 control;
++ u8 xid_info[3];
++} __attribute__ ((packed));
++
++static void ieee80211_send_layer2_update(struct sta_info *sta)
++{
++ struct iapp_layer2_update *msg;
++ struct sk_buff *skb;
++
++ /* Send Level 2 Update Frame to update forwarding tables in layer 2
++ * bridge devices */
++
++ skb = dev_alloc_skb(sizeof(*msg));
++ if (!skb)
++ return;
++ msg = (struct iapp_layer2_update *)skb_put(skb, sizeof(*msg));
++
++ /* 802.2 Type 1 Logical Link Control (LLC) Exchange Identifier (XID)
++ * Update response frame; IEEE Std 802.2-1998, 5.4.1.2.1 */
++
++ memset(msg->da, 0xff, ETH_ALEN);
++ memcpy(msg->sa, sta->addr, ETH_ALEN);
++ msg->len = htons(6);
++ msg->dsap = 0;
++ msg->ssap = 0x01; /* NULL LSAP, CR Bit: Response */
++ msg->control = 0xaf; /* XID response lsb.1111F101.
++ * F=0 (no poll command; unsolicited frame) */
++ msg->xid_info[0] = 0x81; /* XID format identifier */
++ msg->xid_info[1] = 1; /* LLC types/classes: Type 1 LLC */
++ msg->xid_info[2] = 0; /* XID sender's receive window size (RW) */
++
++ skb->dev = sta->dev;
++ skb->protocol = eth_type_trans(skb, sta->dev);
++ memset(skb->cb, 0, sizeof(skb->cb));
++ netif_rx(skb);
++}
++
++static void sta_apply_parameters(struct ieee80211_local *local,
++ struct sta_info *sta,
++ struct station_parameters *params)
++{
++ u32 rates;
++ int i, j;
++ struct ieee80211_hw_mode *mode;
++
++ if (params->station_flags & STATION_FLAG_CHANGED) {
++ sta->flags &= ~WLAN_STA_AUTHORIZED;
++ if (params->station_flags & STATION_FLAG_AUTHORIZED)
++ sta->flags |= WLAN_STA_AUTHORIZED;
++
++ sta->flags &= ~WLAN_STA_SHORT_PREAMBLE;
++ if (params->station_flags & STATION_FLAG_SHORT_PREAMBLE)
++ sta->flags |= WLAN_STA_SHORT_PREAMBLE;
++
++ sta->flags &= ~WLAN_STA_WME;
++ if (params->station_flags & STATION_FLAG_WME)
++ sta->flags |= WLAN_STA_WME;
++ }
++
++ if (params->aid) {
++ sta->aid = params->aid;
++ if (sta->aid > IEEE80211_MAX_AID)
++ sta->aid = 0; /* XXX: should this be an error? */
++ }
++
++ if (params->listen_interval >= 0)
++ sta->listen_interval = params->listen_interval;
++
++ if (params->supported_rates) {
++ rates = 0;
++ mode = local->oper_hw_mode;
++ for (i = 0; i < params->supported_rates_len; i++) {
++ int rate = (params->supported_rates[i] & 0x7f) * 5;
++ for (j = 0; j < mode->num_rates; j++) {
++ if (mode->rates[j].rate == rate)
++ rates |= BIT(j);
++ }
++ }
++ sta->supp_rates = rates;
++ }
++}
++
++static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
++ u8 *mac, struct station_parameters *params)
++{
++ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
++ struct sta_info *sta;
++ struct ieee80211_sub_if_data *sdata;
++
++ /* Prevent a race with changing the rate control algorithm */
++ if (!netif_running(dev))
++ return -ENETDOWN;
++
++ /* XXX: get sta belonging to dev */
++ sta = sta_info_get(local, mac);
++ if (sta) {
++ sta_info_put(sta);
++ return -EEXIST;
++ }
++
++ if (params->vlan) {
++ sdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);
++
++ if (sdata->type != IEEE80211_IF_TYPE_VLAN ||
++ sdata->type != IEEE80211_IF_TYPE_AP)
++ return -EINVAL;
++ } else
++ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
++
++ sta = sta_info_add(local, dev, mac, GFP_KERNEL);
++ if (!sta)
++ return -ENOMEM;
++
++ sta->dev = sdata->dev;
++ if (sdata->type == IEEE80211_IF_TYPE_VLAN ||
++ sdata->type == IEEE80211_IF_TYPE_AP)
++ ieee80211_send_layer2_update(sta);
++
++ sta->flags = WLAN_STA_AUTH | WLAN_STA_ASSOC;
++
++ sta_apply_parameters(local, sta, params);
++
++ rate_control_rate_init(sta, local);
++
++ sta_info_put(sta);
++
++ return 0;
++}
++
++static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev,
++ u8 *mac)
++{
++ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
++ struct sta_info *sta;
++
++ if (mac) {
++ /* XXX: get sta belonging to dev */
++ sta = sta_info_get(local, mac);
++ if (!sta)
++ return -ENOENT;
++
++ sta_info_free(sta);
++ sta_info_put(sta);
++ } else
++ sta_info_flush(local, dev);
++
++ return 0;
++}
++
++static int ieee80211_change_station(struct wiphy *wiphy,
++ struct net_device *dev,
++ u8 *mac,
++ struct station_parameters *params)
++{
++ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
++ struct sta_info *sta;
++ struct ieee80211_sub_if_data *vlansdata;
++
++ /* XXX: get sta belonging to dev */
++ sta = sta_info_get(local, mac);
++ if (!sta)
++ return -ENOENT;
++
++ if (params->vlan && params->vlan != sta->dev) {
++ vlansdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);
++
++ if (vlansdata->type != IEEE80211_IF_TYPE_VLAN ||
++ vlansdata->type != IEEE80211_IF_TYPE_AP)
++ return -EINVAL;
++
++ sta->dev = params->vlan;
++ ieee80211_send_layer2_update(sta);
++ }
++
++ sta_apply_parameters(local, sta, params);
++
++ sta_info_put(sta);
++
++ return 0;
++}
++
+ struct cfg80211_ops mac80211_config_ops = {
+ .add_virtual_intf = ieee80211_add_iface,
+ .del_virtual_intf = ieee80211_del_iface,
+@@ -439,4 +628,7 @@ struct cfg80211_ops mac80211_config_ops
+ .add_beacon = ieee80211_add_beacon,
+ .set_beacon = ieee80211_set_beacon,
+ .del_beacon = ieee80211_del_beacon,
++ .add_station = ieee80211_add_station,
++ .del_station = ieee80211_del_station,
++ .change_station = ieee80211_change_station,
+ };