]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - net/wireless/reg.c
592b2e391d42085686dc3a461b7bae61c05cc5d2
[linux-2.6-omap-h63xx.git] / net / wireless / reg.c
1 /*
2  * Copyright 2002-2005, Instant802 Networks, Inc.
3  * Copyright 2005-2006, Devicescape Software, Inc.
4  * Copyright 2007       Johannes Berg <johannes@sipsolutions.net>
5  * Copyright 2008       Luis R. Rodriguez <lrodriguz@atheros.com>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2 as
9  * published by the Free Software Foundation.
10  */
11
12 /**
13  * DOC: Wireless regulatory infrastructure
14  *
15  * The usual implementation is for a driver to read a device EEPROM to
16  * determine which regulatory domain it should be operating under, then
17  * looking up the allowable channels in a driver-local table and finally
18  * registering those channels in the wiphy structure.
19  *
20  * Another set of compliance enforcement is for drivers to use their
21  * own compliance limits which can be stored on the EEPROM. The host
22  * driver or firmware may ensure these are used.
23  *
24  * In addition to all this we provide an extra layer of regulatory
25  * conformance. For drivers which do not have any regulatory
26  * information CRDA provides the complete regulatory solution.
27  * For others it provides a community effort on further restrictions
28  * to enhance compliance.
29  *
30  * Note: When number of rules --> infinity we will not be able to
31  * index on alpha2 any more, instead we'll probably have to
32  * rely on some SHA1 checksum of the regdomain for example.
33  *
34  */
35 #include <linux/kernel.h>
36 #include <linux/list.h>
37 #include <linux/random.h>
38 #include <linux/nl80211.h>
39 #include <linux/platform_device.h>
40 #include <net/wireless.h>
41 #include <net/cfg80211.h>
42 #include "core.h"
43 #include "reg.h"
44
45 /* To trigger userspace events */
46 static struct platform_device *reg_pdev;
47
48 /* Keep the ordering from large to small */
49 static u32 supported_bandwidths[] = {
50         MHZ_TO_KHZ(40),
51         MHZ_TO_KHZ(20),
52 };
53
54 bool is_world_regdom(char *alpha2)
55 {
56         if (!alpha2)
57                 return false;
58         if (alpha2[0] == '0' && alpha2[1] == '0')
59                 return true;
60         return false;
61 }
62
63 static bool is_alpha2_set(char *alpha2)
64 {
65         if (!alpha2)
66                 return false;
67         if (alpha2[0] != 0 && alpha2[1] != 0)
68                 return true;
69         return false;
70 }
71
72 static bool is_alpha_upper(char letter)
73 {
74         /* ASCII A - Z */
75         if (letter >= 65 && letter <= 90)
76                 return true;
77         return false;
78 }
79
80 static bool is_unknown_alpha2(char *alpha2)
81 {
82         if (!alpha2)
83                 return false;
84         /* Special case where regulatory domain was built by driver
85          * but a specific alpha2 cannot be determined */
86         if (alpha2[0] == '9' && alpha2[1] == '9')
87                 return true;
88         return false;
89 }
90
91 static bool is_an_alpha2(char *alpha2)
92 {
93         if (!alpha2)
94                 return false;
95         if (is_alpha_upper(alpha2[0]) && is_alpha_upper(alpha2[1]))
96                 return true;
97         return false;
98 }
99
100 static bool alpha2_equal(char *alpha2_x, char *alpha2_y)
101 {
102         if (!alpha2_x || !alpha2_y)
103                 return false;
104         if (alpha2_x[0] == alpha2_y[0] &&
105                 alpha2_x[1] == alpha2_y[1])
106                 return true;
107         return false;
108 }
109
110 static bool regdom_changed(char *alpha2)
111 {
112         if (!cfg80211_regdomain)
113                 return true;
114         if (alpha2_equal(cfg80211_regdomain->alpha2, alpha2))
115                 return false;
116         return true;
117 }
118
119 /* This lets us keep regulatory code which is updated on a regulatory
120  * basis in userspace. */
121 static int call_crda(const char *alpha2)
122 {
123         char country_env[9 + 2] = "COUNTRY=";
124         char *envp[] = {
125                 country_env,
126                 NULL
127         };
128
129         if (!is_world_regdom((char *) alpha2))
130                 printk(KERN_INFO "cfg80211: Calling CRDA for country: %c%c\n",
131                         alpha2[0], alpha2[1]);
132         else
133 #ifdef CONFIG_WIRELESS_OLD_REGULATORY
134                 return -EINVAL;
135 #else
136                 printk(KERN_INFO "cfg80211: Calling CRDA to update world "
137                         "regulatory domain\n");
138 #endif
139
140         country_env[8] = alpha2[0];
141         country_env[9] = alpha2[1];
142
143         return kobject_uevent_env(&reg_pdev->dev.kobj, KOBJ_CHANGE, envp);
144 }
145
146 /* This has the logic which determines when a new request
147  * should be ignored. */
148 static int ignore_request(struct wiphy *wiphy, enum reg_set_by set_by,
149         char *alpha2, struct ieee80211_regdomain *rd)
150 {
151         struct regulatory_request *last_request = NULL;
152
153         /* All initial requests are respected */
154         if (list_empty(&regulatory_requests))
155                 return 0;
156
157         last_request = list_first_entry(&regulatory_requests,
158                 struct regulatory_request, list);
159
160         switch (set_by) {
161         case REGDOM_SET_BY_INIT:
162                 return -EINVAL;
163         case REGDOM_SET_BY_CORE:
164                 /* Always respect new wireless core hints, should only
165                  * come in for updating the world regulatory domain at init
166                  * anyway */
167                 return 0;
168         case REGDOM_SET_BY_COUNTRY_IE:
169                 if (last_request->initiator == set_by) {
170                         if (last_request->wiphy != wiphy) {
171                                 /* Two cards with two APs claiming different
172                                  * different Country IE alpha2s!
173                                  * You're special!! */
174                                 if (!alpha2_equal(last_request->alpha2,
175                                                 cfg80211_regdomain->alpha2)) {
176                                         /* XXX: Deal with conflict, consider
177                                          * building a new one out of the
178                                          * intersection */
179                                         WARN_ON(1);
180                                         return -EOPNOTSUPP;
181                                 }
182                                 return -EALREADY;
183                         }
184                         /* Two consecutive Country IE hints on the same wiphy */
185                         if (!alpha2_equal(cfg80211_regdomain->alpha2, alpha2))
186                                 return 0;
187                         return -EALREADY;
188                 }
189                 if (WARN_ON(!is_alpha2_set(alpha2) || !is_an_alpha2(alpha2)),
190                                 "Invalid Country IE regulatory hint passed "
191                                 "to the wireless core\n")
192                         return -EINVAL;
193                 /* We ignore Country IE hints for now, as we haven't yet
194                  * added the dot11MultiDomainCapabilityEnabled flag
195                  * for wiphys */
196                 return 1;
197         case REGDOM_SET_BY_DRIVER:
198                 BUG_ON(!wiphy);
199                 if (last_request->initiator == set_by) {
200                         /* Two separate drivers hinting different things,
201                          * this is possible if you have two devices present
202                          * on a system with different EEPROM regulatory
203                          * readings. XXX: Do intersection, we support only
204                          * the first regulatory hint for now */
205                         if (last_request->wiphy != wiphy)
206                                 return -EALREADY;
207                         if (rd)
208                                 return -EALREADY;
209                         /* Driver should not be trying to hint different
210                          * regulatory domains! */
211                         BUG_ON(!alpha2_equal(alpha2,
212                                         cfg80211_regdomain->alpha2));
213                         return -EALREADY;
214                 }
215                 if (last_request->initiator == REGDOM_SET_BY_CORE)
216                         return 0;
217                 /* XXX: Handle intersection, and add the
218                  * dot11MultiDomainCapabilityEnabled flag to wiphy. For now
219                  * we assume the driver has this set to false, following the
220                  * 802.11d dot11MultiDomainCapabilityEnabled documentation */
221                 if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE)
222                         return 0;
223                 return 0;
224         case REGDOM_SET_BY_USER:
225                 if (last_request->initiator == set_by ||
226                                 last_request->initiator == REGDOM_SET_BY_CORE)
227                         return 0;
228                 /* Drivers can use their wiphy's reg_notifier()
229                  * to override any information */
230                 if (last_request->initiator == REGDOM_SET_BY_DRIVER)
231                         return 0;
232                 /* XXX: Handle intersection */
233                 if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE)
234                         return -EOPNOTSUPP;
235                 return 0;
236         default:
237                 return -EINVAL;
238         }
239 }
240
241 static bool __reg_is_valid_request(char *alpha2,
242         struct regulatory_request **request)
243 {
244         struct regulatory_request *req;
245         if (list_empty(&regulatory_requests))
246                 return false;
247         list_for_each_entry(req, &regulatory_requests, list) {
248                 if (alpha2_equal(req->alpha2, alpha2)) {
249                         *request = req;
250                         return true;
251                 }
252         }
253         return false;
254 }
255
256 /* Used by nl80211 before kmalloc'ing our regulatory domain */
257 bool reg_is_valid_request(char *alpha2)
258 {
259         struct regulatory_request *request = NULL;
260         return  __reg_is_valid_request(alpha2, &request);
261 }
262
263 /* Sanity check on a regulatory rule */
264 static bool is_valid_reg_rule(struct ieee80211_reg_rule *rule)
265 {
266         struct ieee80211_freq_range *freq_range = &rule->freq_range;
267         u32 freq_diff;
268
269         if (freq_range->start_freq_khz == 0 || freq_range->end_freq_khz == 0)
270                 return false;
271
272         if (freq_range->start_freq_khz > freq_range->end_freq_khz)
273                 return false;
274
275         freq_diff = freq_range->end_freq_khz - freq_range->start_freq_khz;
276
277         if (freq_range->max_bandwidth_khz > freq_diff)
278                 return false;
279
280         return true;
281 }
282
283 static bool is_valid_rd(struct ieee80211_regdomain *rd)
284 {
285         struct ieee80211_reg_rule *reg_rule = NULL;
286         unsigned int i;
287
288         if (!rd->n_reg_rules)
289                 return false;
290
291         for (i = 0; i < rd->n_reg_rules; i++) {
292                 reg_rule = &rd->reg_rules[i];
293                 if (!is_valid_reg_rule(reg_rule))
294                         return false;
295         }
296
297         return true;
298 }
299
300 /* Returns value in KHz */
301 static u32 freq_max_bandwidth(const struct ieee80211_freq_range *freq_range,
302         u32 freq)
303 {
304         unsigned int i;
305         for (i = 0; i < ARRAY_SIZE(supported_bandwidths); i++) {
306                 u32 start_freq_khz = freq - supported_bandwidths[i]/2;
307                 u32 end_freq_khz = freq + supported_bandwidths[i]/2;
308                 if (start_freq_khz >= freq_range->start_freq_khz &&
309                         end_freq_khz <= freq_range->end_freq_khz)
310                         return supported_bandwidths[i];
311         }
312         return 0;
313 }
314
315 /* XXX: add support for the rest of enum nl80211_reg_rule_flags, we may
316  * want to just have the channel structure use these */
317 static u32 map_regdom_flags(u32 rd_flags)
318 {
319         u32 channel_flags = 0;
320         if (rd_flags & NL80211_RRF_PASSIVE_SCAN)
321                 channel_flags |= IEEE80211_CHAN_PASSIVE_SCAN;
322         if (rd_flags & NL80211_RRF_NO_IBSS)
323                 channel_flags |= IEEE80211_CHAN_NO_IBSS;
324         if (rd_flags & NL80211_RRF_DFS)
325                 channel_flags |= IEEE80211_CHAN_RADAR;
326         return channel_flags;
327 }
328
329 /**
330  * freq_reg_info - get regulatory information for the given frequency
331  * @center_freq: Frequency in KHz for which we want regulatory information for
332  * @bandwidth: the bandwidth requirement you have in KHz, if you do not have one
333  *      you can set this to 0. If this frequency is allowed we then set
334  *      this value to the maximum allowed bandwidth.
335  * @reg_rule: the regulatory rule which we have for this frequency
336  *
337  * Use this function to get the regulatory rule for a specific frequency.
338  */
339 static int freq_reg_info(u32 center_freq, u32 *bandwidth,
340                          const struct ieee80211_reg_rule **reg_rule)
341 {
342         int i;
343         u32 max_bandwidth = 0;
344
345         if (!cfg80211_regdomain)
346                 return -EINVAL;
347
348         for (i = 0; i < cfg80211_regdomain->n_reg_rules; i++) {
349                 const struct ieee80211_reg_rule *rr;
350                 const struct ieee80211_freq_range *fr = NULL;
351                 const struct ieee80211_power_rule *pr = NULL;
352
353                 rr = &cfg80211_regdomain->reg_rules[i];
354                 fr = &rr->freq_range;
355                 pr = &rr->power_rule;
356                 max_bandwidth = freq_max_bandwidth(fr, center_freq);
357                 if (max_bandwidth && *bandwidth <= max_bandwidth) {
358                         *reg_rule = rr;
359                         *bandwidth = max_bandwidth;
360                         break;
361                 }
362         }
363
364         return !max_bandwidth;
365 }
366
367 static void handle_channel(struct ieee80211_channel *chan)
368 {
369         int r;
370         u32 flags = chan->orig_flags;
371         u32 max_bandwidth = 0;
372         const struct ieee80211_reg_rule *reg_rule = NULL;
373         const struct ieee80211_power_rule *power_rule = NULL;
374
375         r = freq_reg_info(MHZ_TO_KHZ(chan->center_freq),
376                 &max_bandwidth, &reg_rule);
377
378         if (r) {
379                 flags |= IEEE80211_CHAN_DISABLED;
380                 chan->flags = flags;
381                 return;
382         }
383
384         power_rule = &reg_rule->power_rule;
385
386         chan->flags = flags | map_regdom_flags(reg_rule->flags);
387         chan->max_antenna_gain = min(chan->orig_mag,
388                 (int) MBI_TO_DBI(power_rule->max_antenna_gain));
389         chan->max_bandwidth = KHZ_TO_MHZ(max_bandwidth);
390         if (chan->orig_mpwr)
391                 chan->max_power = min(chan->orig_mpwr,
392                         (int) MBM_TO_DBM(power_rule->max_eirp));
393         else
394                 chan->max_power = (int) MBM_TO_DBM(power_rule->max_eirp);
395 }
396
397 static void handle_band(struct ieee80211_supported_band *sband)
398 {
399         int i;
400
401         for (i = 0; i < sband->n_channels; i++)
402                 handle_channel(&sband->channels[i]);
403 }
404
405 static void update_all_wiphy_regulatory(enum reg_set_by setby)
406 {
407         struct cfg80211_registered_device *drv;
408
409         list_for_each_entry(drv, &cfg80211_drv_list, list)
410                 wiphy_update_regulatory(&drv->wiphy, setby);
411 }
412
413 void wiphy_update_regulatory(struct wiphy *wiphy, enum reg_set_by setby)
414 {
415         enum ieee80211_band band;
416         for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
417                 if (wiphy->bands[band])
418                         handle_band(wiphy->bands[band]);
419                 if (wiphy->reg_notifier)
420                         wiphy->reg_notifier(wiphy, setby);
421         }
422 }
423
424 /* Caller must hold &cfg80211_drv_mutex */
425 int __regulatory_hint(struct wiphy *wiphy, enum reg_set_by set_by,
426                       const char *alpha2, struct ieee80211_regdomain *rd)
427 {
428         struct regulatory_request *request;
429         char *rd_alpha2;
430         int r = 0;
431
432         r = ignore_request(wiphy, set_by, (char *) alpha2, rd);
433         if (r)
434                 return r;
435
436         if (rd)
437                 rd_alpha2 = rd->alpha2;
438         else
439                 rd_alpha2 = (char *) alpha2;
440
441         switch (set_by) {
442         case REGDOM_SET_BY_CORE:
443         case REGDOM_SET_BY_COUNTRY_IE:
444         case REGDOM_SET_BY_DRIVER:
445         case REGDOM_SET_BY_USER:
446                 request = kzalloc(sizeof(struct regulatory_request),
447                         GFP_KERNEL);
448                 if (!request)
449                         return -ENOMEM;
450
451                 request->alpha2[0] = rd_alpha2[0];
452                 request->alpha2[1] = rd_alpha2[1];
453                 request->initiator = set_by;
454                 request->wiphy = wiphy;
455
456                 list_add_tail(&request->list, &regulatory_requests);
457                 if (rd)
458                         break;
459                 r = call_crda(alpha2);
460 #ifndef CONFIG_WIRELESS_OLD_REGULATORY
461                 if (r)
462                         printk(KERN_ERR "cfg80211: Failed calling CRDA\n");
463 #endif
464                 break;
465         default:
466                 r = -ENOTSUPP;
467                 break;
468         }
469
470         return r;
471 }
472
473 /* If rd is not NULL and if this call fails the caller must free it */
474 int regulatory_hint(struct wiphy *wiphy, const char *alpha2,
475         struct ieee80211_regdomain *rd)
476 {
477         int r;
478         BUG_ON(!rd && !alpha2);
479
480         mutex_lock(&cfg80211_drv_mutex);
481
482         r = __regulatory_hint(wiphy, REGDOM_SET_BY_DRIVER, alpha2, rd);
483         if (r || !rd)
484                 goto unlock_and_exit;
485
486         /* If the driver passed a regulatory domain we skipped asking
487          * userspace for one so we can now go ahead and set it */
488         r = set_regdom(rd);
489
490 unlock_and_exit:
491         mutex_unlock(&cfg80211_drv_mutex);
492         return r;
493 }
494 EXPORT_SYMBOL(regulatory_hint);
495
496
497 static void print_rd_rules(struct ieee80211_regdomain *rd)
498 {
499         unsigned int i;
500         struct ieee80211_reg_rule *reg_rule = NULL;
501         struct ieee80211_freq_range *freq_range = NULL;
502         struct ieee80211_power_rule *power_rule = NULL;
503
504         printk(KERN_INFO "\t(start_freq - end_freq @ bandwidth), "
505                 "(max_antenna_gain, max_eirp)\n");
506
507         for (i = 0; i < rd->n_reg_rules; i++) {
508                 reg_rule = &rd->reg_rules[i];
509                 freq_range = &reg_rule->freq_range;
510                 power_rule = &reg_rule->power_rule;
511
512                 /* There may not be documentation for max antenna gain
513                  * in certain regions */
514                 if (power_rule->max_antenna_gain)
515                         printk(KERN_INFO "\t(%d KHz - %d KHz @ %d KHz), "
516                                 "(%d mBi, %d mBm)\n",
517                                 freq_range->start_freq_khz,
518                                 freq_range->end_freq_khz,
519                                 freq_range->max_bandwidth_khz,
520                                 power_rule->max_antenna_gain,
521                                 power_rule->max_eirp);
522                 else
523                         printk(KERN_INFO "\t(%d KHz - %d KHz @ %d KHz), "
524                                 "(N/A, %d mBm)\n",
525                                 freq_range->start_freq_khz,
526                                 freq_range->end_freq_khz,
527                                 freq_range->max_bandwidth_khz,
528                                 power_rule->max_eirp);
529         }
530 }
531
532 static void print_regdomain(struct ieee80211_regdomain *rd)
533 {
534
535         if (is_world_regdom(rd->alpha2))
536                 printk(KERN_INFO "cfg80211: World regulatory "
537                         "domain updated:\n");
538         else {
539                 if (is_unknown_alpha2(rd->alpha2))
540                         printk(KERN_INFO "cfg80211: Regulatory domain "
541                                 "changed to driver built-in settings "
542                                 "(unknown country)\n");
543                 else
544                         printk(KERN_INFO "cfg80211: Regulatory domain "
545                                 "changed to country: %c%c\n",
546                                 rd->alpha2[0], rd->alpha2[1]);
547         }
548         print_rd_rules(rd);
549 }
550
551 void print_regdomain_info(struct ieee80211_regdomain *rd)
552 {
553         printk(KERN_INFO "cfg80211: Regulatory domain: %c%c\n",
554                 rd->alpha2[0], rd->alpha2[1]);
555         print_rd_rules(rd);
556 }
557
558 #ifdef CONFIG_WIRELESS_OLD_REGULATORY
559
560 static bool is_old_static_regdom(struct ieee80211_regdomain *rd)
561 {
562         if (rd == &us_regdom || rd == &jp_regdom || rd == &eu_regdom)
563                 return true;
564         return false;
565 }
566
567 /* The old crap never deals with a world regulatory domain, it only
568  * deals with the static regulatory domain passed and if possible
569  * an updated "US" or "JP" regulatory domain. We do however store the
570  * old static regulatory domain in cfg80211_world_regdom for convenience
571  * of use here */
572 static void reset_regdomains_static(void)
573 {
574         if (!is_old_static_regdom(cfg80211_regdomain))
575                 kfree(cfg80211_regdomain);
576         /* This is setting the regdom to the old static regdom */
577         cfg80211_regdomain =
578                 (struct ieee80211_regdomain *) cfg80211_world_regdom;
579 }
580 #else
581 static void reset_regdomains(void)
582 {
583         if (cfg80211_world_regdom && cfg80211_world_regdom != &world_regdom) {
584                 if (cfg80211_world_regdom == cfg80211_regdomain) {
585                         kfree(cfg80211_regdomain);
586                 } else {
587                         kfree(cfg80211_world_regdom);
588                         kfree(cfg80211_regdomain);
589                 }
590         } else if (cfg80211_regdomain && cfg80211_regdomain != &world_regdom)
591                 kfree(cfg80211_regdomain);
592
593         cfg80211_world_regdom = (struct ieee80211_regdomain *) &world_regdom;
594         cfg80211_regdomain = NULL;
595 }
596
597 /* Dynamic world regulatory domain requested by the wireless
598  * core upon initialization */
599 static void update_world_regdomain(struct ieee80211_regdomain *rd)
600 {
601         BUG_ON(list_empty(&regulatory_requests));
602
603         reset_regdomains();
604
605         cfg80211_world_regdom = rd;
606         cfg80211_regdomain = rd;
607 }
608 #endif
609
610 static int __set_regdom(struct ieee80211_regdomain *rd)
611 {
612         struct regulatory_request *request = NULL;
613
614         /* Some basic sanity checks first */
615
616 #ifdef CONFIG_WIRELESS_OLD_REGULATORY
617         /* We ignore the world regdom with the old static regdomains setup
618          * as there is no point to it with satic regulatory definitions :(
619          * Don't worry this shit will be removed soon... */
620         if (is_world_regdom(rd->alpha2))
621                 return -EINVAL;
622 #else
623         if (is_world_regdom(rd->alpha2)) {
624                 if (WARN_ON(!__reg_is_valid_request(rd->alpha2, &request)))
625                         return -EINVAL;
626                 update_world_regdomain(rd);
627                 return 0;
628         }
629 #endif
630
631         if (!is_alpha2_set(rd->alpha2) && !is_an_alpha2(rd->alpha2) &&
632                         !is_unknown_alpha2(rd->alpha2))
633                 return -EINVAL;
634
635         if (list_empty(&regulatory_requests))
636                 return -EINVAL;
637
638 #ifdef CONFIG_WIRELESS_OLD_REGULATORY
639         /* Static "US" and "JP" will be overridden, but just once */
640         if (!is_old_static_regdom(cfg80211_regdomain) &&
641                         !regdom_changed(rd->alpha2))
642                 return -EINVAL;
643 #else
644         if (!regdom_changed(rd->alpha2))
645                 return -EINVAL;
646 #endif
647
648         /* Now lets set the regulatory domain, update all driver channels
649          * and finally inform them of what we have done, in case they want
650          * to review or adjust their own settings based on their own
651          * internal EEPROM data */
652
653         if (WARN_ON(!__reg_is_valid_request(rd->alpha2, &request)))
654                 return -EINVAL;
655
656 #ifdef CONFIG_WIRELESS_OLD_REGULATORY
657         reset_regdomains_static();
658 #else
659         reset_regdomains();
660 #endif
661
662         /* Country IE parsing coming soon */
663         switch (request->initiator) {
664         case REGDOM_SET_BY_CORE:
665         case REGDOM_SET_BY_DRIVER:
666         case REGDOM_SET_BY_USER:
667                 if (!is_valid_rd(rd)) {
668                         printk(KERN_ERR "cfg80211: Invalid "
669                                 "regulatory domain detected:\n");
670                         print_regdomain_info(rd);
671                         return -EINVAL;
672                 }
673                 break;
674         case REGDOM_SET_BY_COUNTRY_IE: /* Not yet */
675                 WARN_ON(1);
676         default:
677                 return -EOPNOTSUPP;
678         }
679
680         /* Tada! */
681         cfg80211_regdomain = rd;
682         request->granted = 1;
683
684         return 0;
685 }
686
687
688 /* Use this call to set the current regulatory domain. Conflicts with
689  * multiple drivers can be ironed out later. Caller must've already
690  * kmalloc'd the rd structure. If this calls fails you should kfree()
691  * the passed rd. Caller must hold cfg80211_drv_mutex */
692 int set_regdom(struct ieee80211_regdomain *rd)
693 {
694         struct regulatory_request *this_request = NULL, *prev_request = NULL;
695         int r;
696
697         if (!list_empty(&regulatory_requests))
698                 prev_request = list_first_entry(&regulatory_requests,
699                         struct regulatory_request, list);
700
701         /* Note that this doesn't update the wiphys, this is done below */
702         r = __set_regdom(rd);
703         if (r)
704                 return r;
705
706         BUG_ON((!__reg_is_valid_request(rd->alpha2, &this_request)));
707
708         /* The initial standard core update of the world regulatory domain, no
709          * need to keep that request info around if it didn't fail. */
710         if (is_world_regdom(rd->alpha2) &&
711                         this_request->initiator == REGDOM_SET_BY_CORE &&
712                         this_request->granted) {
713                 list_del(&this_request->list);
714                 kfree(this_request);
715                 this_request = NULL;
716         }
717
718         /* Remove old requests, we only leave behind the last one */
719         if (prev_request) {
720                 list_del(&prev_request->list);
721                 kfree(prev_request);
722                 prev_request = NULL;
723         }
724
725         /* This would make this whole thing pointless */
726         BUG_ON(rd != cfg80211_regdomain);
727
728         /* update all wiphys now with the new established regulatory domain */
729         update_all_wiphy_regulatory(this_request->initiator);
730
731         print_regdomain(rd);
732
733         return r;
734 }
735
736 int regulatory_init(void)
737 {
738         reg_pdev = platform_device_register_simple("regulatory", 0, NULL, 0);
739         if (IS_ERR(reg_pdev))
740                 return PTR_ERR(reg_pdev);
741         return 0;
742 }
743
744 void regulatory_exit(void)
745 {
746         struct regulatory_request *req, *req_tmp;
747         mutex_lock(&cfg80211_drv_mutex);
748 #ifdef CONFIG_WIRELESS_OLD_REGULATORY
749         reset_regdomains_static();
750 #else
751         reset_regdomains();
752 #endif
753         list_for_each_entry_safe(req, req_tmp, &regulatory_requests, list) {
754                 list_del(&req->list);
755                 kfree(req);
756         }
757         platform_device_unregister(reg_pdev);
758         mutex_unlock(&cfg80211_drv_mutex);
759 }