]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - net/wireless/nl80211.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-2.6
[linux-2.6-omap-h63xx.git] / net / wireless / nl80211.c
index 88a530f707e653fab505ba53bcd52124b38d59b0..ab9d8f14e15103a4d762c08fdd132e1565c15df3 100644 (file)
@@ -7,7 +7,6 @@
 #include <linux/if.h>
 #include <linux/module.h>
 #include <linux/err.h>
-#include <linux/mutex.h>
 #include <linux/list.h>
 #include <linux/if_ether.h>
 #include <linux/ieee80211.h>
@@ -1906,6 +1905,19 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
        int r;
        char *data = NULL;
 
+       /*
+        * You should only get this when cfg80211 hasn't yet initialized
+        * completely when built-in to the kernel right between the time
+        * window between nl80211_init() and regulatory_init(), if that is
+        * even possible.
+        */
+       mutex_lock(&cfg80211_mutex);
+       if (unlikely(!cfg80211_regdomain)) {
+               mutex_unlock(&cfg80211_mutex);
+               return -EINPROGRESS;
+       }
+       mutex_unlock(&cfg80211_mutex);
+
        if (!info->attrs[NL80211_ATTR_REG_ALPHA2])
                return -EINVAL;
 
@@ -1916,14 +1928,9 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
        if (is_world_regdom(data))
                return -EINVAL;
 #endif
-       mutex_lock(&cfg80211_mutex);
-       r = __regulatory_hint(NULL, REGDOM_SET_BY_USER, data, 0, ENVIRON_ANY);
-       mutex_unlock(&cfg80211_mutex);
-       /* This means the regulatory domain was already set, however
-        * we don't want to confuse userspace with a "successful error"
-        * message so lets just treat it as a success */
-       if (r == -EALREADY)
-               r = 0;
+
+       r = regulatory_hint_user(data);
+
        return r;
 }
 
@@ -1943,6 +1950,11 @@ static int nl80211_get_mesh_params(struct sk_buff *skb,
        if (err)
                return err;
 
+       if (!drv->ops->get_mesh_params) {
+               err = -EOPNOTSUPP;
+               goto out;
+       }
+
        /* Get the mesh params */
        rtnl_lock();
        err = drv->ops->get_mesh_params(&drv->wiphy, dev, &cur_params);
@@ -2052,6 +2064,11 @@ static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info)
        if (err)
                return err;
 
+       if (!drv->ops->set_mesh_params) {
+               err = -EOPNOTSUPP;
+               goto out;
+       }
+
        /* This makes sure that there aren't more than 32 mesh config
         * parameters (otherwise our bitfield scheme would not work.) */
        BUILD_BUG_ON(NL80211_MESHCONF_ATTR_MAX > 32);
@@ -2096,6 +2113,7 @@ static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info)
        err = drv->ops->set_mesh_params(&drv->wiphy, dev, &cfg, mask);
        rtnl_unlock();
 
+ out:
        /* cleanup */
        cfg80211_put_dev(drv);
        dev_put(dev);
@@ -2732,6 +2750,9 @@ static struct genl_multicast_group nl80211_config_mcgrp = {
 static struct genl_multicast_group nl80211_scan_mcgrp = {
        .name = "scan",
 };
+static struct genl_multicast_group nl80211_regulatory_mcgrp = {
+       .name = "regulatory",
+};
 
 /* notification functions */
 
@@ -2811,6 +2832,61 @@ void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev,
        genlmsg_multicast(msg, 0, nl80211_scan_mcgrp.id, GFP_KERNEL);
 }
 
+/*
+ * This can happen on global regulatory changes or device specific settings
+ * based on custom world regulatory domains.
+ */
+void nl80211_send_reg_change_event(struct regulatory_request *request)
+{
+       struct sk_buff *msg;
+       void *hdr;
+
+       msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+       if (!msg)
+               return;
+
+       hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_REG_CHANGE);
+       if (!hdr) {
+               nlmsg_free(msg);
+               return;
+       }
+
+       /* Userspace can always count this one always being set */
+       NLA_PUT_U8(msg, NL80211_ATTR_REG_INITIATOR, request->initiator);
+
+       if (request->alpha2[0] == '0' && request->alpha2[1] == '0')
+               NLA_PUT_U8(msg, NL80211_ATTR_REG_TYPE,
+                          NL80211_REGDOM_TYPE_WORLD);
+       else if (request->alpha2[0] == '9' && request->alpha2[1] == '9')
+               NLA_PUT_U8(msg, NL80211_ATTR_REG_TYPE,
+                          NL80211_REGDOM_TYPE_CUSTOM_WORLD);
+       else if ((request->alpha2[0] == '9' && request->alpha2[1] == '8') ||
+                request->intersect)
+               NLA_PUT_U8(msg, NL80211_ATTR_REG_TYPE,
+                          NL80211_REGDOM_TYPE_INTERSECTION);
+       else {
+               NLA_PUT_U8(msg, NL80211_ATTR_REG_TYPE,
+                          NL80211_REGDOM_TYPE_COUNTRY);
+               NLA_PUT_STRING(msg, NL80211_ATTR_REG_ALPHA2, request->alpha2);
+       }
+
+       if (wiphy_idx_valid(request->wiphy_idx))
+               NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, request->wiphy_idx);
+
+       if (genlmsg_end(msg, hdr) < 0) {
+               nlmsg_free(msg);
+               return;
+       }
+
+       genlmsg_multicast(msg, 0, nl80211_regulatory_mcgrp.id, GFP_KERNEL);
+
+       return;
+
+nla_put_failure:
+       genlmsg_cancel(msg, hdr);
+       nlmsg_free(msg);
+}
+
 /* initialisation/exit functions */
 
 int nl80211_init(void)
@@ -2835,6 +2911,10 @@ int nl80211_init(void)
        if (err)
                goto err_out;
 
+       err = genl_register_mc_group(&nl80211_fam, &nl80211_regulatory_mcgrp);
+       if (err)
+               goto err_out;
+
        return 0;
  err_out:
        genl_unregister_family(&nl80211_fam);