diff options
Diffstat (limited to 'package/mac80211/patches/023-mac80211-implement-sta.patch')
-rw-r--r-- | package/mac80211/patches/023-mac80211-implement-sta.patch | 224 |
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 0000000000..095067676c --- /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, + }; |