summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2017-09-13 10:07:22 -0400
committerJohannes Berg <johannes.berg@intel.com>2017-10-11 07:04:15 -0400
commit1ea4ff3e9f0b8d53e680a2bb9e8e644bf03aeb4d (patch)
tree798b7b73a9bf61aaf2c1ef9c5265d5581f01ef2b
parent007f6c5e6eb45c81ee89368a5f226572ae638831 (diff)
cfg80211: support reloading regulatory database
If the regulatory database is loaded, and then updated, it may be necessary to reload it. Add an nl80211 command to do this. Note that this just reloads the database, it doesn't re-apply the rules from it immediately. Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r--include/uapi/linux/nl80211.h4
-rw-r--r--net/wireless/nl80211.c11
-rw-r--r--net/wireless/reg.c80
-rw-r--r--net/wireless/reg.h6
4 files changed, 81 insertions, 20 deletions
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 95832ce03a44..f882fe1f9709 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -990,6 +990,8 @@
990 * &NL80211_CMD_CONNECT or &NL80211_CMD_ROAM. If the 4 way handshake failed 990 * &NL80211_CMD_CONNECT or &NL80211_CMD_ROAM. If the 4 way handshake failed
991 * &NL80211_CMD_DISCONNECT should be indicated instead. 991 * &NL80211_CMD_DISCONNECT should be indicated instead.
992 * 992 *
993 * @NL80211_CMD_RELOAD_REGDB: Request that the regdb firmware file is reloaded.
994 *
993 * @NL80211_CMD_MAX: highest used command number 995 * @NL80211_CMD_MAX: highest used command number
994 * @__NL80211_CMD_AFTER_LAST: internal use 996 * @__NL80211_CMD_AFTER_LAST: internal use
995 */ 997 */
@@ -1194,6 +1196,8 @@ enum nl80211_commands {
1194 1196
1195 NL80211_CMD_PORT_AUTHORIZED, 1197 NL80211_CMD_PORT_AUTHORIZED,
1196 1198
1199 NL80211_CMD_RELOAD_REGDB,
1200
1197 /* add new commands above here */ 1201 /* add new commands above here */
1198 1202
1199 /* used to define NL80211_CMD_MAX below */ 1203 /* used to define NL80211_CMD_MAX below */
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 5129342151e6..67a03f2885a4 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -5678,6 +5678,11 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
5678 } 5678 }
5679} 5679}
5680 5680
5681static int nl80211_reload_regdb(struct sk_buff *skb, struct genl_info *info)
5682{
5683 return reg_reload_regdb();
5684}
5685
5681static int nl80211_get_mesh_config(struct sk_buff *skb, 5686static int nl80211_get_mesh_config(struct sk_buff *skb,
5682 struct genl_info *info) 5687 struct genl_info *info)
5683{ 5688{
@@ -12709,6 +12714,12 @@ static const struct genl_ops nl80211_ops[] = {
12709 .flags = GENL_ADMIN_PERM, 12714 .flags = GENL_ADMIN_PERM,
12710 }, 12715 },
12711 { 12716 {
12717 .cmd = NL80211_CMD_RELOAD_REGDB,
12718 .doit = nl80211_reload_regdb,
12719 .policy = nl80211_policy,
12720 .flags = GENL_ADMIN_PERM,
12721 },
12722 {
12712 .cmd = NL80211_CMD_GET_MESH_CONFIG, 12723 .cmd = NL80211_CMD_GET_MESH_CONFIG,
12713 .doit = nl80211_get_mesh_config, 12724 .doit = nl80211_get_mesh_config,
12714 .policy = nl80211_policy, 12725 .policy = nl80211_policy,
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index e9aeb05aaf3e..180addda52af 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -781,6 +781,8 @@ static int query_regdb(const char *alpha2)
781 const struct fwdb_header *hdr = regdb; 781 const struct fwdb_header *hdr = regdb;
782 const struct fwdb_country *country; 782 const struct fwdb_country *country;
783 783
784 ASSERT_RTNL();
785
784 if (IS_ERR(regdb)) 786 if (IS_ERR(regdb))
785 return PTR_ERR(regdb); 787 return PTR_ERR(regdb);
786 788
@@ -796,41 +798,47 @@ static int query_regdb(const char *alpha2)
796 798
797static void regdb_fw_cb(const struct firmware *fw, void *context) 799static void regdb_fw_cb(const struct firmware *fw, void *context)
798{ 800{
801 int set_error = 0;
802 bool restore = true;
799 void *db; 803 void *db;
800 804
801 if (!fw) { 805 if (!fw) {
802 pr_info("failed to load regulatory.db\n"); 806 pr_info("failed to load regulatory.db\n");
803 regdb = ERR_PTR(-ENODATA); 807 set_error = -ENODATA;
804 goto restore; 808 } else if (!valid_regdb(fw->data, fw->size)) {
805 }
806
807 if (!valid_regdb(fw->data, fw->size)) {
808 pr_info("loaded regulatory.db is malformed\n"); 809 pr_info("loaded regulatory.db is malformed\n");
809 release_firmware(fw); 810 set_error = -EINVAL;
810 regdb = ERR_PTR(-EINVAL);
811 goto restore;
812 } 811 }
813 812
814 db = kmemdup(fw->data, fw->size, GFP_KERNEL); 813 rtnl_lock();
815 release_firmware(fw); 814 if (WARN_ON(regdb && !IS_ERR(regdb))) {
815 /* just restore and free new db */
816 } else if (set_error) {
817 regdb = ERR_PTR(set_error);
818 } else if (fw) {
819 db = kmemdup(fw->data, fw->size, GFP_KERNEL);
820 if (db) {
821 regdb = db;
822 restore = context && query_regdb(context);
823 } else {
824 restore = true;
825 }
826 }
816 827
817 if (!db) 828 if (restore)
818 goto restore; 829 restore_regulatory_settings(true);
819 regdb = db;
820 830
821 if (query_regdb(context))
822 goto restore;
823 goto free;
824 restore:
825 rtnl_lock();
826 restore_regulatory_settings(true);
827 rtnl_unlock(); 831 rtnl_unlock();
828 free: 832
829 kfree(context); 833 kfree(context);
834
835 release_firmware(fw);
830} 836}
831 837
832static int query_regdb_file(const char *alpha2) 838static int query_regdb_file(const char *alpha2)
833{ 839{
840 ASSERT_RTNL();
841
834 if (regdb) 842 if (regdb)
835 return query_regdb(alpha2); 843 return query_regdb(alpha2);
836 844
@@ -843,6 +851,38 @@ static int query_regdb_file(const char *alpha2)
843 (void *)alpha2, regdb_fw_cb); 851 (void *)alpha2, regdb_fw_cb);
844} 852}
845 853
854int reg_reload_regdb(void)
855{
856 const struct firmware *fw;
857 void *db;
858 int err;
859
860 err = request_firmware(&fw, "regulatory.db", &reg_pdev->dev);
861 if (err)
862 return err;
863
864 if (!valid_regdb(fw->data, fw->size)) {
865 err = -ENODATA;
866 goto out;
867 }
868
869 db = kmemdup(fw->data, fw->size, GFP_KERNEL);
870 if (!db) {
871 err = -ENOMEM;
872 goto out;
873 }
874
875 rtnl_lock();
876 if (!IS_ERR_OR_NULL(regdb))
877 kfree(regdb);
878 regdb = db;
879 rtnl_unlock();
880
881 out:
882 release_firmware(fw);
883 return err;
884}
885
846static bool reg_query_database(struct regulatory_request *request) 886static bool reg_query_database(struct regulatory_request *request)
847{ 887{
848 /* query internal regulatory database (if it exists) */ 888 /* query internal regulatory database (if it exists) */
diff --git a/net/wireless/reg.h b/net/wireless/reg.h
index ca7fedf2e7a1..9529c522611a 100644
--- a/net/wireless/reg.h
+++ b/net/wireless/reg.h
@@ -179,4 +179,10 @@ void regulatory_propagate_dfs_state(struct wiphy *wiphy,
179 * @wiphy2 - wiphy it's dfs_region to be checked against that of wiphy1 179 * @wiphy2 - wiphy it's dfs_region to be checked against that of wiphy1
180 */ 180 */
181bool reg_dfs_domain_same(struct wiphy *wiphy1, struct wiphy *wiphy2); 181bool reg_dfs_domain_same(struct wiphy *wiphy1, struct wiphy *wiphy2);
182
183/**
184 * reg_reload_regdb - reload the regulatory.db firmware file
185 */
186int reg_reload_regdb(void);
187
182#endif /* __NET_WIRELESS_REG_H */ 188#endif /* __NET_WIRELESS_REG_H */