Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+82 -21
+4
include/uapi/linux/nl80211.h
··· 990 990 * &NL80211_CMD_CONNECT or &NL80211_CMD_ROAM. If the 4 way handshake failed 991 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 995 * @NL80211_CMD_MAX: highest used command number 994 996 * @__NL80211_CMD_AFTER_LAST: internal use 995 997 */ ··· 1195 1193 NL80211_CMD_DEL_PMK, 1196 1194 1197 1195 NL80211_CMD_PORT_AUTHORIZED, 1196 + 1197 + NL80211_CMD_RELOAD_REGDB, 1198 1198 1199 1199 /* add new commands above here */ 1200 1200
+11
net/wireless/nl80211.c
··· 5678 5678 } 5679 5679 } 5680 5680 5681 + static int nl80211_reload_regdb(struct sk_buff *skb, struct genl_info *info) 5682 + { 5683 + return reg_reload_regdb(); 5684 + } 5685 + 5681 5686 static int nl80211_get_mesh_config(struct sk_buff *skb, 5682 5687 struct genl_info *info) 5683 5688 { ··· 12710 12705 { 12711 12706 .cmd = NL80211_CMD_REQ_SET_REG, 12712 12707 .doit = nl80211_req_set_reg, 12708 + .policy = nl80211_policy, 12709 + .flags = GENL_ADMIN_PERM, 12710 + }, 12711 + { 12712 + .cmd = NL80211_CMD_RELOAD_REGDB, 12713 + .doit = nl80211_reload_regdb, 12713 12714 .policy = nl80211_policy, 12714 12715 .flags = GENL_ADMIN_PERM, 12715 12716 },
+61 -21
net/wireless/reg.c
··· 781 781 const struct fwdb_header *hdr = regdb; 782 782 const struct fwdb_country *country; 783 783 784 + ASSERT_RTNL(); 785 + 784 786 if (IS_ERR(regdb)) 785 787 return PTR_ERR(regdb); 786 788 ··· 798 796 799 797 static void regdb_fw_cb(const struct firmware *fw, void *context) 800 798 { 799 + int set_error = 0; 800 + bool restore = true; 801 801 void *db; 802 802 803 803 if (!fw) { 804 804 pr_info("failed to load regulatory.db\n"); 805 - regdb = ERR_PTR(-ENODATA); 806 - goto restore; 807 - } 808 - 809 - if (!valid_regdb(fw->data, fw->size)) { 805 + set_error = -ENODATA; 806 + } else if (!valid_regdb(fw->data, fw->size)) { 810 807 pr_info("loaded regulatory.db is malformed\n"); 811 - release_firmware(fw); 812 - regdb = ERR_PTR(-EINVAL); 813 - goto restore; 808 + set_error = -EINVAL; 814 809 } 815 810 816 - db = kmemdup(fw->data, fw->size, GFP_KERNEL); 817 - release_firmware(fw); 818 - 819 - if (!db) 820 - goto restore; 821 - regdb = db; 822 - 823 - if (query_regdb(context)) 824 - goto restore; 825 - goto free; 826 - restore: 827 811 rtnl_lock(); 828 - restore_regulatory_settings(true); 812 + if (WARN_ON(regdb && !IS_ERR(regdb))) { 813 + /* just restore and free new db */ 814 + } else if (set_error) { 815 + regdb = ERR_PTR(set_error); 816 + } else if (fw) { 817 + db = kmemdup(fw->data, fw->size, GFP_KERNEL); 818 + if (db) { 819 + regdb = db; 820 + restore = context && query_regdb(context); 821 + } else { 822 + restore = true; 823 + } 824 + } 825 + 826 + if (restore) 827 + restore_regulatory_settings(true); 828 + 829 829 rtnl_unlock(); 830 - free: 830 + 831 831 kfree(context); 832 + 833 + release_firmware(fw); 832 834 } 833 835 834 836 static int query_regdb_file(const char *alpha2) 835 837 { 838 + ASSERT_RTNL(); 839 + 836 840 if (regdb) 837 841 return query_regdb(alpha2); 838 842 ··· 849 841 return request_firmware_nowait(THIS_MODULE, true, "regulatory.db", 850 842 &reg_pdev->dev, GFP_KERNEL, 851 843 (void *)alpha2, regdb_fw_cb); 844 + } 845 + 846 + int reg_reload_regdb(void) 847 + { 848 + const struct firmware *fw; 849 + void *db; 850 + int err; 851 + 852 + err = request_firmware(&fw, "regulatory.db", &reg_pdev->dev); 853 + if (err) 854 + return err; 855 + 856 + if (!valid_regdb(fw->data, fw->size)) { 857 + err = -ENODATA; 858 + goto out; 859 + } 860 + 861 + db = kmemdup(fw->data, fw->size, GFP_KERNEL); 862 + if (!db) { 863 + err = -ENOMEM; 864 + goto out; 865 + } 866 + 867 + rtnl_lock(); 868 + if (!IS_ERR_OR_NULL(regdb)) 869 + kfree(regdb); 870 + regdb = db; 871 + rtnl_unlock(); 872 + 873 + out: 874 + release_firmware(fw); 875 + return err; 852 876 } 853 877 854 878 static bool reg_query_database(struct regulatory_request *request)
+6
net/wireless/reg.h
··· 179 179 * @wiphy2 - wiphy it's dfs_region to be checked against that of wiphy1 180 180 */ 181 181 bool reg_dfs_domain_same(struct wiphy *wiphy1, struct wiphy *wiphy2); 182 + 183 + /** 184 + * reg_reload_regdb - reload the regulatory.db firmware file 185 + */ 186 + int reg_reload_regdb(void); 187 + 182 188 #endif /* __NET_WIRELESS_REG_H */