mac80211: Send Layer 2 Update frame on reassociation
[safe/jmp/linux-2.6] / net / mac80211 / cfg.c
index 5a3bdaa..9d4e4d8 100644 (file)
 #include "rate.h"
 #include "mesh.h"
 
-struct ieee80211_hw *wiphy_to_hw(struct wiphy *wiphy)
-{
-       struct ieee80211_local *local = wiphy_priv(wiphy);
-       return &local->hw;
-}
-EXPORT_SYMBOL(wiphy_to_hw);
-
-static enum ieee80211_if_types
-nl80211_type_to_mac80211_type(enum nl80211_iftype type)
+static bool nl80211_type_check(enum nl80211_iftype type)
 {
        switch (type) {
-       case NL80211_IFTYPE_UNSPECIFIED:
-               return IEEE80211_IF_TYPE_STA;
        case NL80211_IFTYPE_ADHOC:
-               return IEEE80211_IF_TYPE_IBSS;
        case NL80211_IFTYPE_STATION:
-               return IEEE80211_IF_TYPE_STA;
        case NL80211_IFTYPE_MONITOR:
-               return IEEE80211_IF_TYPE_MNTR;
 #ifdef CONFIG_MAC80211_MESH
        case NL80211_IFTYPE_MESH_POINT:
-               return IEEE80211_IF_TYPE_MESH_POINT;
 #endif
+       case NL80211_IFTYPE_AP:
+       case NL80211_IFTYPE_AP_VLAN:
        case NL80211_IFTYPE_WDS:
-               return IEEE80211_IF_TYPE_WDS;
+               return true;
        default:
-               return IEEE80211_IF_TYPE_INVALID;
+               return false;
        }
 }
 
