History

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.

Johannes Berg committed 9 years ago

Commit 1ea4ff31 parent 007f6c54 files · +81 −20Browse files

Unified · Split

4 files
  1. include/uapi/linux/nl80211.h +4 −0
  2. net/wireless/nl80211.c +11 −0
  3. net/wireless/reg.c +60 −20
  4. net/wireless/reg.h +6 −0
include/uapi/linux/nl80211.h+4−0
@@ -990,6 +990,8 @@ · 989 unmodified lines
990990 * &NL80211_CMD_CONNECT or &NL80211_CMD_ROAM. If the 4 way handshake failed
991991 * &NL80211_CMD_DISCONNECT should be indicated instead.
992992 *
993+ * @NL80211_CMD_RELOAD_REGDB: Request that the regdb firmware file is reloaded.
994+ *
993995 * @NL80211_CMD_MAX: highest used command number
994996 * @__NL80211_CMD_AFTER_LAST: internal use
995997 */
@@ -1194,6 +1196,8 @@ enum nl80211_commands { · 198 unmodified lines
11941196
11951197 NL80211_CMD_PORT_AUTHORIZED,
11961198
1199+ NL80211_CMD_RELOAD_REGDB,
1200+
11971201 /* add new commands above here */
11981202
11991203 /* used to define NL80211_CMD_MAX below */
net/wireless/nl80211.c+11−0
@@ -5678,6 +5678,11 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info) · 5677 unmodified lines
56785678 }
56795679 }
56805680
5681+static int nl80211_reload_regdb(struct sk_buff *skb, struct genl_info *info)
5682+{
5683+ return reg_reload_regdb();
5684+}
5685+
56815686 static int nl80211_get_mesh_config(struct sk_buff *skb,
56825687 struct genl_info *info)
56835688 {
@@ -12708,6 +12713,12 @@ static const struct genl_ops nl80211_ops[] = { · 7024 unmodified lines
1270812713 .policy = nl80211_policy,
1270912714 .flags = GENL_ADMIN_PERM,
1271012715 },
12716+ {
12717+ .cmd = NL80211_CMD_RELOAD_REGDB,
12718+ .doit = nl80211_reload_regdb,
12719+ .policy = nl80211_policy,
12720+ .flags = GENL_ADMIN_PERM,
12721+ },
1271112722 {
1271212723 .cmd = NL80211_CMD_GET_MESH_CONFIG,
1271312724 .doit = nl80211_get_mesh_config,
net/wireless/reg.c+60−20
@@ -781,6 +781,8 @@ static int query_regdb(const char *alpha2) · 780 unmodified lines
781781 const struct fwdb_header *hdr = regdb;
782782 const struct fwdb_country *country;
783783
784+ ASSERT_RTNL();
785+
784786 if (IS_ERR(regdb))
785787 return PTR_ERR(regdb);
786788
@@ -796,41 +798,47 @@ static int query_regdb(const char *alpha2) · 9 unmodified lines
796798
797799 static void regdb_fw_cb(const struct firmware *fw, void *context)
798800 {
801+ int set_error = 0;
802+ bool restore = true;
799803 void *db;
800804
801805 if (!fw) {
802806 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)) {
808809 pr_info("loaded regulatory.db is malformed\n");
809− release_firmware(fw);
810− regdb = ERR_PTR(-EINVAL);
811− goto restore;
810+ set_error = -EINVAL;
812811 }
813812
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+ }
816827
817− if (!db)
818− goto restore;
819− regdb = db;
828+ if (restore)
829+ restore_regulatory_settings(true);
820830
821− if (query_regdb(context))
822− goto restore;
823− goto free;
824− restore:
825− rtnl_lock();
826− restore_regulatory_settings(true);
827831 rtnl_unlock();
828− free:
832+
829833 kfree(context);
834+
835+ release_firmware(fw);
830836 }
831837
832838 static int query_regdb_file(const char *alpha2)
833839 {
840+ ASSERT_RTNL();
841+
834842 if (regdb)
835843 return query_regdb(alpha2);
836844
@@ -843,6 +851,38 @@ static int query_regdb_file(const char *alpha2) · 6 unmodified lines
843851 (void *)alpha2, regdb_fw_cb);
844852 }
845853
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", &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+
846886 static bool reg_query_database(struct regulatory_request *request)
847887 {
848888 /* query internal regulatory database (if it exists) */
net/wireless/reg.h+6−0
@@ -179,4 +179,10 @@ void regulatory_propagate_dfs_state(struct wiphy *wiphy, · 178 unmodified lines
179179 * @wiphy2 - wiphy it's dfs_region to be checked against that of wiphy1
180180 */
181181 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+
182188 #endif /* __NET_WIRELESS_REG_H */