| @@ -781,6 +781,8 @@ static int query_regdb(const char *alpha2) · 780 unmodified lines |
| 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 | |
| @@ -796,41 +798,47 @@ static int query_regdb(const char *alpha2) · 9 unmodified lines |
| 796 | 798 | |
| 797 | 799 | static void regdb_fw_cb(const struct firmware *fw, void *context) |
| 798 | 800 | { |
| 801 | + int set_error = 0; |
| 802 | + bool restore = true; |
| 799 | 803 | void *db; |
| 800 | 804 | |
| 801 | 805 | if (!fw) { |
| 802 | 806 | pr_info("failed to load regulatory.db\n"); |
| 803 | | − regdb = ERR_PTR(-ENODATA); |
| 804 | | − goto restore; |
| 805 | | − } |
| 806 | | − |
| 807 | | − if (!valid_regdb(fw->data, fw->size)) { |
| 807 | + set_error = -ENODATA; |
| 808 | + } else if (!valid_regdb(fw->data, fw->size)) { |
| 808 | 809 | pr_info("loaded regulatory.db is malformed\n"); |
| 809 | | − release_firmware(fw); |
| 810 | | − regdb = ERR_PTR(-EINVAL); |
| 811 | | − goto restore; |
| 810 | + set_error = -EINVAL; |
| 812 | 811 | } |
| 813 | 812 | |
| 814 | | − db = kmemdup(fw->data, fw->size, GFP_KERNEL); |
| 815 | | − release_firmware(fw); |
| 813 | + rtnl_lock(); |
| 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) |
| 818 | | − goto restore; |
| 819 | | − regdb = db; |
| 828 | + if (restore) |
| 829 | + restore_regulatory_settings(true); |
| 820 | 830 | |
| 821 | | − if (query_regdb(context)) |
| 822 | | − goto restore; |
| 823 | | − goto free; |
| 824 | | − restore: |
| 825 | | − rtnl_lock(); |
| 826 | | − restore_regulatory_settings(true); |
| 827 | 831 | rtnl_unlock(); |
| 828 | | − free: |
| 832 | + |
| 829 | 833 | kfree(context); |
| 834 | + |
| 835 | + release_firmware(fw); |
| 830 | 836 | } |
| 831 | 837 | |
| 832 | 838 | static int query_regdb_file(const char *alpha2) |
| 833 | 839 | { |
| 840 | + ASSERT_RTNL(); |
| 841 | + |
| 834 | 842 | if (regdb) |
| 835 | 843 | return query_regdb(alpha2); |
| 836 | 844 | |
| @@ -843,6 +851,38 @@ static int query_regdb_file(const char *alpha2) · 6 unmodified lines |
| 843 | 851 | (void *)alpha2, regdb_fw_cb); |
| 844 | 852 | } |
| 845 | 853 | |
| 854 | +int reg_reload_regdb(void) |
| 855 | +{ |
| 856 | + const struct firmware *fw; |
| 857 | + void *db; |
| 858 | + int err; |
| 859 | + |
| 860 | + err = request_firmware(&fw, "regulatory.db", ®_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 | + |
| 846 | 886 | static bool reg_query_database(struct regulatory_request *request) |
| 847 | 887 | { |
| 848 | 888 | /* query internal regulatory database (if it exists) */ |