cfg80211/mac80211: Update set_tx_power to use mBm instead of dBm units
[pandora-kernel.git] / net / mac80211 / cfg.c
index edc872e..f4efbfa 100644 (file)
@@ -97,9 +97,6 @@ static int ieee80211_change_iface(struct wiphy *wiphy,
                                            params->mesh_id_len,
                                            params->mesh_id);
 
-       if (sdata->vif.type != NL80211_IFTYPE_MONITOR || !flags)
-               return 0;
-
        if (type == NL80211_IFTYPE_AP_VLAN &&
            params && params->use_4addr == 0)
                rcu_assign_pointer(sdata->u.vlan.sta, NULL);
@@ -107,7 +104,9 @@ static int ieee80211_change_iface(struct wiphy *wiphy,
                 params && params->use_4addr >= 0)
                sdata->u.mgd.use_4addr = params->use_4addr;
 
-       sdata->u.mntr_flags = *flags;
+       if (sdata->vif.type == NL80211_IFTYPE_MONITOR && flags)
+               sdata->u.mntr_flags = *flags;
+
        return 0;
 }
 
@@ -121,6 +120,9 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
        struct ieee80211_key *key;
        int err;
 
+       if (!netif_running(dev))
+               return -ENETDOWN;
+
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
        switch (params->cipher) {
@@ -146,7 +148,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
        if (!key)
                return -ENOMEM;
 
-       rcu_read_lock();
+       mutex_lock(&sdata->local->sta_mtx);
 
        if (mac_addr) {
                sta = sta_info_get_bss(sdata, mac_addr);
@@ -161,7 +163,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
 
        err = 0;
  out_unlock:
-       rcu_read_unlock();
+       mutex_unlock(&sdata->local->sta_mtx);
 
        return err;
 }
@@ -175,7 +177,7 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
 
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-       rcu_read_lock();
+       mutex_lock(&sdata->local->sta_mtx);
 
        if (mac_addr) {
                ret = -ENOENT;
@@ -203,7 +205,7 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
 
        ret = 0;
  out_unlock:
-       rcu_read_unlock();
+       mutex_unlock(&sdata->local->sta_mtx);
 
        return ret;
 }
@@ -306,15 +308,10 @@ static int ieee80211_config_default_key(struct wiphy *wiphy,
                                        struct net_device *dev,
                                        u8 key_idx)
 {
-       struct ieee80211_sub_if_data *sdata;
-
-       rcu_read_lock();
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        ieee80211_set_default_key(sdata, key_idx);
 
-       rcu_read_unlock();
-
        return 0;
 }
 
@@ -411,6 +408,17 @@ static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev,
        return ret;
 }
 
+static int ieee80211_dump_survey(struct wiphy *wiphy, struct net_device *dev,
+                                int idx, struct survey_info *survey)
+{
+       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+
+       if (!local->ops->get_survey)
+               return -EOPNOTSUPP;
+
+       return drv_get_survey(local, idx, survey);
+}
+
 static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev,
                                 u8 *mac, struct station_info *sinfo)
 {
@@ -1104,6 +1112,13 @@ static int ieee80211_change_bss(struct wiphy *wiphy,
                changed |= BSS_CHANGED_BASIC_RATES;
        }
 
+       if (params->ap_isolate >= 0) {
+               if (params->ap_isolate)
+                       sdata->flags |= IEEE80211_SDATA_DONT_BRIDGE_PACKETS;
+               else
+                       sdata->flags &= ~IEEE80211_SDATA_DONT_BRIDGE_PACKETS;
+       }
+
        ieee80211_bss_info_change_notify(sdata, changed);
 
        return 0;
@@ -1137,19 +1152,47 @@ static int ieee80211_set_txq_params(struct wiphy *wiphy,
                return -EINVAL;
        }
 
+       /* enable WMM or activate new settings */
+       local->hw.conf.flags |= IEEE80211_CONF_QOS;
+       drv_config(local, IEEE80211_CONF_CHANGE_QOS);
+
        return 0;
 }
 
 static int ieee80211_set_channel(struct wiphy *wiphy,
+                                struct net_device *netdev,
                                 struct ieee80211_channel *chan,
                                 enum nl80211_channel_type channel_type)
 {
        struct ieee80211_local *local = wiphy_priv(wiphy);
+       struct ieee80211_sub_if_data *sdata = NULL;
+
+       if (netdev)
+               sdata = IEEE80211_DEV_TO_SUB_IF(netdev);
+
+       switch (ieee80211_get_channel_mode(local, NULL)) {
+       case CHAN_MODE_HOPPING:
+               return -EBUSY;
+       case CHAN_MODE_FIXED:
+               if (local->oper_channel != chan)
+                       return -EBUSY;
+               if (!sdata && local->_oper_channel_type == channel_type)
+                       return 0;
+               break;
+       case CHAN_MODE_UNDEFINED:
+               break;
+       }
 
        local->oper_channel = chan;
-       local->oper_channel_type = channel_type;
 
-       return ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
+       if (!ieee80211_set_channel_type(local, sdata, channel_type))
+               return -EBUSY;
+
+       ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
+       if (sdata && sdata->vif.type != NL80211_IFTYPE_MONITOR)
+               ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_HT);
+
+       return 0;
 }
 
 #ifdef CONFIG_PM