@@ -52,17 +40,15 @@ static int ieee80211_add_iface(struct wiphy *wiphy, char *name,
                               struct vif_params *params)
 {
        struct ieee80211_local *local = wiphy_priv(wiphy);
-       enum ieee80211_if_types itype;
        struct net_device *dev;
        struct ieee80211_sub_if_data *sdata;
        int err;
 
-       itype = nl80211_type_to_mac80211_type(type);
-       if (itype == IEEE80211_IF_TYPE_INVALID)
+       if (!nl80211_type_check(type))
                return -EINVAL;
 
-       err = ieee80211_if_add(local, name, &dev, itype, params);
-       if (err || itype != IEEE80211_IF_TYPE_MNTR || !flags)
+       err = ieee80211_if_add(local, name, &dev, type, params);
+       if (err || type != NL80211_IFTYPE_MONITOR || !flags)
                return err;
 
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
@@ -91,9 +77,7 @@ static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex,
                                  enum nl80211_iftype type, u32 *flags,
                                  struct vif_params *params)
 {
-       struct ieee80211_local *local = wiphy_priv(wiphy);
        struct net_device *dev;
-       enum ieee80211_if_types itype;
        struct ieee80211_sub_if_data *sdata;
        int ret;
 
@@ -102,25 +86,24 @@ static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex,
        if (!dev)
                return -ENODEV;
 
-       itype = nl80211_type_to_mac80211_type(type);
-       if (itype == IEEE80211_IF_TYPE_INVALID)
+       if (!nl80211_type_check(type))
                return -EINVAL;
 
-       if (dev == local->mdev)
-               return -EOPNOTSUPP;
-
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-       ret = ieee80211_if_change_type(sdata, itype);
+       ret = ieee80211_if_change_type(sdata, type);
        if (ret)
                return ret;
 
+       if (netif_running(sdata->dev))
+               return -EBUSY;
+
        if (ieee80211_vif_is_mesh(&sdata->vif) && params->mesh_id_len)
-               ieee80211_if_sta_set_mesh_id(&sdata->u.sta,
-                                            params->mesh_id_len,
-                                            params->mesh_id);
+               ieee80211_sdata_set_mesh_id(sdata,
+                                           params->mesh_id_len,
+                                           params->mesh_id);
 
-       if (sdata->vif.type != IEEE80211_IF_TYPE_MNTR || !flags)
+       if (sdata->vif.type != NL80211_IFTYPE_MONITOR || !flags)
                return 0;
 
        sdata->u.mntr_flags = *flags;
@@ -131,16 +114,12 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
                             u8 key_idx, u8 *mac_addr,
                             struct key_params *params)
 {
-       struct ieee80211_local *local = wiphy_priv(wiphy);
        struct ieee80211_sub_if_data *sdata;
        struct sta_info *sta = NULL;
        enum ieee80211_key_alg alg;
        struct ieee80211_key *key;
        int err;
 
-       if (dev == local->mdev)
-               return -EOPNOTSUPP;
-
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
        switch (params->cipher) {
@@ -185,14 +164,10 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
 static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
                             u8 key_idx, u8 *mac_addr)
 {
-       struct ieee80211_local *local = wiphy_priv(wiphy);
        struct ieee80211_sub_if_data *sdata;
        struct sta_info *sta;
        int ret;
 
-       if (dev == local->mdev)
-               return -EOPNOTSUPP;
-
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
        rcu_read_lock();
@@ -233,7 +208,6 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
                             void (*callback)(void *cookie,
                                              struct key_params *params))
 {
-       struct ieee80211_local *local = wiphy_priv(wiphy);
        struct ieee80211_sub_if_data *sdata;
        struct sta_info *sta = NULL;
        u8 seq[6] = {0};
@@ -243,9 +217,6 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
        u16 iv16;
        int err = -ENOENT;
 
-       if (dev == local->mdev)
-               return -EOPNOTSUPP;
-
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
        rcu_read_lock();
@@ -321,12 +292,8 @@ static int ieee80211_config_default_key(struct wiphy *wiphy,
                                        struct net_device *dev,
                                        u8 key_idx)
 {
-       struct ieee80211_local *local = wiphy_priv(wiphy);
        struct ieee80211_sub_if_data *sdata;
 
-       if (dev == local->mdev)
-               return -EOPNOTSUPP;
-
        rcu_read_lock();
 
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
@@ -343,12 +310,35 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
 
        sinfo->filled = STATION_INFO_INACTIVE_TIME |
                        STATION_INFO_RX_BYTES |
-                       STATION_INFO_TX_BYTES;
+                       STATION_INFO_TX_BYTES |
+                       STATION_INFO_TX_BITRATE;
 
        sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx);
        sinfo->rx_bytes = sta->rx_bytes;
        sinfo->tx_bytes = sta->tx_bytes;
 
+       if (sta->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) {
+               sinfo->filled |= STATION_INFO_SIGNAL;
+               sinfo->signal = (s8)sta->last_signal;
+       }
+
+       sinfo->txrate.flags = 0;
+       if (sta->last_tx_rate.flags & IEEE80211_TX_RC_MCS)
+               sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
+       if (sta->last_tx_rate.flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
+               sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
+       if (sta->last_tx_rate.flags & IEEE80211_TX_RC_SHORT_GI)
+               sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
+
+       if (!(sta->last_tx_rate.flags & IEEE80211_TX_RC_MCS)) {
+               struct ieee80211_supported_band *sband;
+               sband = sta->local->hw.wiphy->bands[
+                               sta->local->hw.conf.channel->band];
+               sinfo->txrate.legacy =
+                       sband->bitrates[sta->last_tx_rate.idx].bitrate;
+       } else
+               sinfo->txrate.mcs = sta->last_tx_rate.idx;
+
        if (ieee80211_vif_is_mesh(&sdata->vif)) {
 #ifdef CONFIG_MAC80211_MESH
                sinfo->filled |= STATION_INFO_LLID |
@@ -375,7 +365,7 @@ static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev,
        sta = sta_info_get_by_idx(local, idx, dev);
        if (sta) {
                ret = 0;
-               memcpy(mac, sta->addr, ETH_ALEN);
+               memcpy(mac, sta->sta.addr, ETH_ALEN);
                sta_set_sinfo(sta, sinfo);
        }
 
@@ -429,8 +419,10 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata,
         */
        if (params->interval) {
                sdata->local->hw.conf.beacon_int = params->interval;
-               if (ieee80211_hw_config(sdata->local))
-                       return -EINVAL;
+               err = ieee80211_hw_config(sdata->local,
+                                       IEEE80211_CONF_CHANGE_BEACON_INTERVAL);
+               if (err < 0)
+                       return err;
                /*
                 * We updated some parameter so if below bails out
                 * it's not an error.
@@ -507,16 +499,12 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata,
 static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev,
                                struct beacon_parameters *params)
 {
-       struct ieee80211_local *local = wiphy_priv(wiphy);
        struct ieee80211_sub_if_data *sdata;
        struct beacon_data *old;
 
-       if (dev == local->mdev)
-               return -EOPNOTSUPP;
-
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-       if (sdata->vif.type != IEEE80211_IF_TYPE_AP)
+       if (sdata->vif.type != NL80211_IFTYPE_AP)
                return -EINVAL;
 
        old = sdata->u.ap.beacon;
@@ -530,16 +518,12 @@ static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev,
 static int ieee80211_set_beacon(struct wiphy *wiphy, struct net_device *dev,
                                struct beacon_parameters *params)
 {
-       struct ieee80211_local *local = wiphy_priv(wiphy);
        struct ieee80211_sub_if_data *sdata;
        struct beacon_data *old;
 
-       if (dev == local->mdev)
-               return -EOPNOTSUPP;
-
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-       if (sdata->vif.type != IEEE80211_IF_TYPE_AP)
+       if (sdata->vif.type != NL80211_IFTYPE_AP)
                return -EINVAL;
 
        old = sdata->u.ap.beacon;
@@ -552,16 +536,12 @@ static int ieee80211_set_beacon(struct wiphy *wiphy, struct net_device *dev,
 
 static int ieee80211_del_beacon(struct wiphy *wiphy, struct net_device *dev)
 {
-       struct ieee80211_local *local = wiphy_priv(wiphy);
        struct ieee80211_sub_if_data *sdata;
        struct beacon_data *old;
 
-       if (dev == local->mdev)
-               return -EOPNOTSUPP;
-
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-       if (sdata->vif.type != IEEE80211_IF_TYPE_AP)
+       if (sdata->vif.type != NL80211_IFTYPE_AP)
                return -EINVAL;
 
        old = sdata->u.ap.beacon;
@@ -604,7 +584,7 @@ static void ieee80211_send_layer2_update(struct sta_info *sta)
         * 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);
+       memcpy(msg->sa, sta->sta.addr, ETH_ALEN);
        msg->len = htons(6);
        msg->dsap = 0;
        msg->ssap = 0x01;       /* NULL LSAP, CR Bit: Response */
@@ -629,6 +609,8 @@ static void sta_apply_parameters(struct ieee80211_local *local,
        struct ieee80211_supported_band *sband;
        struct ieee80211_sub_if_data *sdata = sta->sdata;
 
+       sband = local->hw.wiphy->bands[local->oper_channel->band];
+
        /*
         * FIXME: updating the flags is racy when this function is
         *        called from ieee80211_change_station(), this will
@@ -659,9 +641,9 @@ static void sta_apply_parameters(struct ieee80211_local *local,
         */
 
        if (params->aid) {
-               sta->aid = params->aid;
-               if (sta->aid > IEEE80211_MAX_AID)
-                       sta->aid = 0; /* XXX: should this be an error? */
+               sta->sta.aid = params->aid;
+               if (sta->sta.aid > IEEE80211_MAX_AID)
+                       sta->sta.aid = 0; /* XXX: should this be an error? */
        }
 
        if (params->listen_interval >= 0)
@@ -669,7 +651,6 @@ static void sta_apply_parameters(struct ieee80211_local *local,
 
        if (params->supported_rates) {
                rates = 0;
-               sband = local->hw.wiphy->bands[local->oper_channel->band];
 
                for (i = 0; i < params->supported_rates_len; i++) {
                        int rate = (params->supported_rates[i] & 0x7f) * 5;
@@ -678,13 +659,13 @@ static void sta_apply_parameters(struct ieee80211_local *local,
                                        rates |= BIT(j);
                        }
                }
-               sta->supp_rates[local->oper_channel->band] = rates;
+               sta->sta.supp_rates[local->oper_channel->band] = rates;
        }
 
-       if (params->ht_capa) {
-               ieee80211_ht_cap_ie_to_ht_info(params->ht_capa,
-                                              &sta->ht_info);
-       }
+       if (params->ht_capa)
+               ieee80211_ht_cap_ie_to_sta_ht_cap(sband,
+                                                 params->ht_capa,
+                                                 &sta->sta.ht_cap);
 
        if (ieee80211_vif_is_mesh(&sdata->vif) && params->plink_action) {
                switch (params->plink_action) {
@@ -705,9 +686,7 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
        struct sta_info *sta;
        struct ieee80211_sub_if_data *sdata;
        int err;
-
-       if (dev == local->mdev || params->vlan == local->mdev)
-               return -EOPNOTSUPP;
+       int layer2_update;
 
        /* Prevent a race with changing the rate control algorithm */
        if (!netif_running(dev))
@@ -716,8 +695,8 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
        if (params->vlan) {
                sdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);
 
-               if (sdata->vif.type != IEEE80211_IF_TYPE_VLAN &&
-                   sdata->vif.type != IEEE80211_IF_TYPE_AP)
+               if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
+                   sdata->vif.type != NL80211_IFTYPE_AP)
                        return -EINVAL;
        } else
                sdata = IEEE80211_DEV_TO_SUB_IF(dev);
@@ -736,19 +715,27 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
 
        sta_apply_parameters(local, sta, params);
 
-       rate_control_rate_init(sta, local);
+       rate_control_rate_init(sta);
+
+       layer2_update = sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
+               sdata->vif.type == NL80211_IFTYPE_AP;
 
        rcu_read_lock();
 
        err = sta_info_insert(sta);
        if (err) {
                /* STA has been freed */
+               if (err == -EEXIST && layer2_update) {
+                       /* Need to update layer 2 devices on reassociation */
+                       sta = sta_info_get(local, mac);
+                       if (sta)
+                               ieee80211_send_layer2_update(sta);
+               }
                rcu_read_unlock();
                return err;
        }
 
-       if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN ||
-           sdata->vif.type == IEEE80211_IF_TYPE_AP)
+       if (layer2_update)
                ieee80211_send_layer2_update(sta);
 
        rcu_read_unlock();
@@ -763,9 +750,6 @@ static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev,
        struct ieee80211_sub_if_data *sdata;
        struct sta_info *sta;
 
-       if (dev == local->mdev)
-               return -EOPNOTSUPP;
-
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
        if (mac) {
@@ -797,9 +781,6 @@ static int ieee80211_change_station(struct wiphy *wiphy,
        struct sta_info *sta;
        struct ieee80211_sub_if_data *vlansdata;
 
-       if (dev == local->mdev || params->vlan == local->mdev)
-               return -EOPNOTSUPP;
-
        rcu_read_lock();
 
        /* XXX: get sta belonging to dev */
@@ -812,8 +793,8 @@ static int ieee80211_change_station(struct wiphy *wiphy,
        if (params->vlan && params->vlan != sta->sdata->dev) {
                vlansdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);
 
-               if (vlansdata->vif.type != IEEE80211_IF_TYPE_VLAN &&
-                   vlansdata->vif.type != IEEE80211_IF_TYPE_AP) {
+               if (vlansdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
+                   vlansdata->vif.type != NL80211_IFTYPE_AP) {
                        rcu_read_unlock();
                        return -EINVAL;
                }
@@ -839,15 +820,12 @@ static int ieee80211_add_mpath(struct wiphy *wiphy, struct net_device *dev,
        struct sta_info *sta;
        int err;
 
-       if (dev == local->mdev)
-               return -EOPNOTSUPP;
-
        if (!netif_running(dev))
                return -ENETDOWN;
 
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-       if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT)
+       if (sdata->vif.type != NL80211_IFTYPE_MESH_POINT)
                return -ENOTSUPP;
 
        rcu_read_lock();
@@ -895,15 +873,12 @@ static int ieee80211_change_mpath(struct wiphy *wiphy,
        struct mesh_path *mpath;
        struct sta_info *sta;
 
-       if (dev == local->mdev)
-               return -EOPNOTSUPP;
-
        if (!netif_running(dev))
                return -ENETDOWN;
 
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-       if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT)
+       if (sdata->vif.type != NL80211_IFTYPE_MESH_POINT)
                return -ENOTSUPP;
 
        rcu_read_lock();
@@ -930,7 +905,7 @@ static void mpath_set_pinfo(struct mesh_path *mpath, u8 *next_hop,
                            struct mpath_info *pinfo)
 {
        if (mpath->next_hop)
-               memcpy(next_hop, mpath->next_hop->addr, ETH_ALEN);
+               memcpy(next_hop, mpath->next_hop->sta.addr, ETH_ALEN);
        else
                memset(next_hop, 0, ETH_ALEN);
 
@@ -969,16 +944,12 @@ static int ieee80211_get_mpath(struct wiphy *wiphy, struct net_device *dev,
                               u8 *dst, u8 *next_hop, struct mpath_info *pinfo)
 
 {
-       struct ieee80211_local *local = wiphy_priv(wiphy);
        struct ieee80211_sub_if_data *sdata;
        struct mesh_path *mpath;
 
-       if (dev == local->mdev)
-               return -EOPNOTSUPP;
-
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-       if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT)
+       if (sdata->vif.type != NL80211_IFTYPE_MESH_POINT)
                return -ENOTSUPP;
 
        rcu_read_lock();
@@ -997,16 +968,12 @@ static int ieee80211_dump_mpath(struct wiphy *wiphy, struct net_device *dev,
                                 int idx, u8 *dst, u8 *next_hop,
                                 struct mpath_info *pinfo)
 {
-       struct ieee80211_local *local = wiphy_priv(wiphy);
        struct ieee80211_sub_if_data *sdata;
        struct mesh_path *mpath;
 
-       if (dev == local->mdev)
-               return -EOPNOTSUPP;
-
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-       if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT)
+       if (sdata->vif.type != NL80211_IFTYPE_MESH_POINT)
                return -ENOTSUPP;
 
        rcu_read_lock();
@@ -1020,44 +987,160 @@ static int ieee80211_dump_mpath(struct wiphy *wiphy, struct net_device *dev,
        rcu_read_unlock();
        return 0;
 }
+
+static int ieee80211_get_mesh_params(struct wiphy *wiphy,
+                               struct net_device *dev,
+                               struct mesh_config *conf)
+{
+       struct ieee80211_sub_if_data *sdata;
+       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+       if (sdata->vif.type != NL80211_IFTYPE_MESH_POINT)
+               return -ENOTSUPP;
+       memcpy(conf, &(sdata->u.mesh.mshcfg), sizeof(struct mesh_config));
+       return 0;
+}
+
+static inline bool _chg_mesh_attr(enum nl80211_meshconf_params parm, u32 mask)
+{
+       return (mask >> (parm-1)) & 0x1;
+}
+
+static int ieee80211_set_mesh_params(struct wiphy *wiphy,
+                               struct net_device *dev,
+                               const struct mesh_config *nconf, u32 mask)
+{
+       struct mesh_config *conf;
+       struct ieee80211_sub_if_data *sdata;
+       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+       if (sdata->vif.type != NL80211_IFTYPE_MESH_POINT)
+               return -ENOTSUPP;
+
+       /* Set the config options which we are interested in setting */
+       conf = &(sdata->u.mesh.mshcfg);
+       if (_chg_mesh_attr(NL80211_MESHCONF_RETRY_TIMEOUT, mask))
+               conf->dot11MeshRetryTimeout = nconf->dot11MeshRetryTimeout;
+       if (_chg_mesh_attr(NL80211_MESHCONF_CONFIRM_TIMEOUT, mask))
+               conf->dot11MeshConfirmTimeout = nconf->dot11MeshConfirmTimeout;
+       if (_chg_mesh_attr(NL80211_MESHCONF_HOLDING_TIMEOUT, mask))
+               conf->dot11MeshHoldingTimeout = nconf->dot11MeshHoldingTimeout;
+       if (_chg_mesh_attr(NL80211_MESHCONF_MAX_PEER_LINKS, mask))
+               conf->dot11MeshMaxPeerLinks = nconf->dot11MeshMaxPeerLinks;
+       if (_chg_mesh_attr(NL80211_MESHCONF_MAX_RETRIES, mask))
+               conf->dot11MeshMaxRetries = nconf->dot11MeshMaxRetries;
+       if (_chg_mesh_attr(NL80211_MESHCONF_TTL, mask))
+               conf->dot11MeshTTL = nconf->dot11MeshTTL;
+       if (_chg_mesh_attr(NL80211_MESHCONF_AUTO_OPEN_PLINKS, mask))
+               conf->auto_open_plinks = nconf->auto_open_plinks;
+       if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES, mask))
+               conf->dot11MeshHWMPmaxPREQretries =
+                       nconf->dot11MeshHWMPmaxPREQretries;
+       if (_chg_mesh_attr(NL80211_MESHCONF_PATH_REFRESH_TIME, mask))
+               conf->path_refresh_time = nconf->path_refresh_time;
+       if (_chg_mesh_attr(NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT, mask))
+               conf->min_discovery_timeout = nconf->min_discovery_timeout;
+       if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT, mask))
+               conf->dot11MeshHWMPactivePathTimeout =
+                       nconf->dot11MeshHWMPactivePathTimeout;
+       if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL, mask))
+               conf->dot11MeshHWMPpreqMinInterval =
+                       nconf->dot11MeshHWMPpreqMinInterval;
+       if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
+                          mask))
+               conf->dot11MeshHWMPnetDiameterTraversalTime =
+                       nconf->dot11MeshHWMPnetDiameterTraversalTime;
+       return 0;
+}
+
 #endif
 
 static int ieee80211_change_bss(struct wiphy *wiphy,
                                struct net_device *dev,
                                struct bss_parameters *params)
 {
-       struct ieee80211_local *local = wiphy_priv(wiphy);
        struct ieee80211_sub_if_data *sdata;
        u32 changed = 0;
 
-       if (dev == local->mdev)
-               return -EOPNOTSUPP;
-
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-       if (sdata->vif.type != IEEE80211_IF_TYPE_AP)
+       if (sdata->vif.type != NL80211_IFTYPE_AP)
                return -EINVAL;
 
        if (params->use_cts_prot >= 0) {
-               sdata->bss_conf.use_cts_prot = params->use_cts_prot;
+               sdata->vif.bss_conf.use_cts_prot = params->use_cts_prot;
                changed |= BSS_CHANGED_ERP_CTS_PROT;
        }
        if (params->use_short_preamble >= 0) {
-               sdata->bss_conf.use_short_preamble =
+               sdata->vif.bss_conf.use_short_preamble =
                        params->use_short_preamble;
                changed |= BSS_CHANGED_ERP_PREAMBLE;
        }
        if (params->use_short_slot_time >= 0) {
-               sdata->bss_conf.use_short_slot =
+               sdata->vif.bss_conf.use_short_slot =
                        params->use_short_slot_time;
                changed |= BSS_CHANGED_ERP_SLOT;
        }
 
+       if (params->basic_rates) {
+               int i, j;
+               u32 rates = 0;
+               struct ieee80211_local *local = wiphy_priv(wiphy);
+               struct ieee80211_supported_band *sband =
+                       wiphy->bands[local->oper_channel->band];
+
+               for (i = 0; i < params->basic_rates_len; i++) {
+                       int rate = (params->basic_rates[i] & 0x7f) * 5;
+                       for (j = 0; j < sband->n_bitrates; j++) {
+                               if (sband->bitrates[j].bitrate == rate)
+                                       rates |= BIT(j);
+                       }
+               }
+               sdata->vif.bss_conf.basic_rates = rates;
+               changed |= BSS_CHANGED_BASIC_RATES;
+       }
+
        ieee80211_bss_info_change_notify(sdata, changed);
 
        return 0;
 }
 
+static int ieee80211_set_txq_params(struct wiphy *wiphy,
+                                   struct ieee80211_txq_params *params)
+{
+       struct ieee80211_local *local = wiphy_priv(wiphy);
+       struct ieee80211_tx_queue_params p;
+
+       if (!local->ops->conf_tx)
+               return -EOPNOTSUPP;
+
+       memset(&p, 0, sizeof(p));
+       p.aifs = params->aifs;
+       p.cw_max = params->cwmax;
+       p.cw_min = params->cwmin;
+       p.txop = params->txop;
+       if (local->ops->conf_tx(local_to_hw(local), params->queue, &p)) {
+               printk(KERN_DEBUG "%s: failed to set TX queue "
+                      "parameters for queue %d\n", local->mdev->name,
+                      params->queue);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int ieee80211_set_channel(struct wiphy *wiphy,
+                                struct ieee80211_channel *chan,
+                                enum nl80211_channel_type channel_type)
+{
+       struct ieee80211_local *local = wiphy_priv(wiphy);
+
+       local->oper_channel = chan;
+       local->oper_channel_type = channel_type;
+
+       return ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
+}
+
 struct cfg80211_ops mac80211_config_ops = {
        .add_virtual_intf = ieee80211_add_iface,
        .del_virtual_intf = ieee80211_del_iface,
@@ -1080,6 +1163,10 @@ struct cfg80211_ops mac80211_config_ops = {
        .change_mpath = ieee80211_change_mpath,
        .get_mpath = ieee80211_get_mpath,
        .dump_mpath = ieee80211_dump_mpath,
+       .set_mesh_params = ieee80211_set_mesh_params,
+       .get_mesh_params = ieee80211_get_mesh_params,
 #endif
        .change_bss = ieee80211_change_bss,
+       .set_txq_params = ieee80211_set_txq_params,
+       .set_channel = ieee80211_set_channel,
 };