aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/reg.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2008-12-28 15:49:40 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2008-12-28 15:49:40 -0500
commit0191b625ca5a46206d2fb862bb08f36f2fcb3b31 (patch)
tree454d1842b1833d976da62abcbd5c47521ebe9bd7 /net/wireless/reg.c
parent54a696bd07c14d3b1192d03ce7269bc59b45209a (diff)
parenteb56092fc168bf5af199d47af50c0d84a96db898 (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6: (1429 commits) net: Allow dependancies of FDDI & Tokenring to be modular. igb: Fix build warning when DCA is disabled. net: Fix warning fallout from recent NAPI interface changes. gro: Fix potential use after free sfc: If AN is enabled, always read speed/duplex from the AN advertising bits sfc: When disabling the NIC, close the device rather than unregistering it sfc: SFT9001: Add cable diagnostics sfc: Add support for multiple PHY self-tests sfc: Merge top-level functions for self-tests sfc: Clean up PHY mode management in loopback self-test sfc: Fix unreliable link detection in some loopback modes sfc: Generate unique names for per-NIC workqueues 802.3ad: use standard ethhdr instead of ad_header 802.3ad: generalize out mac address initializer 802.3ad: initialize ports LACPDU from const initializer 802.3ad: remove typedef around ad_system 802.3ad: turn ports is_individual into a bool 802.3ad: turn ports is_enabled into a bool 802.3ad: make ntt bool ixgbe: Fix set_ringparam in ixgbe to use the same memory pools. ... Fixed trivial IPv4/6 address printing conflicts in fs/cifs/connect.c due to the conversion to %pI (in this networking merge) and the addition of doing IPv6 addresses (from the earlier merge of CIFS).
Diffstat (limited to 'net/wireless/reg.c')
-rw-r--r--net/wireless/reg.c1005
1 files changed, 762 insertions, 243 deletions
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index eb3b1a9f9b12..4f877535e666 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -42,17 +42,40 @@
42#include "core.h" 42#include "core.h"
43#include "reg.h" 43#include "reg.h"
44 44
45/* wiphy is set if this request's initiator is REGDOM_SET_BY_DRIVER */ 45/**
46 * struct regulatory_request - receipt of last regulatory request
47 *
48 * @wiphy: this is set if this request's initiator is
49 * %REGDOM_SET_BY_COUNTRY_IE or %REGDOM_SET_BY_DRIVER. This
50 * can be used by the wireless core to deal with conflicts
51 * and potentially inform users of which devices specifically
52 * cased the conflicts.
53 * @initiator: indicates who sent this request, could be any of
54 * of those set in reg_set_by, %REGDOM_SET_BY_*
55 * @alpha2: the ISO / IEC 3166 alpha2 country code of the requested
56 * regulatory domain. We have a few special codes:
57 * 00 - World regulatory domain
58 * 99 - built by driver but a specific alpha2 cannot be determined
59 * 98 - result of an intersection between two regulatory domains
60 * @intersect: indicates whether the wireless core should intersect
61 * the requested regulatory domain with the presently set regulatory
62 * domain.
63 * @country_ie_checksum: checksum of the last processed and accepted
64 * country IE
65 * @country_ie_env: lets us know if the AP is telling us we are outdoor,
66 * indoor, or if it doesn't matter
67 */
46struct regulatory_request { 68struct regulatory_request {
47 struct list_head list;
48 struct wiphy *wiphy; 69 struct wiphy *wiphy;
49 int granted;
50 enum reg_set_by initiator; 70 enum reg_set_by initiator;
51 char alpha2[2]; 71 char alpha2[2];
72 bool intersect;
73 u32 country_ie_checksum;
74 enum environment_cap country_ie_env;
52}; 75};
53 76
54static LIST_HEAD(regulatory_requests); 77/* Receipt of information from last regulatory request */
55DEFINE_MUTEX(cfg80211_reg_mutex); 78static struct regulatory_request *last_request;
56 79
57/* To trigger userspace events */ 80/* To trigger userspace events */
58static struct platform_device *reg_pdev; 81static struct platform_device *reg_pdev;
@@ -63,13 +86,16 @@ static u32 supported_bandwidths[] = {
63 MHZ_TO_KHZ(20), 86 MHZ_TO_KHZ(20),
64}; 87};
65 88
66static struct list_head regulatory_requests;
67
68/* Central wireless core regulatory domains, we only need two, 89/* Central wireless core regulatory domains, we only need two,
69 * the current one and a world regulatory domain in case we have no 90 * the current one and a world regulatory domain in case we have no
70 * information to give us an alpha2 */ 91 * information to give us an alpha2 */
71static const struct ieee80211_regdomain *cfg80211_regdomain; 92static const struct ieee80211_regdomain *cfg80211_regdomain;
72 93
94/* We use this as a place for the rd structure built from the
95 * last parsed country IE to rest until CRDA gets back to us with
96 * what it thinks should apply for the same country */
97static const struct ieee80211_regdomain *country_ie_regdomain;
98
73/* We keep a static world regulatory domain in case of the absence of CRDA */ 99/* We keep a static world regulatory domain in case of the absence of CRDA */
74static const struct ieee80211_regdomain world_regdom = { 100static const struct ieee80211_regdomain world_regdom = {
75 .n_reg_rules = 1, 101 .n_reg_rules = 1,
@@ -204,7 +230,7 @@ static void reset_regdomains(void)
204 * core upon initialization */ 230 * core upon initialization */
205static void update_world_regdomain(const struct ieee80211_regdomain *rd) 231static void update_world_regdomain(const struct ieee80211_regdomain *rd)
206{ 232{
207 BUG_ON(list_empty(&regulatory_requests)); 233 BUG_ON(!last_request);
208 234
209 reset_regdomains(); 235 reset_regdomains();
210 236
@@ -249,6 +275,18 @@ static bool is_unknown_alpha2(const char *alpha2)
249 return false; 275 return false;
250} 276}
251 277
278static bool is_intersected_alpha2(const char *alpha2)
279{
280 if (!alpha2)
281 return false;
282 /* Special case where regulatory domain is the
283 * result of an intersection between two regulatory domain
284 * structures */
285 if (alpha2[0] == '9' && alpha2[1] == '8')
286 return true;
287 return false;
288}
289
252static bool is_an_alpha2(const char *alpha2) 290static bool is_an_alpha2(const char *alpha2)
253{ 291{
254 if (!alpha2) 292 if (!alpha2)
@@ -277,6 +315,25 @@ static bool regdom_changed(const char *alpha2)
277 return true; 315 return true;
278} 316}
279 317
318/**
319 * country_ie_integrity_changes - tells us if the country IE has changed
320 * @checksum: checksum of country IE of fields we are interested in
321 *
322 * If the country IE has not changed you can ignore it safely. This is
323 * useful to determine if two devices are seeing two different country IEs
324 * even on the same alpha2. Note that this will return false if no IE has
325 * been set on the wireless core yet.
326 */
327static bool country_ie_integrity_changes(u32 checksum)
328{
329 /* If no IE has been set then the checksum doesn't change */
330 if (unlikely(!last_request->country_ie_checksum))
331 return false;
332 if (unlikely(last_request->country_ie_checksum != checksum))
333 return true;
334 return false;
335}
336
280/* This lets us keep regulatory code which is updated on a regulatory 337/* This lets us keep regulatory code which is updated on a regulatory
281 * basis in userspace. */ 338 * basis in userspace. */
282static int call_crda(const char *alpha2) 339static int call_crda(const char *alpha2)
@@ -300,121 +357,13 @@ static int call_crda(const char *alpha2)
300 return kobject_uevent_env(&reg_pdev->dev.kobj, KOBJ_CHANGE, envp); 357 return kobject_uevent_env(&reg_pdev->dev.kobj, KOBJ_CHANGE, envp);
301} 358}
302 359
303/* This has the logic which determines when a new request
304 * should be ignored. */
305static int ignore_request(struct wiphy *wiphy, enum reg_set_by set_by,
306 char *alpha2, struct ieee80211_regdomain *rd)
307{
308 struct regulatory_request *last_request = NULL;
309
310 /* All initial requests are respected */
311 if (list_empty(&regulatory_requests))
312 return 0;
313
314 last_request = list_first_entry(&regulatory_requests,
315 struct regulatory_request, list);
316
317 switch (set_by) {
318 case REGDOM_SET_BY_INIT:
319 return -EINVAL;
320 case REGDOM_SET_BY_CORE:
321 /* Always respect new wireless core hints, should only
322 * come in for updating the world regulatory domain at init
323 * anyway */
324 return 0;
325 case REGDOM_SET_BY_COUNTRY_IE:
326 if (last_request->initiator == set_by) {
327 if (last_request->wiphy != wiphy) {
328 /* Two cards with two APs claiming different
329 * different Country IE alpha2s!
330 * You're special!! */
331 if (!alpha2_equal(last_request->alpha2,
332 cfg80211_regdomain->alpha2)) {
333 /* XXX: Deal with conflict, consider
334 * building a new one out of the
335 * intersection */
336 WARN_ON(1);
337 return -EOPNOTSUPP;
338 }
339 return -EALREADY;
340 }
341 /* Two consecutive Country IE hints on the same wiphy */
342 if (!alpha2_equal(cfg80211_regdomain->alpha2, alpha2))
343 return 0;
344 return -EALREADY;
345 }
346 if (WARN(!is_alpha2_set(alpha2) || !is_an_alpha2(alpha2),
347 "Invalid Country IE regulatory hint passed "
348 "to the wireless core\n"))
349 return -EINVAL;
350 /* We ignore Country IE hints for now, as we haven't yet
351 * added the dot11MultiDomainCapabilityEnabled flag
352 * for wiphys */
353 return 1;
354 case REGDOM_SET_BY_DRIVER:
355 BUG_ON(!wiphy);
356 if (last_request->initiator == set_by) {
357 /* Two separate drivers hinting different things,
358 * this is possible if you have two devices present
359 * on a system with different EEPROM regulatory
360 * readings. XXX: Do intersection, we support only
361 * the first regulatory hint for now */
362 if (last_request->wiphy != wiphy)
363 return -EALREADY;
364 if (rd)
365 return -EALREADY;
366 /* Driver should not be trying to hint different
367 * regulatory domains! */
368 BUG_ON(!alpha2_equal(alpha2,
369 cfg80211_regdomain->alpha2));
370 return -EALREADY;
371 }
372 if (last_request->initiator == REGDOM_SET_BY_CORE)
373 return 0;
374 /* XXX: Handle intersection, and add the
375 * dot11MultiDomainCapabilityEnabled flag to wiphy. For now
376 * we assume the driver has this set to false, following the
377 * 802.11d dot11MultiDomainCapabilityEnabled documentation */
378 if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE)
379 return 0;
380 return 0;
381 case REGDOM_SET_BY_USER:
382 if (last_request->initiator == set_by ||
383 last_request->initiator == REGDOM_SET_BY_CORE)
384 return 0;
385 /* Drivers can use their wiphy's reg_notifier()
386 * to override any information */
387 if (last_request->initiator == REGDOM_SET_BY_DRIVER)
388 return 0;
389 /* XXX: Handle intersection */
390 if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE)
391 return -EOPNOTSUPP;
392 return 0;
393 default:
394 return -EINVAL;
395 }
396}
397
398static bool __reg_is_valid_request(const char *alpha2,
399 struct regulatory_request **request)
400{
401 struct regulatory_request *req;
402 if (list_empty(&regulatory_requests))
403 return false;
404 list_for_each_entry(req, &regulatory_requests, list) {
405 if (alpha2_equal(req->alpha2, alpha2)) {
406 *request = req;
407 return true;
408 }
409 }
410 return false;
411}
412
413/* Used by nl80211 before kmalloc'ing our regulatory domain */ 360/* Used by nl80211 before kmalloc'ing our regulatory domain */
414bool reg_is_valid_request(const char *alpha2) 361bool reg_is_valid_request(const char *alpha2)
415{ 362{
416 struct regulatory_request *request = NULL; 363 if (!last_request)
417 return __reg_is_valid_request(alpha2, &request); 364 return false;
365
366 return alpha2_equal(last_request->alpha2, alpha2);
418} 367}
419 368
420/* Sanity check on a regulatory rule */ 369/* Sanity check on a regulatory rule */
@@ -423,7 +372,7 @@ static bool is_valid_reg_rule(const struct ieee80211_reg_rule *rule)
423 const struct ieee80211_freq_range *freq_range = &rule->freq_range; 372 const struct ieee80211_freq_range *freq_range = &rule->freq_range;
424 u32 freq_diff; 373 u32 freq_diff;
425 374
426 if (freq_range->start_freq_khz == 0 || freq_range->end_freq_khz == 0) 375 if (freq_range->start_freq_khz <= 0 || freq_range->end_freq_khz <= 0)
427 return false; 376 return false;
428 377
429 if (freq_range->start_freq_khz > freq_range->end_freq_khz) 378 if (freq_range->start_freq_khz > freq_range->end_freq_khz)
@@ -431,7 +380,7 @@ static bool is_valid_reg_rule(const struct ieee80211_reg_rule *rule)
431 380
432 freq_diff = freq_range->end_freq_khz - freq_range->start_freq_khz; 381 freq_diff = freq_range->end_freq_khz - freq_range->start_freq_khz;
433 382
434 if (freq_range->max_bandwidth_khz > freq_diff) 383 if (freq_diff <= 0 || freq_range->max_bandwidth_khz > freq_diff)
435 return false; 384 return false;
436 385
437 return true; 386 return true;
@@ -445,6 +394,9 @@ static bool is_valid_rd(const struct ieee80211_regdomain *rd)
445 if (!rd->n_reg_rules) 394 if (!rd->n_reg_rules)
446 return false; 395 return false;
447 396
397 if (WARN_ON(rd->n_reg_rules > NL80211_MAX_SUPP_REG_RULES))
398 return false;
399
448 for (i = 0; i < rd->n_reg_rules; i++) { 400 for (i = 0; i < rd->n_reg_rules; i++) {
449 reg_rule = &rd->reg_rules[i]; 401 reg_rule = &rd->reg_rules[i];
450 if (!is_valid_reg_rule(reg_rule)) 402 if (!is_valid_reg_rule(reg_rule))
@@ -469,6 +421,311 @@ static u32 freq_max_bandwidth(const struct ieee80211_freq_range *freq_range,
469 return 0; 421 return 0;
470} 422}
471 423
424/* Converts a country IE to a regulatory domain. A regulatory domain
425 * structure has a lot of information which the IE doesn't yet have,
426 * so for the other values we use upper max values as we will intersect
427 * with our userspace regulatory agent to get lower bounds. */
428static struct ieee80211_regdomain *country_ie_2_rd(
429 u8 *country_ie,
430 u8 country_ie_len,
431 u32 *checksum)
432{
433 struct ieee80211_regdomain *rd = NULL;
434 unsigned int i = 0;
435 char alpha2[2];
436 u32 flags = 0;
437 u32 num_rules = 0, size_of_regd = 0;
438 u8 *triplets_start = NULL;
439 u8 len_at_triplet = 0;
440 /* the last channel we have registered in a subband (triplet) */
441 int last_sub_max_channel = 0;
442
443 *checksum = 0xDEADBEEF;
444
445 /* Country IE requirements */
446 BUG_ON(country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN ||
447 country_ie_len & 0x01);
448
449 alpha2[0] = country_ie[0];
450 alpha2[1] = country_ie[1];
451
452 /*
453 * Third octet can be:
454 * 'I' - Indoor
455 * 'O' - Outdoor
456 *
457 * anything else we assume is no restrictions
458 */
459 if (country_ie[2] == 'I')
460 flags = NL80211_RRF_NO_OUTDOOR;
461 else if (country_ie[2] == 'O')
462 flags = NL80211_RRF_NO_INDOOR;
463
464 country_ie += 3;
465 country_ie_len -= 3;
466
467 triplets_start = country_ie;
468 len_at_triplet = country_ie_len;
469
470 *checksum ^= ((flags ^ alpha2[0] ^ alpha2[1]) << 8);
471
472 /* We need to build a reg rule for each triplet, but first we must
473 * calculate the number of reg rules we will need. We will need one
474 * for each channel subband */
475 while (country_ie_len >= 3) {
476 struct ieee80211_country_ie_triplet *triplet =
477 (struct ieee80211_country_ie_triplet *) country_ie;
478 int cur_sub_max_channel = 0, cur_channel = 0;
479
480 if (triplet->ext.reg_extension_id >=
481 IEEE80211_COUNTRY_EXTENSION_ID) {
482 country_ie += 3;
483 country_ie_len -= 3;
484 continue;
485 }
486
487 cur_channel = triplet->chans.first_channel;
488 cur_sub_max_channel = ieee80211_channel_to_frequency(
489 cur_channel + triplet->chans.num_channels);
490
491 /* Basic sanity check */
492 if (cur_sub_max_channel < cur_channel)
493 return NULL;
494
495 /* Do not allow overlapping channels. Also channels
496 * passed in each subband must be monotonically
497 * increasing */
498 if (last_sub_max_channel) {
499 if (cur_channel <= last_sub_max_channel)
500 return NULL;
501 if (cur_sub_max_channel <= last_sub_max_channel)
502 return NULL;
503 }
504
505 /* When dot11RegulatoryClassesRequired is supported
506 * we can throw ext triplets as part of this soup,
507 * for now we don't care when those change as we
508 * don't support them */
509 *checksum ^= ((cur_channel ^ cur_sub_max_channel) << 8) |
510 ((cur_sub_max_channel ^ cur_sub_max_channel) << 16) |
511 ((triplet->chans.max_power ^ cur_sub_max_channel) << 24);
512
513 last_sub_max_channel = cur_sub_max_channel;
514
515 country_ie += 3;
516 country_ie_len -= 3;
517 num_rules++;
518
519 /* Note: this is not a IEEE requirement but
520 * simply a memory requirement */
521 if (num_rules > NL80211_MAX_SUPP_REG_RULES)
522 return NULL;
523 }
524
525 country_ie = triplets_start;
526 country_ie_len = len_at_triplet;
527
528 size_of_regd = sizeof(struct ieee80211_regdomain) +
529 (num_rules * sizeof(struct ieee80211_reg_rule));
530
531 rd = kzalloc(size_of_regd, GFP_KERNEL);
532 if (!rd)
533 return NULL;
534
535 rd->n_reg_rules = num_rules;
536 rd->alpha2[0] = alpha2[0];
537 rd->alpha2[1] = alpha2[1];
538
539 /* This time around we fill in the rd */
540 while (country_ie_len >= 3) {
541 struct ieee80211_country_ie_triplet *triplet =
542 (struct ieee80211_country_ie_triplet *) country_ie;
543 struct ieee80211_reg_rule *reg_rule = NULL;
544 struct ieee80211_freq_range *freq_range = NULL;
545 struct ieee80211_power_rule *power_rule = NULL;
546
547 /* Must parse if dot11RegulatoryClassesRequired is true,
548 * we don't support this yet */
549 if (triplet->ext.reg_extension_id >=
550 IEEE80211_COUNTRY_EXTENSION_ID) {
551 country_ie += 3;
552 country_ie_len -= 3;
553 continue;
554 }
555
556 reg_rule = &rd->reg_rules[i];
557 freq_range = &reg_rule->freq_range;
558 power_rule = &reg_rule->power_rule;
559
560 reg_rule->flags = flags;
561
562 /* The +10 is since the regulatory domain expects
563 * the actual band edge, not the center of freq for
564 * its start and end freqs, assuming 20 MHz bandwidth on
565 * the channels passed */
566 freq_range->start_freq_khz =
567 MHZ_TO_KHZ(ieee80211_channel_to_frequency(
568 triplet->chans.first_channel) - 10);
569 freq_range->end_freq_khz =
570 MHZ_TO_KHZ(ieee80211_channel_to_frequency(
571 triplet->chans.first_channel +
572 triplet->chans.num_channels) + 10);
573
574 /* Large arbitrary values, we intersect later */
575 /* Increment this if we ever support >= 40 MHz channels
576 * in IEEE 802.11 */
577 freq_range->max_bandwidth_khz = MHZ_TO_KHZ(40);
578 power_rule->max_antenna_gain = DBI_TO_MBI(100);
579 power_rule->max_eirp = DBM_TO_MBM(100);
580
581 country_ie += 3;
582 country_ie_len -= 3;
583 i++;
584
585 BUG_ON(i > NL80211_MAX_SUPP_REG_RULES);
586 }
587
588 return rd;
589}
590
591
592/* Helper for regdom_intersect(), this does the real
593 * mathematical intersection fun */
594static int reg_rules_intersect(
595 const struct ieee80211_reg_rule *rule1,
596 const struct ieee80211_reg_rule *rule2,
597 struct ieee80211_reg_rule *intersected_rule)
598{
599 const struct ieee80211_freq_range *freq_range1, *freq_range2;
600 struct ieee80211_freq_range *freq_range;
601 const struct ieee80211_power_rule *power_rule1, *power_rule2;
602 struct ieee80211_power_rule *power_rule;
603 u32 freq_diff;
604
605 freq_range1 = &rule1->freq_range;
606 freq_range2 = &rule2->freq_range;
607 freq_range = &intersected_rule->freq_range;
608
609 power_rule1 = &rule1->power_rule;
610 power_rule2 = &rule2->power_rule;
611 power_rule = &intersected_rule->power_rule;
612
613 freq_range->start_freq_khz = max(freq_range1->start_freq_khz,
614 freq_range2->start_freq_khz);
615 freq_range->end_freq_khz = min(freq_range1->end_freq_khz,
616 freq_range2->end_freq_khz);
617 freq_range->max_bandwidth_khz = min(freq_range1->max_bandwidth_khz,
618 freq_range2->max_bandwidth_khz);
619
620 freq_diff = freq_range->end_freq_khz - freq_range->start_freq_khz;
621 if (freq_range->max_bandwidth_khz > freq_diff)
622 freq_range->max_bandwidth_khz = freq_diff;
623
624 power_rule->max_eirp = min(power_rule1->max_eirp,
625 power_rule2->max_eirp);
626 power_rule->max_antenna_gain = min(power_rule1->max_antenna_gain,
627 power_rule2->max_antenna_gain);
628
629 intersected_rule->flags = (rule1->flags | rule2->flags);
630
631 if (!is_valid_reg_rule(intersected_rule))
632 return -EINVAL;
633
634 return 0;
635}
636
637/**
638 * regdom_intersect - do the intersection between two regulatory domains
639 * @rd1: first regulatory domain
640 * @rd2: second regulatory domain
641 *
642 * Use this function to get the intersection between two regulatory domains.
643 * Once completed we will mark the alpha2 for the rd as intersected, "98",
644 * as no one single alpha2 can represent this regulatory domain.
645 *
646 * Returns a pointer to the regulatory domain structure which will hold the
647 * resulting intersection of rules between rd1 and rd2. We will
648 * kzalloc() this structure for you.
649 */
650static struct ieee80211_regdomain *regdom_intersect(
651 const struct ieee80211_regdomain *rd1,
652 const struct ieee80211_regdomain *rd2)
653{
654 int r, size_of_regd;
655 unsigned int x, y;
656 unsigned int num_rules = 0, rule_idx = 0;
657 const struct ieee80211_reg_rule *rule1, *rule2;
658 struct ieee80211_reg_rule *intersected_rule;
659 struct ieee80211_regdomain *rd;
660 /* This is just a dummy holder to help us count */
661 struct ieee80211_reg_rule irule;
662
663 /* Uses the stack temporarily for counter arithmetic */
664 intersected_rule = &irule;
665
666 memset(intersected_rule, 0, sizeof(struct ieee80211_reg_rule));
667
668 if (!rd1 || !rd2)
669 return NULL;
670
671 /* First we get a count of the rules we'll need, then we actually
672 * build them. This is to so we can malloc() and free() a
673 * regdomain once. The reason we use reg_rules_intersect() here
674 * is it will return -EINVAL if the rule computed makes no sense.
675 * All rules that do check out OK are valid. */
676
677 for (x = 0; x < rd1->n_reg_rules; x++) {
678 rule1 = &rd1->reg_rules[x];
679 for (y = 0; y < rd2->n_reg_rules; y++) {
680 rule2 = &rd2->reg_rules[y];
681 if (!reg_rules_intersect(rule1, rule2,
682 intersected_rule))
683 num_rules++;
684 memset(intersected_rule, 0,
685 sizeof(struct ieee80211_reg_rule));
686 }
687 }
688
689 if (!num_rules)
690 return NULL;
691
692 size_of_regd = sizeof(struct ieee80211_regdomain) +
693 ((num_rules + 1) * sizeof(struct ieee80211_reg_rule));
694
695 rd = kzalloc(size_of_regd, GFP_KERNEL);
696 if (!rd)
697 return NULL;
698
699 for (x = 0; x < rd1->n_reg_rules; x++) {
700 rule1 = &rd1->reg_rules[x];
701 for (y = 0; y < rd2->n_reg_rules; y++) {
702 rule2 = &rd2->reg_rules[y];
703 /* This time around instead of using the stack lets
704 * write to the target rule directly saving ourselves
705 * a memcpy() */
706 intersected_rule = &rd->reg_rules[rule_idx];
707 r = reg_rules_intersect(rule1, rule2,
708 intersected_rule);
709 /* No need to memset here the intersected rule here as
710 * we're not using the stack anymore */
711 if (r)
712 continue;
713 rule_idx++;
714 }
715 }
716
717 if (rule_idx != num_rules) {
718 kfree(rd);
719 return NULL;
720 }
721
722 rd->n_reg_rules = num_rules;
723 rd->alpha2[0] = '9';
724 rd->alpha2[1] = '8';
725
726 return rd;
727}
728
472/* XXX: add support for the rest of enum nl80211_reg_rule_flags, we may 729/* XXX: add support for the rest of enum nl80211_reg_rule_flags, we may
473 * want to just have the channel structure use these */ 730 * want to just have the channel structure use these */
474static u32 map_regdom_flags(u32 rd_flags) 731static u32 map_regdom_flags(u32 rd_flags)
@@ -559,12 +816,23 @@ static void handle_band(struct ieee80211_supported_band *sband)
559 handle_channel(&sband->channels[i]); 816 handle_channel(&sband->channels[i]);
560} 817}
561 818
819static bool ignore_reg_update(struct wiphy *wiphy, enum reg_set_by setby)
820{
821 if (!last_request)
822 return true;
823 if (setby == REGDOM_SET_BY_CORE &&
824 wiphy->fw_handles_regulatory)
825 return true;
826 return false;
827}
828
562static void update_all_wiphy_regulatory(enum reg_set_by setby) 829static void update_all_wiphy_regulatory(enum reg_set_by setby)
563{ 830{
564 struct cfg80211_registered_device *drv; 831 struct cfg80211_registered_device *drv;
565 832
566 list_for_each_entry(drv, &cfg80211_drv_list, list) 833 list_for_each_entry(drv, &cfg80211_drv_list, list)
567 wiphy_update_regulatory(&drv->wiphy, setby); 834 if (!ignore_reg_update(&drv->wiphy, setby))
835 wiphy_update_regulatory(&drv->wiphy, setby);
568} 836}
569 837
570void wiphy_update_regulatory(struct wiphy *wiphy, enum reg_set_by setby) 838void wiphy_update_regulatory(struct wiphy *wiphy, enum reg_set_by setby)
@@ -578,78 +846,237 @@ void wiphy_update_regulatory(struct wiphy *wiphy, enum reg_set_by setby)
578 } 846 }
579} 847}
580 848
581/* Caller must hold &cfg80211_drv_mutex */ 849/* Return value which can be used by ignore_request() to indicate
582int __regulatory_hint(struct wiphy *wiphy, enum reg_set_by set_by, 850 * it has been determined we should intersect two regulatory domains */
583 const char *alpha2, struct ieee80211_regdomain *rd) 851#define REG_INTERSECT 1
584{
585 struct regulatory_request *request;
586 char *rd_alpha2;
587 int r = 0;
588
589 r = ignore_request(wiphy, set_by, (char *) alpha2, rd);
590 if (r)
591 return r;
592 852
593 if (rd) 853/* This has the logic which determines when a new request
594 rd_alpha2 = rd->alpha2; 854 * should be ignored. */
595 else 855static int ignore_request(struct wiphy *wiphy, enum reg_set_by set_by,
596 rd_alpha2 = (char *) alpha2; 856 const char *alpha2)
857{
858 /* All initial requests are respected */
859 if (!last_request)
860 return 0;
597 861
598 switch (set_by) { 862 switch (set_by) {
863 case REGDOM_SET_BY_INIT:
864 return -EINVAL;
599 case REGDOM_SET_BY_CORE: 865 case REGDOM_SET_BY_CORE:
866 /*
867 * Always respect new wireless core hints, should only happen
868 * when updating the world regulatory domain at init.
869 */
870 return 0;
600 case REGDOM_SET_BY_COUNTRY_IE: 871 case REGDOM_SET_BY_COUNTRY_IE:
872 if (unlikely(!is_an_alpha2(alpha2)))
873 return -EINVAL;
874 if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE) {
875 if (last_request->wiphy != wiphy) {
876 /*
877 * Two cards with two APs claiming different
878 * different Country IE alpha2s. We could
879 * intersect them, but that seems unlikely
880 * to be correct. Reject second one for now.
881 */
882 if (!alpha2_equal(alpha2,
883 cfg80211_regdomain->alpha2))
884 return -EOPNOTSUPP;
885 return -EALREADY;
886 }
887 /* Two consecutive Country IE hints on the same wiphy.
888 * This should be picked up early by the driver/stack */
889 if (WARN_ON(!alpha2_equal(cfg80211_regdomain->alpha2,
890 alpha2)))
891 return 0;
892 return -EALREADY;
893 }
894 return REG_INTERSECT;
601 case REGDOM_SET_BY_DRIVER: 895 case REGDOM_SET_BY_DRIVER:
896 if (last_request->initiator == REGDOM_SET_BY_DRIVER)
897 return -EALREADY;
898 return 0;
602 case REGDOM_SET_BY_USER: 899 case REGDOM_SET_BY_USER:
603 request = kzalloc(sizeof(struct regulatory_request), 900 if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE)
604 GFP_KERNEL); 901 return REG_INTERSECT;
605 if (!request) 902 /* If the user knows better the user should set the regdom
606 return -ENOMEM; 903 * to their country before the IE is picked up */
607 904 if (last_request->initiator == REGDOM_SET_BY_USER &&
608 request->alpha2[0] = rd_alpha2[0]; 905 last_request->intersect)
609 request->alpha2[1] = rd_alpha2[1]; 906 return -EOPNOTSUPP;
610 request->initiator = set_by; 907 return 0;
611 request->wiphy = wiphy;
612
613 list_add_tail(&request->list, &regulatory_requests);
614 if (rd)
615 break;
616 r = call_crda(alpha2);
617#ifndef CONFIG_WIRELESS_OLD_REGULATORY
618 if (r)
619 printk(KERN_ERR "cfg80211: Failed calling CRDA\n");
620#endif
621 break;
622 default:
623 r = -ENOTSUPP;
624 break;
625 } 908 }
626 909
627 return r; 910 return -EINVAL;
628} 911}
629 912
630/* If rd is not NULL and if this call fails the caller must free it */ 913/* Caller must hold &cfg80211_drv_mutex */
631int regulatory_hint(struct wiphy *wiphy, const char *alpha2, 914int __regulatory_hint(struct wiphy *wiphy, enum reg_set_by set_by,
632 struct ieee80211_regdomain *rd) 915 const char *alpha2,
916 u32 country_ie_checksum,
917 enum environment_cap env)
633{ 918{
634 int r; 919 struct regulatory_request *request;
635 BUG_ON(!rd && !alpha2); 920 bool intersect = false;
921 int r = 0;
636 922
637 mutex_lock(&cfg80211_drv_mutex); 923 r = ignore_request(wiphy, set_by, alpha2);
638 924
639 r = __regulatory_hint(wiphy, REGDOM_SET_BY_DRIVER, alpha2, rd); 925 if (r == REG_INTERSECT)
640 if (r || !rd) 926 intersect = true;
641 goto unlock_and_exit; 927 else if (r)
928 return r;
642 929
643 /* If the driver passed a regulatory domain we skipped asking 930 request = kzalloc(sizeof(struct regulatory_request),
644 * userspace for one so we can now go ahead and set it */ 931 GFP_KERNEL);
645 r = set_regdom(rd); 932 if (!request)
933 return -ENOMEM;
934
935 request->alpha2[0] = alpha2[0];
936 request->alpha2[1] = alpha2[1];
937 request->initiator = set_by;
938 request->wiphy = wiphy;
939 request->intersect = intersect;
940 request->country_ie_checksum = country_ie_checksum;
941 request->country_ie_env = env;
942
943 kfree(last_request);
944 last_request = request;
945 /*
946 * Note: When CONFIG_WIRELESS_OLD_REGULATORY is enabled
947 * AND if CRDA is NOT present nothing will happen, if someone
948 * wants to bother with 11d with OLD_REG you can add a timer.
949 * If after x amount of time nothing happens you can call:
950 *
951 * return set_regdom(country_ie_regdomain);
952 *
953 * to intersect with the static rd
954 */
955 return call_crda(alpha2);
956}
957
958void regulatory_hint(struct wiphy *wiphy, const char *alpha2)
959{
960 BUG_ON(!alpha2);
646 961
647unlock_and_exit: 962 mutex_lock(&cfg80211_drv_mutex);
963 __regulatory_hint(wiphy, REGDOM_SET_BY_DRIVER, alpha2, 0, ENVIRON_ANY);
648 mutex_unlock(&cfg80211_drv_mutex); 964 mutex_unlock(&cfg80211_drv_mutex);
649 return r;
650} 965}
651EXPORT_SYMBOL(regulatory_hint); 966EXPORT_SYMBOL(regulatory_hint);
652 967
968static bool reg_same_country_ie_hint(struct wiphy *wiphy,
969 u32 country_ie_checksum)
970{
971 if (!last_request->wiphy)
972 return false;
973 if (likely(last_request->wiphy != wiphy))
974 return !country_ie_integrity_changes(country_ie_checksum);
975 /* We should not have let these through at this point, they
976 * should have been picked up earlier by the first alpha2 check
977 * on the device */
978 if (WARN_ON(!country_ie_integrity_changes(country_ie_checksum)))
979 return true;
980 return false;
981}
982
983void regulatory_hint_11d(struct wiphy *wiphy,
984 u8 *country_ie,
985 u8 country_ie_len)
986{
987 struct ieee80211_regdomain *rd = NULL;
988 char alpha2[2];
989 u32 checksum = 0;
990 enum environment_cap env = ENVIRON_ANY;
991
992 if (!last_request)
993 return;
994
995 mutex_lock(&cfg80211_drv_mutex);
996
997 /* IE len must be evenly divisible by 2 */
998 if (country_ie_len & 0x01)
999 goto out;
1000
1001 if (country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN)
1002 goto out;
1003
1004 /* Pending country IE processing, this can happen after we
1005 * call CRDA and wait for a response if a beacon was received before
1006 * we were able to process the last regulatory_hint_11d() call */
1007 if (country_ie_regdomain)
1008 goto out;
1009
1010 alpha2[0] = country_ie[0];
1011 alpha2[1] = country_ie[1];
1012
1013 if (country_ie[2] == 'I')
1014 env = ENVIRON_INDOOR;
1015 else if (country_ie[2] == 'O')
1016 env = ENVIRON_OUTDOOR;
1017
1018 /* We will run this for *every* beacon processed for the BSSID, so
1019 * we optimize an early check to exit out early if we don't have to
1020 * do anything */
1021 if (likely(last_request->wiphy)) {
1022 struct cfg80211_registered_device *drv_last_ie;
1023
1024 drv_last_ie = wiphy_to_dev(last_request->wiphy);
1025
1026 /* Lets keep this simple -- we trust the first AP
1027 * after we intersect with CRDA */
1028 if (likely(last_request->wiphy == wiphy)) {
1029 /* Ignore IEs coming in on this wiphy with
1030 * the same alpha2 and environment cap */
1031 if (likely(alpha2_equal(drv_last_ie->country_ie_alpha2,
1032 alpha2) &&
1033 env == drv_last_ie->env)) {
1034 goto out;
1035 }
1036 /* the wiphy moved on to another BSSID or the AP
1037 * was reconfigured. XXX: We need to deal with the
1038 * case where the user suspends and goes to goes
1039 * to another country, and then gets IEs from an
1040 * AP with different settings */
1041 goto out;
1042 } else {
1043 /* Ignore IEs coming in on two separate wiphys with
1044 * the same alpha2 and environment cap */
1045 if (likely(alpha2_equal(drv_last_ie->country_ie_alpha2,
1046 alpha2) &&
1047 env == drv_last_ie->env)) {
1048 goto out;
1049 }
1050 /* We could potentially intersect though */
1051 goto out;
1052 }
1053 }
1054
1055 rd = country_ie_2_rd(country_ie, country_ie_len, &checksum);
1056 if (!rd)
1057 goto out;
1058
1059 /* This will not happen right now but we leave it here for the
1060 * the future when we want to add suspend/resume support and having
1061 * the user move to another country after doing so, or having the user
1062 * move to another AP. Right now we just trust the first AP. This is why
1063 * this is marked as likley(). If we hit this before we add this support
1064 * we want to be informed of it as it would indicate a mistake in the
1065 * current design */
1066 if (likely(WARN_ON(reg_same_country_ie_hint(wiphy, checksum))))
1067 goto out;
1068
1069 /* We keep this around for when CRDA comes back with a response so
1070 * we can intersect with that */
1071 country_ie_regdomain = rd;
1072
1073 __regulatory_hint(wiphy, REGDOM_SET_BY_COUNTRY_IE,
1074 country_ie_regdomain->alpha2, checksum, env);
1075
1076out:
1077 mutex_unlock(&cfg80211_drv_mutex);
1078}
1079EXPORT_SYMBOL(regulatory_hint_11d);
653 1080
654static void print_rd_rules(const struct ieee80211_regdomain *rd) 1081static void print_rd_rules(const struct ieee80211_regdomain *rd)
655{ 1082{
@@ -689,7 +1116,25 @@ static void print_rd_rules(const struct ieee80211_regdomain *rd)
689static void print_regdomain(const struct ieee80211_regdomain *rd) 1116static void print_regdomain(const struct ieee80211_regdomain *rd)
690{ 1117{
691 1118
692 if (is_world_regdom(rd->alpha2)) 1119 if (is_intersected_alpha2(rd->alpha2)) {
1120 struct wiphy *wiphy = NULL;
1121 struct cfg80211_registered_device *drv;
1122
1123 if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE) {
1124 if (last_request->wiphy) {
1125 wiphy = last_request->wiphy;
1126 drv = wiphy_to_dev(wiphy);
1127 printk(KERN_INFO "cfg80211: Current regulatory "
1128 "domain updated by AP to: %c%c\n",
1129 drv->country_ie_alpha2[0],
1130 drv->country_ie_alpha2[1]);
1131 } else
1132 printk(KERN_INFO "cfg80211: Current regulatory "
1133 "domain intersected: \n");
1134 } else
1135 printk(KERN_INFO "cfg80211: Current regulatory "
1136 "intersected: \n");
1137 } else if (is_world_regdom(rd->alpha2))
693 printk(KERN_INFO "cfg80211: World regulatory " 1138 printk(KERN_INFO "cfg80211: World regulatory "
694 "domain updated:\n"); 1139 "domain updated:\n");
695 else { 1140 else {
@@ -705,21 +1150,50 @@ static void print_regdomain(const struct ieee80211_regdomain *rd)
705 print_rd_rules(rd); 1150 print_rd_rules(rd);
706} 1151}
707 1152
708void print_regdomain_info(const struct ieee80211_regdomain *rd) 1153static void print_regdomain_info(const struct ieee80211_regdomain *rd)
709{ 1154{
710 printk(KERN_INFO "cfg80211: Regulatory domain: %c%c\n", 1155 printk(KERN_INFO "cfg80211: Regulatory domain: %c%c\n",
711 rd->alpha2[0], rd->alpha2[1]); 1156 rd->alpha2[0], rd->alpha2[1]);
712 print_rd_rules(rd); 1157 print_rd_rules(rd);
713} 1158}
714 1159
715static int __set_regdom(const struct ieee80211_regdomain *rd) 1160#ifdef CONFIG_CFG80211_REG_DEBUG
1161static void reg_country_ie_process_debug(
1162 const struct ieee80211_regdomain *rd,
1163 const struct ieee80211_regdomain *country_ie_regdomain,
1164 const struct ieee80211_regdomain *intersected_rd)
716{ 1165{
717 struct regulatory_request *request = NULL; 1166 printk(KERN_DEBUG "cfg80211: Received country IE:\n");
1167 print_regdomain_info(country_ie_regdomain);
1168 printk(KERN_DEBUG "cfg80211: CRDA thinks this should applied:\n");
1169 print_regdomain_info(rd);
1170 if (intersected_rd) {
1171 printk(KERN_DEBUG "cfg80211: We intersect both of these "
1172 "and get:\n");
1173 print_regdomain_info(rd);
1174 return;
1175 }
1176 printk(KERN_DEBUG "cfg80211: Intersection between both failed\n");
1177}
1178#else
1179static inline void reg_country_ie_process_debug(
1180 const struct ieee80211_regdomain *rd,
1181 const struct ieee80211_regdomain *country_ie_regdomain,
1182 const struct ieee80211_regdomain *intersected_rd)
1183{
1184}
1185#endif
718 1186
1187/* Takes ownership of rd only if it doesn't fail */
1188static int __set_regdom(const struct ieee80211_regdomain *rd)
1189{
1190 const struct ieee80211_regdomain *intersected_rd = NULL;
1191 struct cfg80211_registered_device *drv = NULL;
1192 struct wiphy *wiphy = NULL;
719 /* Some basic sanity checks first */ 1193 /* Some basic sanity checks first */
720 1194
721 if (is_world_regdom(rd->alpha2)) { 1195 if (is_world_regdom(rd->alpha2)) {
722 if (WARN_ON(!__reg_is_valid_request(rd->alpha2, &request))) 1196 if (WARN_ON(!reg_is_valid_request(rd->alpha2)))
723 return -EINVAL; 1197 return -EINVAL;
724 update_world_regdomain(rd); 1198 update_world_regdomain(rd);
725 return 0; 1199 return 0;
@@ -729,45 +1203,102 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
729 !is_unknown_alpha2(rd->alpha2)) 1203 !is_unknown_alpha2(rd->alpha2))
730 return -EINVAL; 1204 return -EINVAL;
731 1205
732 if (list_empty(&regulatory_requests)) 1206 if (!last_request)
733 return -EINVAL; 1207 return -EINVAL;
734 1208
735 /* allow overriding the static definitions if CRDA is present */ 1209 /* Lets only bother proceeding on the same alpha2 if the current
736 if (!is_old_static_regdom(cfg80211_regdomain) && 1210 * rd is non static (it means CRDA was present and was used last)
737 !regdom_changed(rd->alpha2)) 1211 * and the pending request came in from a country IE */
738 return -EINVAL; 1212 if (last_request->initiator != REGDOM_SET_BY_COUNTRY_IE) {
1213 /* If someone else asked us to change the rd lets only bother
1214 * checking if the alpha2 changes if CRDA was already called */
1215 if (!is_old_static_regdom(cfg80211_regdomain) &&
1216 !regdom_changed(rd->alpha2))
1217 return -EINVAL;
1218 }
1219
1220 wiphy = last_request->wiphy;
739 1221
740 /* Now lets set the regulatory domain, update all driver channels 1222 /* Now lets set the regulatory domain, update all driver channels
741 * and finally inform them of what we have done, in case they want 1223 * and finally inform them of what we have done, in case they want
742 * to review or adjust their own settings based on their own 1224 * to review or adjust their own settings based on their own
743 * internal EEPROM data */ 1225 * internal EEPROM data */
744 1226
745 if (WARN_ON(!__reg_is_valid_request(rd->alpha2, &request))) 1227 if (WARN_ON(!reg_is_valid_request(rd->alpha2)))
746 return -EINVAL; 1228 return -EINVAL;
747 1229
748 reset_regdomains(); 1230 if (!is_valid_rd(rd)) {
1231 printk(KERN_ERR "cfg80211: Invalid "
1232 "regulatory domain detected:\n");
1233 print_regdomain_info(rd);
1234 return -EINVAL;
1235 }
749 1236
750 /* Country IE parsing coming soon */ 1237 if (!last_request->intersect) {
751 switch (request->initiator) { 1238 reset_regdomains();
752 case REGDOM_SET_BY_CORE: 1239 cfg80211_regdomain = rd;
753 case REGDOM_SET_BY_DRIVER: 1240 return 0;
754 case REGDOM_SET_BY_USER: 1241 }
755 if (!is_valid_rd(rd)) { 1242
756 printk(KERN_ERR "cfg80211: Invalid " 1243 /* Intersection requires a bit more work */
757 "regulatory domain detected:\n"); 1244
758 print_regdomain_info(rd); 1245 if (last_request->initiator != REGDOM_SET_BY_COUNTRY_IE) {
1246
1247 intersected_rd = regdom_intersect(rd, cfg80211_regdomain);
1248 if (!intersected_rd)
759 return -EINVAL; 1249 return -EINVAL;
760 } 1250
761 break; 1251 /* We can trash what CRDA provided now */
762 case REGDOM_SET_BY_COUNTRY_IE: /* Not yet */ 1252 kfree(rd);
763 WARN_ON(1); 1253 rd = NULL;
764 default: 1254
765 return -EOPNOTSUPP; 1255 reset_regdomains();
1256 cfg80211_regdomain = intersected_rd;
1257
1258 return 0;
766 } 1259 }
767 1260
768 /* Tada! */ 1261 /*
769 cfg80211_regdomain = rd; 1262 * Country IE requests are handled a bit differently, we intersect
770 request->granted = 1; 1263 * the country IE rd with what CRDA believes that country should have
1264 */
1265
1266 BUG_ON(!country_ie_regdomain);
1267
1268 if (rd != country_ie_regdomain) {
1269 /* Intersect what CRDA returned and our what we
1270 * had built from the Country IE received */
1271
1272 intersected_rd = regdom_intersect(rd, country_ie_regdomain);
1273
1274 reg_country_ie_process_debug(rd, country_ie_regdomain,
1275 intersected_rd);
1276
1277 kfree(country_ie_regdomain);
1278 country_ie_regdomain = NULL;
1279 } else {
1280 /* This would happen when CRDA was not present and
1281 * OLD_REGULATORY was enabled. We intersect our Country
1282 * IE rd and what was set on cfg80211 originally */
1283 intersected_rd = regdom_intersect(rd, cfg80211_regdomain);
1284 }
1285
1286 if (!intersected_rd)
1287 return -EINVAL;
1288
1289 drv = wiphy_to_dev(wiphy);
1290
1291 drv->country_ie_alpha2[0] = rd->alpha2[0];
1292 drv->country_ie_alpha2[1] = rd->alpha2[1];
1293 drv->env = last_request->country_ie_env;
1294
1295 BUG_ON(intersected_rd == rd);
1296
1297 kfree(rd);
1298 rd = NULL;
1299
1300 reset_regdomains();
1301 cfg80211_regdomain = intersected_rd;
771 1302
772 return 0; 1303 return 0;
773} 1304}
@@ -775,52 +1306,41 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
775 1306
776/* Use this call to set the current regulatory domain. Conflicts with 1307/* Use this call to set the current regulatory domain. Conflicts with
777 * multiple drivers can be ironed out later. Caller must've already 1308 * multiple drivers can be ironed out later. Caller must've already
778 * kmalloc'd the rd structure. If this calls fails you should kfree() 1309 * kmalloc'd the rd structure. Caller must hold cfg80211_drv_mutex */
779 * the passed rd. Caller must hold cfg80211_drv_mutex */
780int set_regdom(const struct ieee80211_regdomain *rd) 1310int set_regdom(const struct ieee80211_regdomain *rd)
781{ 1311{
782 struct regulatory_request *this_request = NULL, *prev_request = NULL;
783 int r; 1312 int r;
784 1313
785 if (!list_empty(&regulatory_requests))
786 prev_request = list_first_entry(&regulatory_requests,
787 struct regulatory_request, list);
788
789 /* Note that this doesn't update the wiphys, this is done below */ 1314 /* Note that this doesn't update the wiphys, this is done below */
790 r = __set_regdom(rd); 1315 r = __set_regdom(rd);
791 if (r) 1316 if (r) {
1317 kfree(rd);
792 return r; 1318 return r;
793
794 BUG_ON((!__reg_is_valid_request(rd->alpha2, &this_request)));
795
796 /* The initial standard core update of the world regulatory domain, no
797 * need to keep that request info around if it didn't fail. */
798 if (is_world_regdom(rd->alpha2) &&
799 this_request->initiator == REGDOM_SET_BY_CORE &&
800 this_request->granted) {
801 list_del(&this_request->list);
802 kfree(this_request);
803 this_request = NULL;
804 }
805
806 /* Remove old requests, we only leave behind the last one */
807 if (prev_request) {
808 list_del(&prev_request->list);
809 kfree(prev_request);
810 prev_request = NULL;
811 } 1319 }
812 1320
813 /* This would make this whole thing pointless */ 1321 /* This would make this whole thing pointless */
814 BUG_ON(rd != cfg80211_regdomain); 1322 if (!last_request->intersect)
1323 BUG_ON(rd != cfg80211_regdomain);
815 1324
816 /* update all wiphys now with the new established regulatory domain */ 1325 /* update all wiphys now with the new established regulatory domain */
817 update_all_wiphy_regulatory(this_request->initiator); 1326 update_all_wiphy_regulatory(last_request->initiator);
818 1327
819 print_regdomain(rd); 1328 print_regdomain(cfg80211_regdomain);
820 1329
821 return r; 1330 return r;
822} 1331}
823 1332
1333/* Caller must hold cfg80211_drv_mutex */
1334void reg_device_remove(struct wiphy *wiphy)
1335{
1336 if (!last_request || !last_request->wiphy)
1337 return;
1338 if (last_request->wiphy != wiphy)
1339 return;
1340 last_request->wiphy = NULL;
1341 last_request->country_ie_env = ENVIRON_ANY;
1342}
1343
824int regulatory_init(void) 1344int regulatory_init(void)
825{ 1345{
826 int err; 1346 int err;
@@ -838,13 +1358,13 @@ int regulatory_init(void)
838 * you have CRDA you get it updated, otherwise you get 1358 * you have CRDA you get it updated, otherwise you get
839 * stuck with the static values. We ignore "EU" code as 1359 * stuck with the static values. We ignore "EU" code as
840 * that is not a valid ISO / IEC 3166 alpha2 */ 1360 * that is not a valid ISO / IEC 3166 alpha2 */
841 if (ieee80211_regdom[0] != 'E' && ieee80211_regdom[1] != 'U') 1361 if (ieee80211_regdom[0] != 'E' || ieee80211_regdom[1] != 'U')
842 err = __regulatory_hint(NULL, REGDOM_SET_BY_CORE, 1362 err = __regulatory_hint(NULL, REGDOM_SET_BY_CORE,
843 ieee80211_regdom, NULL); 1363 ieee80211_regdom, 0, ENVIRON_ANY);
844#else 1364#else
845 cfg80211_regdomain = cfg80211_world_regdom; 1365 cfg80211_regdomain = cfg80211_world_regdom;
846 1366
847 err = __regulatory_hint(NULL, REGDOM_SET_BY_CORE, "00", NULL); 1367 err = __regulatory_hint(NULL, REGDOM_SET_BY_CORE, "00", 0, ENVIRON_ANY);
848 if (err) 1368 if (err)
849 printk(KERN_ERR "cfg80211: calling CRDA failed - " 1369 printk(KERN_ERR "cfg80211: calling CRDA failed - "
850 "unable to update world regulatory domain, " 1370 "unable to update world regulatory domain, "
@@ -856,16 +1376,15 @@ int regulatory_init(void)
856 1376
857void regulatory_exit(void) 1377void regulatory_exit(void)
858{ 1378{
859 struct regulatory_request *req, *req_tmp;
860
861 mutex_lock(&cfg80211_drv_mutex); 1379 mutex_lock(&cfg80211_drv_mutex);
862 1380
863 reset_regdomains(); 1381 reset_regdomains();
864 1382
865 list_for_each_entry_safe(req, req_tmp, &regulatory_requests, list) { 1383 kfree(country_ie_regdomain);
866 list_del(&req->list); 1384 country_ie_regdomain = NULL;
867 kfree(req); 1385
868 } 1386 kfree(last_request);
1387
869 platform_device_unregister(reg_pdev); 1388 platform_device_unregister(reg_pdev);
870 1389
871 mutex_unlock(&cfg80211_drv_mutex); 1390 mutex_unlock(&cfg80211_drv_mutex);