@@ -1193,6 +1236,20 @@ static int ieee80211_auth(struct wiphy *wiphy, struct net_device *dev,
 static int ieee80211_assoc(struct wiphy *wiphy, struct net_device *dev,
                           struct cfg80211_assoc_request *req)
 {
+       struct ieee80211_local *local = wiphy_priv(wiphy);
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+       switch (ieee80211_get_channel_mode(local, sdata)) {
+       case CHAN_MODE_HOPPING:
+               return -EBUSY;
+       case CHAN_MODE_FIXED:
+               if (local->oper_channel == req->bss->channel)
+                       break;
+               return -EBUSY;
+       case CHAN_MODE_UNDEFINED:
+               break;
+       }
+
        return ieee80211_mgd_assoc(IEEE80211_DEV_TO_SUB_IF(dev), req);
 }
 
@@ -1215,8 +1272,22 @@ static int ieee80211_disassoc(struct wiphy *wiphy, struct net_device *dev,
 static int ieee80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
                               struct cfg80211_ibss_params *params)
 {
+       struct ieee80211_local *local = wiphy_priv(wiphy);
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
+       switch (ieee80211_get_channel_mode(local, sdata)) {
+       case CHAN_MODE_HOPPING:
+               return -EBUSY;
+       case CHAN_MODE_FIXED:
+               if (!params->channel_fixed)
+                       return -EBUSY;
+               if (local->oper_channel == params->channel)
+                       break;
+               return -EBUSY;
+       case CHAN_MODE_UNDEFINED:
+               break;
+       }
+
        return ieee80211_ibss_join(sdata, params);
 }
 
@@ -1258,28 +1329,28 @@ static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
 }
 
 static int ieee80211_set_tx_power(struct wiphy *wiphy,
-                                 enum tx_power_setting type, int dbm)
+                                 enum nl80211_tx_power_setting type, int mbm)
 {
        struct ieee80211_local *local = wiphy_priv(wiphy);
        struct ieee80211_channel *chan = local->hw.conf.channel;
        u32 changes = 0;
 
        switch (type) {
-       case TX_POWER_AUTOMATIC:
+       case NL80211_TX_POWER_AUTOMATIC:
                local->user_power_level = -1;
                break;
-       case TX_POWER_LIMITED:
-               if (dbm < 0)
-                       return -EINVAL;
-               local->user_power_level = dbm;
+       case NL80211_TX_POWER_LIMITED:
+               if (mbm < 0 || (mbm % 100))
+                       return -EOPNOTSUPP;
+               local->user_power_level = MBM_TO_DBM(mbm);
                break;
-       case TX_POWER_FIXED:
-               if (dbm < 0)
-                       return -EINVAL;
+       case NL80211_TX_POWER_FIXED:
+               if (mbm < 0 || (mbm % 100))
+                       return -EOPNOTSUPP;
                /* TODO: move to cfg80211 when it knows the channel */
-               if (dbm > chan->max_power)
+               if (MBM_TO_DBM(mbm) > chan->max_power)
                        return -EINVAL;
-               local->user_power_level = dbm;
+               local->user_power_level = MBM_TO_DBM(mbm);
                break;
        }
 
@@ -1345,7 +1416,7 @@ int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata,
         * association, there's no need to send an action frame.
         */
        if (!sdata->u.mgd.associated ||
-           sdata->local->oper_channel_type == NL80211_CHAN_NO_HT) {
+           sdata->vif.bss_conf.channel_type == NL80211_CHAN_NO_HT) {
                mutex_lock(&sdata->local->iflist_mtx);
                ieee80211_recalc_smps(sdata->local, sdata);
                mutex_unlock(&sdata->local->iflist_mtx);
@@ -1375,7 +1446,6 @@ static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct ieee80211_conf *conf = &local->hw.conf;
 
        if (sdata->vif.type != NL80211_IFTYPE_STATION)
                return -EOPNOTSUPP;
@@ -1384,11 +1454,11 @@ static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
                return -EOPNOTSUPP;
 
        if (enabled == sdata->u.mgd.powersave &&
-           timeout == conf->dynamic_ps_timeout)
+           timeout == local->dynamic_ps_forced_timeout)
                return 0;
 
        sdata->u.mgd.powersave = enabled;
-       conf->dynamic_ps_timeout = timeout;
+       local->dynamic_ps_forced_timeout = timeout;
 
        /* no change, but if automatic follow powersave */
        mutex_lock(&sdata->u.mgd.mtx);
@@ -1403,6 +1473,35 @@ static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
        return 0;
 }
 
