diff options
Diffstat (limited to 'net/wireless/reg.c')
-rw-r--r-- | net/wireless/reg.c | 120 |
1 files changed, 96 insertions, 24 deletions
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index baa898add287..dc13c3ffeca6 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
@@ -40,6 +40,7 @@ | |||
40 | #include <net/cfg80211.h> | 40 | #include <net/cfg80211.h> |
41 | #include "core.h" | 41 | #include "core.h" |
42 | #include "reg.h" | 42 | #include "reg.h" |
43 | #include "regdb.h" | ||
43 | #include "nl80211.h" | 44 | #include "nl80211.h" |
44 | 45 | ||
45 | /* Receipt of information from last regulatory request */ | 46 | /* Receipt of information from last regulatory request */ |
@@ -335,6 +336,98 @@ static bool country_ie_integrity_changes(u32 checksum) | |||
335 | return false; | 336 | return false; |
336 | } | 337 | } |
337 | 338 | ||
339 | static int reg_copy_regd(const struct ieee80211_regdomain **dst_regd, | ||
340 | const struct ieee80211_regdomain *src_regd) | ||
341 | { | ||
342 | struct ieee80211_regdomain *regd; | ||
343 | int size_of_regd = 0; | ||
344 | unsigned int i; | ||
345 | |||
346 | size_of_regd = sizeof(struct ieee80211_regdomain) + | ||
347 | ((src_regd->n_reg_rules + 1) * sizeof(struct ieee80211_reg_rule)); | ||
348 | |||
349 | regd = kzalloc(size_of_regd, GFP_KERNEL); | ||
350 | if (!regd) | ||
351 | return -ENOMEM; | ||
352 | |||
353 | memcpy(regd, src_regd, sizeof(struct ieee80211_regdomain)); | ||
354 | |||
355 | for (i = 0; i < src_regd->n_reg_rules; i++) | ||
356 | memcpy(®d->reg_rules[i], &src_regd->reg_rules[i], | ||
357 | sizeof(struct ieee80211_reg_rule)); | ||
358 | |||
359 | *dst_regd = regd; | ||
360 | return 0; | ||
361 | } | ||
362 | |||
363 | #ifdef CONFIG_CFG80211_INTERNAL_REGDB | ||
364 | struct reg_regdb_search_request { | ||
365 | char alpha2[2]; | ||
366 | struct list_head list; | ||
367 | }; | ||
368 | |||
369 | static LIST_HEAD(reg_regdb_search_list); | ||
370 | static DEFINE_SPINLOCK(reg_regdb_search_lock); | ||
371 | |||
372 | static void reg_regdb_search(struct work_struct *work) | ||
373 | { | ||
374 | struct reg_regdb_search_request *request; | ||
375 | const struct ieee80211_regdomain *curdom, *regdom; | ||
376 | int i, r; | ||
377 | |||
378 | spin_lock(®_regdb_search_lock); | ||
379 | while (!list_empty(®_regdb_search_list)) { | ||
380 | request = list_first_entry(®_regdb_search_list, | ||
381 | struct reg_regdb_search_request, | ||
382 | list); | ||
383 | list_del(&request->list); | ||
384 | |||
385 | for (i=0; i<reg_regdb_size; i++) { | ||
386 | curdom = reg_regdb[i]; | ||
387 | |||
388 | if (!memcmp(request->alpha2, curdom->alpha2, 2)) { | ||
389 | r = reg_copy_regd(®dom, curdom); | ||
390 | if (r) | ||
391 | break; | ||
392 | spin_unlock(®_regdb_search_lock); | ||
393 | mutex_lock(&cfg80211_mutex); | ||
394 | set_regdom(regdom); | ||
395 | mutex_unlock(&cfg80211_mutex); | ||
396 | spin_lock(®_regdb_search_lock); | ||
397 | break; | ||
398 | } | ||
399 | } | ||
400 | |||
401 | kfree(request); | ||
402 | } | ||
403 | spin_unlock(®_regdb_search_lock); | ||
404 | } | ||
405 | |||
406 | static DECLARE_WORK(reg_regdb_work, reg_regdb_search); | ||
407 | |||
408 | static void reg_regdb_query(const char *alpha2) | ||
409 | { | ||
410 | struct reg_regdb_search_request *request; | ||
411 | |||
412 | if (!alpha2) | ||
413 | return; | ||
414 | |||
415 | request = kzalloc(sizeof(struct reg_regdb_search_request), GFP_KERNEL); | ||
416 | if (!request) | ||
417 | return; | ||
418 | |||
419 | memcpy(request->alpha2, alpha2, 2); | ||
420 | |||
421 | spin_lock(®_regdb_search_lock); | ||
422 | list_add_tail(&request->list, ®_regdb_search_list); | ||
423 | spin_unlock(®_regdb_search_lock); | ||
424 | |||
425 | schedule_work(®_regdb_work); | ||
426 | } | ||
427 | #else | ||
428 | static inline void reg_regdb_query(const char *alpha2) {} | ||
429 | #endif /* CONFIG_CFG80211_INTERNAL_REGDB */ | ||
430 | |||
338 | /* | 431 | /* |
339 | * This lets us keep regulatory code which is updated on a regulatory | 432 | * This lets us keep regulatory code which is updated on a regulatory |
340 | * basis in userspace. | 433 | * basis in userspace. |
@@ -354,6 +447,9 @@ static int call_crda(const char *alpha2) | |||
354 | printk(KERN_INFO "cfg80211: Calling CRDA to update world " | 447 | printk(KERN_INFO "cfg80211: Calling CRDA to update world " |
355 | "regulatory domain\n"); | 448 | "regulatory domain\n"); |
356 | 449 | ||
450 | /* query internal regulatory database (if it exists) */ | ||
451 | reg_regdb_query(alpha2); | ||
452 | |||
357 | country_env[8] = alpha2[0]; | 453 | country_env[8] = alpha2[0]; |
358 | country_env[9] = alpha2[1]; | 454 | country_env[9] = alpha2[1]; |
359 | 455 | ||
@@ -1342,30 +1438,6 @@ void wiphy_apply_custom_regulatory(struct wiphy *wiphy, | |||
1342 | } | 1438 | } |
1343 | EXPORT_SYMBOL(wiphy_apply_custom_regulatory); | 1439 | EXPORT_SYMBOL(wiphy_apply_custom_regulatory); |
1344 | 1440 | ||
1345 | static int reg_copy_regd(const struct ieee80211_regdomain **dst_regd, | ||
1346 | const struct ieee80211_regdomain *src_regd) | ||
1347 | { | ||
1348 | struct ieee80211_regdomain *regd; | ||
1349 | int size_of_regd = 0; | ||
1350 | unsigned int i; | ||
1351 | |||
1352 | size_of_regd = sizeof(struct ieee80211_regdomain) + | ||
1353 | ((src_regd->n_reg_rules + 1) * sizeof(struct ieee80211_reg_rule)); | ||
1354 | |||
1355 | regd = kzalloc(size_of_regd, GFP_KERNEL); | ||
1356 | if (!regd) | ||
1357 | return -ENOMEM; | ||
1358 | |||
1359 | memcpy(regd, src_regd, sizeof(struct ieee80211_regdomain)); | ||
1360 | |||
1361 | for (i = 0; i < src_regd->n_reg_rules; i++) | ||
1362 | memcpy(®d->reg_rules[i], &src_regd->reg_rules[i], | ||
1363 | sizeof(struct ieee80211_reg_rule)); | ||
1364 | |||
1365 | *dst_regd = regd; | ||
1366 | return 0; | ||
1367 | } | ||
1368 | |||
1369 | /* | 1441 | /* |
1370 | * Return value which can be used by ignore_request() to indicate | 1442 | * Return value which can be used by ignore_request() to indicate |
1371 | * it has been determined we should intersect two regulatory domains | 1443 | * it has been determined we should intersect two regulatory domains |