+static int ieee80211_set_cqm_rssi_config(struct wiphy *wiphy,
+                                        struct net_device *dev,
+                                        s32 rssi_thold, u32 rssi_hyst)
+{
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+       struct ieee80211_vif *vif = &sdata->vif;
+       struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
+
+       if (rssi_thold == bss_conf->cqm_rssi_thold &&
+           rssi_hyst == bss_conf->cqm_rssi_hyst)
+               return 0;
+
+       bss_conf->cqm_rssi_thold = rssi_thold;
+       bss_conf->cqm_rssi_hyst = rssi_hyst;
+
+       if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_CQM_RSSI)) {
+               if (sdata->vif.type != NL80211_IFTYPE_STATION)
+                       return -EOPNOTSUPP;
+               return 0;
+       }
+
+       /* tell the driver upon association, unless already associated */
+       if (sdata->u.mgd.associated)
+               ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_CQM);
+
+       return 0;
+}
+
 static int ieee80211_set_bitrate_mask(struct wiphy *wiphy,
                                      struct net_device *dev,
                                      const u8 *addr,
@@ -1452,10 +1551,58 @@ static int ieee80211_cancel_remain_on_channel(struct wiphy *wiphy,
 static int ieee80211_action(struct wiphy *wiphy, struct net_device *dev,
                            struct ieee80211_channel *chan,
                            enum nl80211_channel_type channel_type,
+                           bool channel_type_valid,
                            const u8 *buf, size_t len, u64 *cookie)
 {
-       return ieee80211_mgd_action(IEEE80211_DEV_TO_SUB_IF(dev), chan,
-                                   channel_type, buf, len, cookie);
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct ieee80211_local *local = sdata->local;
+       struct sk_buff *skb;
+       struct sta_info *sta;
+       const struct ieee80211_mgmt *mgmt = (void *)buf;
+       u32 flags = IEEE80211_TX_INTFL_NL80211_FRAME_TX |
+                   IEEE80211_TX_CTL_REQ_TX_STATUS;
+
+       /* Check that we are on the requested channel for transmission */
+       if (chan != local->tmp_channel &&
+           chan != local->oper_channel)
+               return -EBUSY;
+       if (channel_type_valid &&
+           (channel_type != local->tmp_channel_type &&
+            channel_type != local->_oper_channel_type))
+               return -EBUSY;
+
+       switch (sdata->vif.type) {
+       case NL80211_IFTYPE_ADHOC:
+               if (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC)
+                       break;
+               rcu_read_lock();
+               sta = sta_info_get(sdata, mgmt->da);
+               rcu_read_unlock();
+               if (!sta)
+                       return -ENOLINK;
+               break;
+       case NL80211_IFTYPE_STATION:
+               if (!(sdata->u.mgd.flags & IEEE80211_STA_MFP_ENABLED))
+                       flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
+               break;
+       default:
+               return -EOPNOTSUPP;
+       }
+
+       skb = dev_alloc_skb(local->hw.extra_tx_headroom + len);
+       if (!skb)
+               return -ENOMEM;
+       skb_reserve(skb, local->hw.extra_tx_headroom);
+
+       memcpy(skb_put(skb, len), buf, len);
+
+       IEEE80211_SKB_CB(skb)->flags = flags;
+
+       skb->dev = sdata->dev;
+       ieee80211_tx_skb(sdata, skb);
+
+       *cookie = (unsigned long) skb;
+       return 0;
 }
 
 struct cfg80211_ops mac80211_config_ops = {
@@ -1475,6 +1622,7 @@ struct cfg80211_ops mac80211_config_ops = {
        .change_station = ieee80211_change_station,
        .get_station = ieee80211_get_station,
        .dump_station = ieee80211_dump_station,
+       .dump_survey = ieee80211_dump_survey,
 #ifdef CONFIG_MAC80211_MESH
        .add_mpath = ieee80211_add_mpath,
        .del_mpath = ieee80211_del_mpath,
@@ -1507,4 +1655,5 @@ struct cfg80211_ops mac80211_config_ops = {
        .remain_on_channel = ieee80211_remain_on_channel,
        .cancel_remain_on_channel = ieee80211_cancel_remain_on_channel,
        .action = ieee80211_action,
+       .set_cqm_rssi_config = ieee80211_set_cqm_rssi_config,
 };