* Re: [RFC] [PATCH 2/3] adds ieee80211_regdomains support
@ 2006-10-23 22:47 Luis R. Rodriguez
2006-10-24 8:33 ` Johannes Berg
2006-10-25 2:07 ` Anand Kumria
0 siblings, 2 replies; 5+ messages in thread
From: Luis R. Rodriguez @ 2006-10-23 22:47 UTC (permalink / raw)
To: netdev; +Cc: Jiri Benc, John W. Linville, Jean Tourrilhes
[-- Attachment #1: Type: text/plain, Size: 481 bytes --]
ieee80211_regdomains
Breaks down regulatory domains into data structures which allow
drivers to share channel and power contraints based on stack
regulatory domain. This driver adds in-kernel support for common
regulatory domains (such as FCC and ETSI), makes updating the
regulatory domain database through userspace completely optional which
should make it easier to introduce, and adds support for PtMP (Point
to MultiPoint) and PtP (Point to Point) type restrictions.
Luis
[-- Attachment #2: patch-02-ieee80211_regdomains.diff --]
[-- Type: text/x-patch, Size: 47661 bytes --]
diff -Naurp wireless-dev-old/include/net/d80211_regdomains.h wireless-dev/include/net/d80211_regdomains.h
--- wireless-dev-old/include/net/d80211_regdomains.h 1969-12-31 19:00:00.000000000 -0500
+++ wireless-dev/include/net/d80211_regdomains.h 2006-10-23 16:55:19.000000000 -0400
@@ -0,0 +1,210 @@
+#ifndef _IEEE80211_REGDOMAIN_H
+#define _IEEE80211_REGDOMAIN_H
+/*
+ * Copyright (C) 2006 Luis R. Rodriguez <mcgrof@winlab.rutgers.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <net/d80211.h>
+#include <net/d80211_iso3166-1.h>
+
+#define IEEE80211_REGDOMAINS_VERSION "0.9"
+
+/* Max default power for Equivalent Isotropically Radiated Power (EIRP)
+ * EIRP = IR - loss in transmission line + passive gain of the antenna */
+#define MAX_DF_80211_EIRP_POWER 20 /* 20dBm (100mW) */
+/* Regulatory domain name size */
+#define REGNAMSIZ 22
+
+#define CHANNEL_24MHZ_FREQ(chan) (chan == 14) ? 2484 : ((2407 + (5 * (chan))))
+#define CHANNEL_5MHZ_FREQ(chan) \
+ (chan >= 240 && chan <= 252) ? 5000 - (5 * (chan)) : 5000 + (5 * (chan))
+
+/* Most 5GHz band 802.11a channels restrictions skip channels 65-148 */
+#define number_80211a_channels_defaults(amin, amax) \
+ (((amax - 149 + 4) + (64 - amin + 4)) / 4)
+
+/* Stack regulatory domain values. Atheros seems to have started this
+ * convention and most hardware vendors followed their example.
+ * Although these are *very* common we allow for a hw-specific
+ * map between stack and device regdomain values. */
+enum stack_regdomain {
+ REGDOMAIN_WORLD = 0x00, /* World compliance, minimum set */
+ REGDOMAIN_FCC = 0x10, /* USA */
+ REGDOMAIN_IC = 0x20, /* Canada */
+ REGDOMAIN_ETSI = 0x30, /* Europe */
+ REGDOMAIN_SPAIN = 0x31, /* Spain */
+ REGDOMAIN_FRANCE = 0x32, /* France */
+ REGDOMAIN_MKK = 0x40, /* Japan */
+};
+
+struct ieee80211_regdomain {
+ u32 regdomain_id; /* stack-aware value */
+ char regdomain_name[REGNAMSIZ]; /* stack-aware value */
+ struct list_head list; /* node, part of ieee80211_regdomain_list */
+ /* List of supported bands (struct ieee80211_band_restrictions) */
+ struct list_head band_restrictions_list;
+};
+
+enum ieee80211_band {
+ IEEE80211_BAND_24GHZ = 0,
+ IEEE80211_BAND_5GHZ,
+ IEEE80211_NUM_SUPPORTED_BANDS, /* stack supported bands */
+};
+
+struct ieee80211_band_restrictions {
+ enum ieee80211_band band; /* IEEE80211_BAND_24GHZ, IEEE80211_BAND_5GHZ */
+ /* node, part of band_restrictions_list */
+ struct list_head list;
+ /* list of subband restrictions for PtMP (Point to MultiPoint)
+ * (struct ieee80211_subband_restrictions) */
+ struct list_head subband_restrictions_list;
+ /* list of subband restrictions for PtP (Point to Point)
+ * (struct ieee80211_subband_restrictions) */
+ struct list_head subband_restrictions_list_p2p;
+};
+
+enum subband_type {
+ IEEE80211_SUBBAND_RANGE = 0, /* for sequential channels */
+ IEEE80211_SUBBAND_SET, /* non sequential set of channels */
+};
+
+#define IEEE80211_SUBBAND_INDOOR_CAP (1 << 1)
+#define IEEE80211_SUBBAND_OUTDOOR_CAP (1 << 2)
+
+/* A subband is a set of channels with a shared set of common values.
+ * Channels who have the same:
+ * - type
+ * - mode
+ * - environment cap
+ * belong to the same subband */
+struct ieee80211_subband_restrictions {
+ enum subband_type type;
+ /* XXX: patch d80211 to make mode enum available, use here then */
+ u8 mode; /* MODE_IEEE80211A, MODE_IEEE80211B, MODE_IEEE80211G, etc */
+ u8 environment_cap; /* indoor and outdoor capabilities */
+ /* For power we use Equivalent Isotropically Radiated Power (EIRP)
+ * EIRP is the total radiated power. Each device driver should specify their
+ * antenna gain. The IR can then be computed approx as:
+ * IR = regdomain EIRP - passive gain of antenna
+ */
+ u8 max_eirp_indoor; /* maximum allowed power in dBm */
+ u8 max_eirp_outdoor; /* maximum allowed power in dBm */
+ u8 num_channels; /* avoid 5GHz channel hop arithmetic mess */
+ u8 min_chan; /* what channel regdomain starts in */
+ u8 max_chan; /* what channel regdomain end in */
+ /* node, part of subband_restrictions_list */
+ struct list_head list;
+ /* list of channels (struct ieee80211_regdomain_channel) */
+ struct list_head channel_list;
+};
+
+/* Wrapper to make ieee80211_channel a list node, part of a channel_list */
+/* XXX: consider putting a struct list_head on ieee80211_channel to
+ * remove this struct */
+struct ieee80211_regdomain_channel {
+ struct list_head list;
+ struct ieee80211_channel channel;
+};
+
+
+/* Now we define regulatory domain maps for the Stack -->
+ * I. iso3166-1 alpha3
+ * II. Device hw regdomains
+ */
+
+/* I. Generic stack isocountry --> regulatory domain map */
+struct ieee80211_iso3166_reg_map {
+ u32 regdomain_id; /* stack-aware value */
+ /* Used as 802.11d uses 3 octects for Country Information Element,
+ * this should be the ISO-3166-1 alpha 3 codes */
+ char alpha3[ISOCOUNTRYSIZ3];
+ struct list_head list; /* node, part of iso3166_reg_map_list */
+};
+
+/* II. Device specific - stack regdomain --> hw regdomain map */
+struct ieee80211_regulatory_map {
+ char hwreg_reg_mapname[ISOCOUNTRYSIZ];
+ struct list_head hwreg_map_list; /* struct ieee80211_hwreg_map */
+ struct list_head list; /* node, part of ieee80211_regulatory_maps */
+};
+struct ieee80211_hwreg_map {
+ u32 regdomain_id; /* stack-aware value */
+ u32 regdomain_id_hw; /* hw regdomain equivalent */
+ struct list_head list; /* node, part of hwreg_reg_maps_list */
+};
+
+static inline int number_80211a_channels(int amin, int amax){
+ if(amin > 64 || amax < 149)
+ return -1;
+ else
+ return number_80211a_channels_defaults(amin, amax);
+}
+
+static inline int check_reg_addition(int, char *);
+int regdomain_name_valid(char *);
+int regdomain_exists(int, char *);
+static inline void setup_regdomain(struct ieee80211_regdomain *, u8 ,char *);
+static inline void setup_band_restrictions(
+ struct ieee80211_band_restrictions *b,
+ enum ieee80211_band band);
+static inline void setup_subband_restrictions(
+ struct ieee80211_subband_restrictions *,
+ enum subband_type, u8, u8, u8, u8, u8, u8, u8);
+static void free_regdomains(void);
+static int add_regdomain_bga(u8 reg_id, char *reg_name,
+ u8 channel_min_g, u8 channel_max_g,
+ u8 channel_min_a, u8 channel_max_a);
+void print_regdomain(struct ieee80211_regdomain *);
+void print_regdomains(void);
+void print_iso3166_reg_map(void);
+void print_hwreg_reg_map(void);
+int get_ieee80211_regname(u32, char *);
+static int load_user_regdomains(void);
+static int load_regdomain_defaults(void);
+static int update_ieee80211_regdomains(void);
+
+
+int alpha3_valid(char *);
+int add_iso3166_reg_map(char *, u32);
+inline int iso3166_to_reg_exists(char *);
+int iso3166_to_reg(char *, u32);
+
+/* TODO: Complete 802.11d support */
+#ifdef CONFIG_IEEE80211D
+/* You are either:
+ * IEEE80211D_NON_CONFORMING not conforming to 802.11d or any regdomain
+ * IEEE80211D_MINIMUM conforming to world regulatory domain
+ * IEEE80211D_REGULATORY conforming to a regulatory domain on list
+ * IEEE80211D_BSS_REQUEST your BSS has requested to conform to 802.11d
+ * IEEE80211D_COMFORMING joined BSS which offers 802.11d conformance
+ * */
+enum ieee80211d_status {
+ IEEE80211D_NON_CONFORMING = 0,
+ IEEE80211D_MINIMUM,
+ IEEE80211D_REGULATORY,
+ IEEE80211D_BSS_REQUEST,
+ IEEE80211D_COMFORMING,
+};
+
+/* 802.11d conformance */
+struct ieee80211d_conformance {
+ char alpha3[ISOCOUNTRYSIZ3]; /* captured from BSS */
+ enum ieee80211d_status status; /* describes 802.11d/regulatory status */
+};
+#endif /* CONFIG_IEEE80211D */
+
+#endif
diff -Naurp wireless-dev-old/net/d80211/ieee80211_regdomains.c wireless-dev/net/d80211/ieee80211_regdomains.c
--- wireless-dev-old/net/d80211/ieee80211_regdomains.c 1969-12-31 19:00:00.000000000 -0500
+++ wireless-dev/net/d80211/ieee80211_regdomains.c 2006-10-23 17:03:53.000000000 -0400
@@ -0,0 +1,1325 @@
+/*
+ * Copyright (C) 2006 Luis R. Rodriguez <mcgrof@winlab.rutgers.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <net/d80211_regdomains.h>
+
+#define DRV_NAME "ieee80211_regdomains"
+#define DRV_DESCRIPTION "IEEE-802.11 Regulatory Domain wireless stack driver"
+#define DRV_VERSION IEEE80211_REGDOMAINS_VERSION
+
+MODULE_AUTHOR("Luis R. Rodriguez <mcgrof@winlab.rutgers.edu>");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION(DRV_DESCRIPTION);
+MODULE_VERSION(DRV_VERSION);
+
+/* Default supported list of regulatory domains */
+LIST_HEAD(ieee80211_regdomains_list);
+/* Map of iso3166-alpha3 country codes to specific stack regdomain */
+LIST_HEAD(iso3166_reg_map_list);
+/* List of available hwreg->reg maps which devices adhere to */
+LIST_HEAD(ieee80211_reg_map_list);
+
+rwlock_t regdomain_rwlock = RW_LOCK_UNLOCKED;
+rwlock_t iso3166_reg_rwlock = RW_LOCK_UNLOCKED;
+rwlock_t reg_map_rwlock = RW_LOCK_UNLOCKED;
+
+static inline void setup_regdomain(struct ieee80211_regdomain *r,
+ u8 regdomain_id, char *regdomain_name)
+{
+ strcpy(r->regdomain_name, regdomain_name);
+ r->regdomain_id = regdomain_id;
+}
+
+static inline void setup_band_restrictions(
+ struct ieee80211_band_restrictions *b,
+ enum ieee80211_band band)
+{
+ b->band = band;
+}
+
+static inline void setup_subband_restrictions(
+ struct ieee80211_subband_restrictions *sb,
+ enum subband_type type, u8 mode,
+ u8 min_chan, u8 max_chan, u8 num_channels,
+ u8 max_eirp_indoor, u8 max_eirp_outdoor,
+ u8 environment_cap)
+{
+ sb->type = type;
+ sb->mode = mode;
+ sb->environment_cap = environment_cap;
+ sb->max_eirp_indoor = max_eirp_indoor;
+ sb->max_eirp_outdoor = max_eirp_outdoor;
+ sb->min_chan = min_chan;
+ sb->max_chan = max_chan;
+ sb->num_channels= num_channels;
+}
+
+static inline void setup_reg_channel(
+ struct ieee80211_regdomain_channel *reg_chan,
+ enum ieee80211_band band,
+ short channel)
+{
+ struct ieee80211_channel *chan = ®_chan->channel;
+ chan->chan = channel;
+ chan->val = channel;
+ chan->flag = IEEE80211_CHAN_W_SCAN |
+ IEEE80211_CHAN_W_ACTIVE_SCAN |
+ IEEE80211_CHAN_W_IBSS;
+ switch(band){
+ case IEEE80211_BAND_5GHZ:
+ chan->freq = CHANNEL_5MHZ_FREQ(channel);
+ break;
+ case IEEE80211_BAND_24GHZ:
+ default:
+ chan->freq = CHANNEL_24MHZ_FREQ(channel);
+ break;
+ }
+}
+
+int regdomain_name_valid(char *regdomain_name) {
+ if(strlen(regdomain_name) >= REGNAMSIZ)
+ return 0;
+ return 1;
+}
+
+/* Expects you to hold lock */
+int regdomain_exists(int regdomain_id, char *regdomain_name)
+{
+ struct ieee80211_regdomain *reg;
+ int r = 0;
+ if(!regdomain_name_valid(regdomain_name)) {
+ r = 4;
+ return r;
+ }
+ if (unlikely(list_empty(&ieee80211_regdomains_list)))
+ return r;
+ list_for_each_entry(reg, &ieee80211_regdomains_list, list) {
+ if(reg->regdomain_id == regdomain_id)
+ r++;
+ if(strcmp(reg->regdomain_name, regdomain_name)==0)
+ r+=2;
+ if(r>0)
+ break;
+ }
+ return r;
+}
+
+static int alloc_reg_bands_subbands(struct ieee80211_regdomain **reg,
+ struct ieee80211_band_restrictions *bands[], int num_bands,
+ struct ieee80211_subband_restrictions *subbands[], int num_subs)
+{
+ int b_num, s_num, i;
+ struct ieee80211_band_restrictions *band;
+ struct ieee80211_subband_restrictions *subband;
+
+ /* Alloc regdomain */
+ *reg = kmalloc(sizeof(struct ieee80211_regdomain), GFP_KERNEL);
+ if (*reg == NULL)
+ goto exit;
+ memset(*reg, 0, sizeof(struct ieee80211_regdomain));
+
+ /* Alloc band restrictions */
+ for(b_num = 0; b_num < num_bands; b_num++) {
+ band = kmalloc(sizeof(struct ieee80211_band_restrictions),
+ GFP_KERNEL);
+ if (band == NULL)
+ goto free_bands;
+ memset(band, 0, sizeof(struct ieee80211_band_restrictions));
+ bands[b_num] = band;
+ }
+
+ /* Alloc subband restrictions */
+ for(s_num = 0; s_num < num_subs; s_num++) {
+ subband=kmalloc(sizeof(struct ieee80211_subband_restrictions),
+ GFP_KERNEL);
+ if (subband == NULL)
+ goto free_subbands;
+ memset(subband, 0,
+ sizeof(struct ieee80211_subband_restrictions));
+ subbands[s_num] = subband;
+ }
+
+ return 0;
+
+free_subbands:
+ for(i=0; i < s_num; i++)
+ kfree(subbands[i]);
+free_bands:
+ for(i=0; i < b_num; i++)
+ kfree(bands[i]);
+ kfree(*reg);
+exit:
+ return -ENOMEM;
+}
+
+static void free_subband_channel_list(struct list_head *channel_list)
+{
+ struct ieee80211_regdomain_channel *reg_chan, *reg_chan_tmp;
+ list_for_each_entry_safe(reg_chan, reg_chan_tmp, channel_list, list) {
+ list_del(®_chan->list);
+ kfree(reg_chan);
+ }
+}
+
+static void free_regdomains(void)
+{
+ struct ieee80211_regdomain *reg, *reg_tmp;
+ struct ieee80211_band_restrictions *b, *b_tmp;
+ struct ieee80211_subband_restrictions *sb, *sb_tmp;
+ list_for_each_entry_safe(reg,reg_tmp,&ieee80211_regdomains_list,list) {
+ list_del(®->list);
+ list_for_each_entry_safe(b,b_tmp,®->band_restrictions_list,list) {
+ list_del(&b->list);
+ list_for_each_entry_safe(sb,sb_tmp,&b->subband_restrictions_list,list){
+ list_del(&sb->list);
+ free_subband_channel_list(&sb->channel_list);
+ kfree(sb);
+ }
+ kfree(b);
+ }
+ kfree(reg);
+ }
+}
+
+static void free_iso3166_reg_map_list(void)
+{
+ struct ieee80211_iso3166_reg_map *map, *tmp;
+ list_for_each_entry_safe(map, tmp, &iso3166_reg_map_list, list) {
+ list_del(&map->list);
+ kfree(map);
+ }
+}
+
+
+static void free_hwreg_reg_maps(void)
+{
+ struct ieee80211_regulatory_map *map, *tmp;
+ struct ieee80211_hwreg_map *hwreg_map, *hw_tmp;
+
+ list_for_each_entry_safe(map, tmp, &ieee80211_reg_map_list, list) {
+ list_for_each_entry_safe(hwreg_map, hw_tmp,
+ &map->hwreg_map_list, list) {
+ list_del(&hwreg_map->list);
+ kfree(hwreg_map);
+ }
+ list_del(&map->list);
+ kfree(map);
+ }
+}
+
+static int add_regdomain_world(void)
+{
+ int r = -ENOMEM, i, num_sbs = 4;
+ short chan;
+ struct ieee80211_regdomain *reg = NULL;
+ u32 reg_id = REGDOMAIN_WORLD;
+ char *reg_name = "World compliance";
+
+ struct ieee80211_band_restrictions *bands[2];
+ struct ieee80211_subband_restrictions *subbands[num_sbs];
+
+ struct ieee80211_band_restrictions *b24r;
+ struct ieee80211_band_restrictions *b5r;
+ struct ieee80211_subband_restrictions *ism24;
+ struct ieee80211_subband_restrictions *unii_1;
+ struct ieee80211_subband_restrictions *unii_2;
+ struct ieee80211_subband_restrictions *unii_3;
+
+ read_lock(®domain_rwlock);
+ r = regdomain_exists(reg_id, reg_name);
+ if(r) {
+ read_unlock(®domain_rwlock);
+ goto exit;
+ }
+ read_unlock(®domain_rwlock);
+
+ r = alloc_reg_bands_subbands(®, bands, 2, subbands, num_sbs);
+ if (r)
+ goto exit;
+
+ /* "Who's your daddy and what does he do?" */
+ b24r = bands[0];
+ b5r = bands[1];
+ ism24 = subbands[0];
+ unii_1 = subbands[1];
+ unii_2 = subbands[2];
+ unii_3 = subbands[3];
+
+ /* Setup regdomain, bands and subbands */
+ setup_regdomain(reg, REGDOMAIN_WORLD, reg_name);
+ setup_band_restrictions(b24r, IEEE80211_BAND_24GHZ);
+ setup_band_restrictions(b5r, IEEE80211_BAND_5GHZ);
+
+ /* As per FCC 15.247 */
+
+ /* ISM 2.4 GHz Band */
+ setup_subband_restrictions(ism24,
+ IEEE80211_SUBBAND_RANGE, MODE_IEEE80211G,
+ /* min_chan */ 1,
+ /* max_chan */ 11,
+ /* num,_channels */ 11,
+ /* max_eirp_indoor */ MAX_DF_80211_EIRP_POWER,
+ /* max_eirp_outdoor */ 0,
+ IEEE80211_SUBBAND_INDOOR_CAP);
+
+ /* UNII-1 Band (5150 - 5250 MHz) */
+ setup_subband_restrictions(unii_1,
+ IEEE80211_SUBBAND_RANGE, MODE_IEEE80211A,
+ /* min_chan */ 36,
+ /* max_chan */ 48,
+ /* num,_channels */ 4,
+ /* max_eirp_indoor */ MAX_DF_80211_EIRP_POWER,
+ /* max_eirp_outdoor */ 0,
+ IEEE80211_SUBBAND_INDOOR_CAP);
+
+ /* UNII-2 Band (5250 - 5350 MHz) */
+ setup_subband_restrictions(unii_2,
+ IEEE80211_SUBBAND_RANGE, MODE_IEEE80211A,
+ /* min_chan */ 52,
+ /* max_chan */ 64,
+ /* num,_channels */ 4,
+ /* max_eirp_indoor */ MAX_DF_80211_EIRP_POWER,
+ /* max_eirp_outdoor */ 0,
+ IEEE80211_SUBBAND_INDOOR_CAP);
+
+ /* UNII-3 Band (5725 - 5825 MHz) */
+ setup_subband_restrictions(unii_3,
+ IEEE80211_SUBBAND_RANGE, MODE_IEEE80211A,
+ /* min_chan */ 149,
+ /* max_chan */ 161,
+ /* num,_channels */ 4,
+ /* max_eirp_indoor */ MAX_DF_80211_EIRP_POWER,
+ /* max_eirp_outdoor */ 0,
+ IEEE80211_SUBBAND_INDOOR_CAP);
+
+ /* Initialize all lists */
+ INIT_LIST_HEAD(®->band_restrictions_list);
+ INIT_LIST_HEAD(&b24r->subband_restrictions_list);
+ INIT_LIST_HEAD(&b5r->subband_restrictions_list);
+ INIT_LIST_HEAD(&ism24->channel_list);
+ INIT_LIST_HEAD(&unii_1->channel_list);
+ INIT_LIST_HEAD(&unii_2->channel_list);
+ INIT_LIST_HEAD(&unii_3->channel_list);
+
+ /* Alloc/setup/add g channels */
+ for(chan = ism24->min_chan; chan <= ism24->max_chan; chan++) {
+ struct ieee80211_regdomain_channel *reg_chan;
+ reg_chan = kmalloc(sizeof(struct ieee80211_regdomain_channel),
+ GFP_KERNEL);
+ if(reg_chan == NULL) {
+ r = -ENOMEM;
+ goto free_g_channels;
+ }
+ memset(reg_chan, 0,
+ sizeof(struct ieee80211_regdomain_channel));
+ setup_reg_channel(reg_chan,
+ IEEE80211_BAND_24GHZ, chan);
+ list_add_tail(®_chan->list, &ism24->channel_list);
+ }
+
+ /* Alloc/setup/add a channels */
+ for(i=1; i < num_sbs; i++) {
+ struct ieee80211_subband_restrictions *a_band;
+ a_band = subbands[i];
+ for(chan = a_band->min_chan; chan <= a_band->max_chan;
+ chan = (chan == 64) ? 149 : chan+4) {
+ struct ieee80211_regdomain_channel *reg_chan;
+ reg_chan = kmalloc(sizeof(struct
+ ieee80211_regdomain_channel),
+ GFP_KERNEL);
+ if(reg_chan == NULL) {
+ r = -ENOMEM;
+ goto free_a_channels;
+ }
+ memset(reg_chan, 0, sizeof(struct
+ ieee80211_regdomain_channel));
+ setup_reg_channel(reg_chan,
+ IEEE80211_BAND_5GHZ, chan);
+ list_add_tail(®_chan->list, &a_band->channel_list);
+ }
+ }
+
+ /* Hook regdomain, bands, subbands all together */
+ list_add_tail(&b24r->list, ®->band_restrictions_list);
+ list_add_tail(&b5r->list, ®->band_restrictions_list);
+ list_add_tail(&ism24->list, &b24r->subband_restrictions_list);
+ list_add_tail(&unii_1->list, &b5r->subband_restrictions_list);
+ list_add_tail(&unii_2->list, &b5r->subband_restrictions_list);
+ list_add_tail(&unii_3->list, &b5r->subband_restrictions_list);
+
+ /* Finally, add this reg to list of regdomains */
+ write_lock(®domain_rwlock);
+ list_add_tail(®->list, &ieee80211_regdomains_list);
+ write_unlock(®domain_rwlock);
+
+ check_reg_addition(r, reg_name);
+ return r;
+
+free_a_channels:
+ for(i=1; i < num_sbs; i++) {
+ free_subband_channel_list(&subbands[i]->channel_list);
+ }
+free_g_channels:
+ free_subband_channel_list(&ism24->channel_list);
+
+ list_del(&ism24->channel_list);
+ list_del(&unii_1->channel_list);
+ list_del(&unii_2->channel_list);
+ list_del(&unii_3->channel_list);
+ list_del(&b24r->subband_restrictions_list);
+ list_del(&b5r->subband_restrictions_list);
+ list_del(®->band_restrictions_list);
+exit:
+ check_reg_addition(r, reg_name);
+ return r;
+}
+
+#ifdef D80211_REGDOMAIN_FCC
+static int add_regdomain_fcc(void)
+{
+ int r = -ENOMEM, i, num_sbs = 4;
+ short chan;
+ struct ieee80211_regdomain *reg = NULL;
+ u32 reg_id = REGDOMAIN_FCC;
+ char *reg_name = "FCC";
+
+ struct ieee80211_band_restrictions *bands[2];
+ struct ieee80211_subband_restrictions *subbands[num_sbs];
+
+ struct ieee80211_band_restrictions *b24r;
+ struct ieee80211_band_restrictions *b5r;
+ struct ieee80211_subband_restrictions *ism24;
+ struct ieee80211_subband_restrictions *unii_1;
+ struct ieee80211_subband_restrictions *unii_2;
+ struct ieee80211_subband_restrictions *unii_3;
+
+ read_lock(®domain_rwlock);
+ r = regdomain_exists(reg_id, reg_name);
+ if(r) {
+ read_unlock(®domain_rwlock);
+ goto exit;
+ }
+ read_unlock(®domain_rwlock);
+
+ r = alloc_reg_bands_subbands(®, bands, 2, subbands, num_sbs);
+ if (r)
+ goto exit;
+
+ b24r = bands[0];
+ b5r = bands[1];
+ ism24 = subbands[0];
+ unii_1 = subbands[1];
+ unii_2 = subbands[2];
+ unii_3 = subbands[3];
+
+ /* Setup regdomain, bands and subbands */
+ setup_regdomain(reg, REGDOMAIN_FCC, reg_name);
+ setup_band_restrictions(b24r, IEEE80211_BAND_24GHZ);
+ setup_band_restrictions(b5r, IEEE80211_BAND_5GHZ);
+
+ /* As per FCC 15.247 */
+
+ /* ISM 2.4 GHz Band */
+ setup_subband_restrictions(ism24,
+ IEEE80211_SUBBAND_RANGE, MODE_IEEE80211G,
+ /* min_chan */ 1,
+ /* max_chan */ 11,
+ /* num,_channels */ 11,
+ /* max_eirp_indoor */ 30,
+ /* max_eirp_outdoor */ 30,
+ IEEE80211_SUBBAND_INDOOR_CAP |
+ IEEE80211_SUBBAND_OUTDOOR_CAP);
+
+ /* UNII-1 Band (5150 - 5250 MHz) */
+ setup_subband_restrictions(unii_1,
+ IEEE80211_SUBBAND_RANGE, MODE_IEEE80211A,
+ /* min_chan */ 36,
+ /* max_chan */ 48,
+ /* num,_channels */ 4,
+ /* max_eirp_indoor */ 30,
+ /* max_eirp_outdoor */ 0,
+ IEEE80211_SUBBAND_INDOOR_CAP);
+
+ /* UNII-2 Band (5250 - 5350 MHz) */
+ setup_subband_restrictions(unii_2,
+ IEEE80211_SUBBAND_RANGE, MODE_IEEE80211A,
+ /* min_chan */ 52,
+ /* max_chan */ 64,
+ /* num,_channels */ 4,
+ /* max_eirp_indoor */ 30,
+ /* max_eirp_outdoor */ 30,
+ IEEE80211_SUBBAND_INDOOR_CAP |
+ IEEE80211_SUBBAND_OUTDOOR_CAP);
+
+ /* UNII-3 Band (5725 - 5825 MHz) */
+ setup_subband_restrictions(unii_3,
+ IEEE80211_SUBBAND_RANGE, MODE_IEEE80211A,
+ /* min_chan */ 149,
+ /* max_chan */ 161,
+ /* num,_channels */ 4,
+ /* max_eirp_indoor */ 36,
+ /* max_eirp_outdoor */ 36,
+ IEEE80211_SUBBAND_INDOOR_CAP |
+ IEEE80211_SUBBAND_OUTDOOR_CAP);
+
+ /* Initialize all lists */
+ INIT_LIST_HEAD(®->band_restrictions_list);
+ INIT_LIST_HEAD(&b24r->subband_restrictions_list);
+ INIT_LIST_HEAD(&b5r->subband_restrictions_list);
+ INIT_LIST_HEAD(&ism24->channel_list);
+ INIT_LIST_HEAD(&unii_1->channel_list);
+ INIT_LIST_HEAD(&unii_2->channel_list);
+ INIT_LIST_HEAD(&unii_3->channel_list);
+
+ /* Alloc/setup/add g channels */
+ for(chan = ism24->min_chan; chan <= ism24->max_chan; chan++) {
+ struct ieee80211_regdomain_channel *reg_chan;
+ reg_chan = kmalloc(sizeof(struct ieee80211_regdomain_channel),
+ GFP_KERNEL);
+ if(reg_chan == NULL) {
+ r = -ENOMEM;
+ goto free_g_channels;
+ }
+ memset(reg_chan, 0,
+ sizeof(struct ieee80211_regdomain_channel));
+ setup_reg_channel(reg_chan,
+ IEEE80211_BAND_24GHZ, chan);
+ list_add_tail(®_chan->list, &ism24->channel_list);
+ }
+
+ /* Alloc/setup/add a channels */
+ for(i=1; i < num_sbs; i++) {
+ struct ieee80211_subband_restrictions *a_band;
+ a_band = subbands[i];
+ for(chan = a_band->min_chan; chan <= a_band->max_chan;
+ chan = (chan == 64) ? 149 : chan+4) {
+ struct ieee80211_regdomain_channel *reg_chan;
+ reg_chan = kmalloc(sizeof(struct
+ ieee80211_regdomain_channel),
+ GFP_KERNEL);
+ if(reg_chan == NULL) {
+ r = -ENOMEM;
+ goto free_a_channels;
+ }
+ memset(reg_chan, 0, sizeof(struct
+ ieee80211_regdomain_channel));
+ setup_reg_channel(reg_chan,
+ IEEE80211_BAND_5GHZ, chan);
+ list_add_tail(®_chan->list, &a_band->channel_list);
+ }
+ }
+
+ /* Hook regdomain, bands, subbands all together */
+ list_add_tail(&b24r->list, ®->band_restrictions_list);
+ list_add_tail(&b5r->list, ®->band_restrictions_list);
+ list_add_tail(&ism24->list, &b24r->subband_restrictions_list);
+ list_add_tail(&unii_1->list, &b5r->subband_restrictions_list);
+ list_add_tail(&unii_2->list, &b5r->subband_restrictions_list);
+ list_add_tail(&unii_3->list, &b5r->subband_restrictions_list);
+
+ /* Finally, add this reg to list of regdomains */
+ write_lock(®domain_rwlock);
+ list_add_tail(®->list, &ieee80211_regdomains_list);
+ write_unlock(®domain_rwlock);
+
+ check_reg_addition(r, reg_name);
+ return r;
+
+free_a_channels:
+ for(i=1; i < num_sbs; i++) {
+ free_subband_channel_list(&subbands[i]->channel_list);
+ }
+free_g_channels:
+ free_subband_channel_list(&ism24->channel_list);
+
+ list_del(&ism24->channel_list);
+ list_del(&unii_1->channel_list);
+ list_del(&unii_2->channel_list);
+ list_del(&unii_3->channel_list);
+ list_del(&b24r->subband_restrictions_list);
+ list_del(&b5r->subband_restrictions_list);
+ list_del(®->band_restrictions_list);
+exit:
+ check_reg_addition(r, reg_name);
+ return r;
+}
+#else
+static int add_regdomain_fcc(void)
+{
+ return;
+}
+#endif
+
+#ifdef D80211_REGDOMAIN_MKK
+static int add_regdomain_mkk(void)
+{
+ int r = -ENOMEM, i, num_sbs = 3;
+ short chan;
+ struct ieee80211_regdomain *reg = NULL;
+ u32 reg_id = REGDOMAIN_MKK;
+ char *reg_name = "MKK";
+
+ struct ieee80211_band_restrictions *bands[2];
+ struct ieee80211_subband_restrictions *subbands[num_sbs];
+
+ struct ieee80211_band_restrictions *b24r;
+ struct ieee80211_band_restrictions *b5r;
+ struct ieee80211_subband_restrictions *ism24;
+ struct ieee80211_subband_restrictions *unii_1;
+ struct ieee80211_subband_restrictions *unii_2;
+
+ read_lock(®domain_rwlock);
+ r = regdomain_exists(reg_id, reg_name);
+ if(r) {
+ read_unlock(®domain_rwlock);
+ goto exit;
+ }
+ read_unlock(®domain_rwlock);
+
+ r = alloc_reg_bands_subbands(®, bands, 2, subbands, num_sbs);
+ if (r)
+ goto exit;
+
+ b24r = bands[0];
+ b5r = bands[1];
+ ism24 = subbands[0];
+ unii_1 = subbands[1];
+ unii_2 = subbands[2];
+
+ /* Setup regdomain, bands and subbands */
+ setup_regdomain(reg, REGDOMAIN_FCC, reg_name);
+ setup_band_restrictions(b24r, IEEE80211_BAND_24GHZ);
+ setup_band_restrictions(b5r, IEEE80211_BAND_5GHZ);
+
+ /* As per FCC 15.247 */
+
+ /* ISM 2.4 GHz Band */
+ setup_subband_restrictions(ism24,
+ IEEE80211_SUBBAND_RANGE, MODE_IEEE80211G,
+ /* min_chan */ 1,
+ /* max_chan */ 13,
+ /* num,_channels */ 13,
+ /* max_eirp_indoor */ 30, /* needs verification */
+ /* max_eirp_outdoor */ 30, /* needs verification */
+ IEEE80211_SUBBAND_INDOOR_CAP |
+ IEEE80211_SUBBAND_OUTDOOR_CAP);
+
+
+ /* UNII-1 Band (5150 - 5250 MHz) */
+ /* Note: There are 4 MKK channels: 34, 38, 42, 46 */
+ setup_subband_restrictions(unii_1,
+ IEEE80211_SUBBAND_RANGE, MODE_IEEE80211A,
+ /* min_chan */ 34,
+ /* max_chan */ 46,
+ /* num,_channels */ 4,
+ /* max_eirp_indoor */ 30, /* needs verification */
+ /* max_eirp_outdoor */ 0, /* needs verification */
+ IEEE80211_SUBBAND_INDOOR_CAP);
+
+ /* UNII-2 Band (5250 - 5350 MHz) */
+ setup_subband_restrictions(unii_2,
+ IEEE80211_SUBBAND_RANGE, MODE_IEEE80211A,
+ /* min_chan */ 52,
+ /* max_chan */ 64,
+ /* num,_channels */ 4,
+ /* max_eirp_indoor */ 30,
+ /* max_eirp_outdoor */ 30,
+ IEEE80211_SUBBAND_INDOOR_CAP |
+ IEEE80211_SUBBAND_OUTDOOR_CAP);
+
+ /* Initialize all lists */
+ INIT_LIST_HEAD(®->band_restrictions_list);
+ INIT_LIST_HEAD(&b24r->subband_restrictions_list);
+ INIT_LIST_HEAD(&b5r->subband_restrictions_list);
+ INIT_LIST_HEAD(&ism24->channel_list);
+ INIT_LIST_HEAD(&unii_1->channel_list);
+ INIT_LIST_HEAD(&unii_2->channel_list);
+
+ /* Alloc/setup/add g channels */
+ for(chan = ism24->min_chan; chan <= ism24->max_chan; chan++) {
+ struct ieee80211_regdomain_channel *reg_chan;
+ reg_chan = kmalloc(sizeof(struct ieee80211_regdomain_channel),
+ GFP_KERNEL);
+ if(reg_chan == NULL) {
+ r = -ENOMEM;
+ goto free_g_channels;
+ }
+ memset(reg_chan, 0,
+ sizeof(struct ieee80211_regdomain_channel));
+ setup_reg_channel(reg_chan,
+ IEEE80211_BAND_24GHZ, chan);
+ list_add_tail(®_chan->list, &ism24->channel_list);
+ }
+
+ /* Alloc/setup/add a channels */
+ for(i=1; i < num_sbs; i++) {
+ struct ieee80211_subband_restrictions *a_band;
+ a_band = subbands[i];
+ for(chan = a_band->min_chan; chan <= a_band->max_chan;
+ chan = (chan == 64) ? 149 : chan+4) {
+ struct ieee80211_regdomain_channel *reg_chan;
+ reg_chan = kmalloc(sizeof(struct
+ ieee80211_regdomain_channel),
+ GFP_KERNEL);
+ if(reg_chan == NULL) {
+ r = -ENOMEM;
+ goto free_a_channels;
+ }
+ memset(reg_chan, 0, sizeof(struct
+ ieee80211_regdomain_channel));
+ setup_reg_channel(reg_chan,
+ IEEE80211_BAND_5GHZ, chan);
+ list_add_tail(®_chan->list, &a_band->channel_list);
+ }
+ }
+
+ /* Hook regdomain, bands, subbands all together */
+ list_add_tail(&b24r->list, ®->band_restrictions_list);
+ list_add_tail(&b5r->list, ®->band_restrictions_list);
+ list_add_tail(&ism24->list, &b24r->subband_restrictions_list);
+ list_add_tail(&unii_1->list, &b5r->subband_restrictions_list);
+ list_add_tail(&unii_2->list, &b5r->subband_restrictions_list);
+
+ /* Finally, add this reg to list of regdomains */
+ write_lock(®domain_rwlock);
+ list_add_tail(®->list, &ieee80211_regdomains_list);
+ write_unlock(®domain_rwlock);
+
+ check_reg_addition(r, reg_name);
+ return r;
+
+free_a_channels:
+ for(i=1; i < num_sbs; i++) {
+ free_subband_channel_list(&subbands[i]->channel_list);
+ }
+free_g_channels:
+ free_subband_channel_list(&ism24->channel_list);
+
+ list_del(&ism24->channel_list);
+ list_del(&unii_1->channel_list);
+ list_del(&unii_2->channel_list);
+ list_del(&b24r->subband_restrictions_list);
+ list_del(&b5r->subband_restrictions_list);
+ list_del(®->band_restrictions_list);
+exit:
+ check_reg_addition(r, reg_name);
+ return r;
+}
+#else
+static int add_regdomain_mkk(void)
+{
+ return;
+}
+#endif
+
+/* Adds a regulatory domain which has restrictions on
+ * 802.11bg and 802.11a modes with one subband on each
+ * Note MODE_IEEE80211G's restrictions will also define
+ * 802.11b restrictions as 802.11g is backward
+ * compatible with 802.11b */
+static int add_regdomain_bga(u8 reg_id, char *reg_name,
+ u8 channel_min_g, u8 channel_max_g,
+ u8 channel_min_a, u8 channel_max_a)
+{
+ int r = -ENOMEM;
+ short chan;
+ struct ieee80211_regdomain *reg = NULL;
+ struct ieee80211_band_restrictions *b24r = NULL;
+ struct ieee80211_band_restrictions *b5r = NULL;
+ struct ieee80211_subband_restrictions *sbg = NULL;
+ struct ieee80211_subband_restrictions *sba = NULL;
+ struct ieee80211_band_restrictions *bands[2];
+ struct ieee80211_subband_restrictions *subbands[2];
+ int num_g_channels = channel_max_g - channel_min_g + 1;
+ int num_a_channels = number_80211a_channels(channel_min_a, channel_max_a);
+
+ read_lock(®domain_rwlock);
+ r = regdomain_exists(reg_id, reg_name);
+ read_unlock(®domain_rwlock);
+ if(r)
+ goto exit;
+
+ r = alloc_reg_bands_subbands(®, bands, 2, subbands, 2);
+ if (r)
+ goto exit;
+
+ b24r = bands[0];
+ b5r = bands[1];
+ sbg = subbands[0];
+ sba = subbands[1];
+
+ /* Setup regdomain, bands, subbands */
+ setup_regdomain(reg, reg_id, reg_name);
+ setup_band_restrictions(b24r, IEEE80211_BAND_24GHZ);
+ setup_band_restrictions(b5r, IEEE80211_BAND_24GHZ);
+
+ setup_subband_restrictions(sbg,
+ IEEE80211_SUBBAND_RANGE, MODE_IEEE80211G,
+ channel_min_g, channel_max_g, num_g_channels,
+ MAX_DF_80211_EIRP_POWER, 0,
+ IEEE80211_SUBBAND_INDOOR_CAP);
+ setup_subband_restrictions(sba,
+ IEEE80211_SUBBAND_RANGE, MODE_IEEE80211A,
+ channel_min_a, channel_max_a, num_a_channels,
+ MAX_DF_80211_EIRP_POWER, 0,
+ IEEE80211_SUBBAND_INDOOR_CAP);
+
+ /* Initialize all lists */
+ INIT_LIST_HEAD(®->band_restrictions_list);
+ INIT_LIST_HEAD(&b24r->subband_restrictions_list);
+ INIT_LIST_HEAD(&b5r->subband_restrictions_list);
+ INIT_LIST_HEAD(&sbg->channel_list);
+ INIT_LIST_HEAD(&sba->channel_list);
+
+ /* Alloc/setup/add g channels */
+ for(chan = channel_min_g; chan <= channel_max_g; chan++) {
+ struct ieee80211_regdomain_channel *reg_chan;
+ reg_chan = kmalloc(sizeof(struct ieee80211_regdomain_channel),
+ GFP_KERNEL);
+ if(reg_chan == NULL) {
+ r = -ENOMEM;
+ goto free_g_channels;
+ }
+ memset(reg_chan, 0,
+ sizeof(struct ieee80211_regdomain_channel));
+ setup_reg_channel(reg_chan,
+ IEEE80211_BAND_24GHZ, chan);
+ list_add_tail(®_chan->list, &sbg->channel_list);
+ }
+
+ /* Alloc/setup/add a channels */
+ for(chan = channel_min_a; chan <= channel_max_a;
+ chan = (chan == 64) ? 149 : chan+4) {
+ struct ieee80211_regdomain_channel *reg_chan;
+ reg_chan = kmalloc(sizeof(struct ieee80211_regdomain_channel),
+ GFP_KERNEL);
+ if(reg_chan == NULL) {
+ r = -ENOMEM;
+ goto free_a_channels;
+ }
+ memset(reg_chan, 0,
+ sizeof(struct ieee80211_regdomain_channel));
+ setup_reg_channel(reg_chan,
+ IEEE80211_BAND_5GHZ, chan);
+ list_add_tail(®_chan->list, &sba->channel_list);
+ }
+
+ /* Hook regdomain, bands, subbands all together */
+ list_add_tail(&b24r->list, ®->band_restrictions_list);
+ list_add_tail(&b5r->list, ®->band_restrictions_list);
+ list_add_tail(&sbg->list, &b24r->subband_restrictions_list);
+ list_add_tail(&sba->list, &b5r->subband_restrictions_list);
+
+ /* Finally, add this reg to list of regdomains */
+ write_lock(®domain_rwlock);
+ list_add_tail(®->list, &ieee80211_regdomains_list);
+ write_unlock(®domain_rwlock);
+ check_reg_addition(r, reg_name);
+ return r;
+
+free_a_channels:
+ free_subband_channel_list(&sba->channel_list);
+free_g_channels:
+ free_subband_channel_list(&sbg->channel_list);
+
+ list_del(&sbg->channel_list);
+ list_del(&sba->channel_list);
+ list_del(&b24r->subband_restrictions_list);
+ list_del(&b5r->subband_restrictions_list);
+ list_del(®->band_restrictions_list);
+exit:
+ check_reg_addition(r, reg_name);
+ return r;
+}
+
+/* old: add_regdomain_defaults */
+static inline int check_reg_addition(int r, char *reg_name)
+{
+ printk("%s: regulatory domain %18s - ", DRV_NAME, reg_name);
+ switch(r) {
+ case -ENOMEM:
+ printk("Unable to allocate memory\n");
+ break;
+ case -EINVAL:
+ printk("reg_name is invalid\n");
+ break;
+ case 1:
+ printk("reg_id already in use\n");
+ r = -EINVAL;
+ break;
+ case 2:
+ printk("reg_name already in use\n");
+ r = -EINVAL;
+ break;
+ case 3:
+ printk("reg_id and reg_name already in use\n");
+ r = -EINVAL;
+ break;
+ case 0:
+ printk("registered\n");
+ break;
+ default:
+ printk("Unexpected error detected\n");
+ r = -EINVAL;
+ break;
+ }
+ return r;
+}
+
+void print_regdomain(struct ieee80211_regdomain *reg)
+{
+ struct ieee80211_band_restrictions *b;
+ struct ieee80211_subband_restrictions *sb;
+ struct ieee80211_regdomain_channel *reg_chan;
+
+ if (reg == NULL) {
+ printk("Invalid regulatory domain encountered\n");
+ return;
+ }
+
+ printk("Regulatory Domain:\t%s\tRegulatory Domain ID:\t0x%02x\n",
+ reg->regdomain_name,
+ reg->regdomain_id);
+
+ /* TODO: ieee80211_ioctl.c's ieee80211_ioctl_giwrange() has similar
+ * switch, consolidate */
+ list_for_each_entry(b, ®->band_restrictions_list, list) {
+ list_for_each_entry(sb, &b->subband_restrictions_list, list){
+ switch(sb->mode) {
+ case MODE_IEEE80211G:
+ if (sb->num_channels <= 0) {
+ printk("\t802.11bg not supported\n");
+ continue;
+ }
+ printk("\t802.11bg");
+ break;
+ case MODE_IEEE80211A:
+ if (sb->num_channels <= 0) {
+ printk("\t802.11a not supported\n");
+ continue;
+ }
+ printk("\t802.11a");
+ break;
+ default:
+ printk("\t802.11 mode (%d) not supported\n",
+ sb->mode);
+ continue;
+ }
+ printk(" (num_channels:%d)(min_chan:%d)(max_chan:%d)"
+ "(max_eirp_indoor:%d)"
+ "(max_eirp_outdoor:%d)\n",
+ sb->num_channels, sb->min_chan,
+ sb->max_chan, sb->max_eirp_indoor,
+ sb->max_eirp_outdoor);
+ printk("\t\tChannel\tFreq\t\n");
+
+ list_for_each_entry(reg_chan, &sb->channel_list, list){
+ struct ieee80211_channel *chan = ®_chan->channel;
+ printk("\t\t%d\t%d\t\n", chan->chan, chan->freq);
+ }
+ }
+ }
+ printk("\n");
+}
+
+#ifdef CONFIG_D80211_DEBUG
+void print_regdomains(void)
+{
+ struct ieee80211_regdomain *reg;
+ read_lock(®domain_rwlock);
+ list_for_each_entry(reg, &ieee80211_regdomains_list, list) {
+ print_regdomain(reg);
+ }
+ read_unlock(®domain_rwlock);
+}
+
+void print_iso3166_reg_map(void)
+{
+ struct ieee80211_iso3166_reg_map *map;
+ char regdomain_name[REGNAMSIZ];
+ printk("ISO3166 <--> regulatory domain map:\n");
+ printk("\tCTRY\t-->\tRegdomain\n");
+ read_lock(&iso3166_reg_rwlock);
+ list_for_each_entry(map, &iso3166_reg_map_list, list) {
+ if(get_ieee80211_regname(map->regdomain_id, regdomain_name))
+ printk("\t%s\t-->\t0x%02x (reg_id not registered in "
+ "regulatory db)\n",
+ map->alpha3, map->regdomain_id);
+ else
+ printk("\t%s\t-->\t%s\n", map->alpha3, regdomain_name);
+ }
+ read_unlock(&iso3166_reg_rwlock);
+}
+void print_hwreg_reg_map(void)
+{
+ struct ieee80211_regulatory_map *regmap;
+ struct ieee80211_hwreg_map *hwreg_map;
+ printk("Hardware regulatory domain map\n");
+ read_lock(®_map_rwlock);
+ list_for_each_entry(regmap, &ieee80211_reg_map_list, list) {
+ printk("Regulatory map: %s\n", regmap->hwreg_reg_mapname);
+ printk("\t\tDevice\t-->\tStack\n");
+ list_for_each_entry(hwreg_map, ®map->hwreg_map_list, list) {
+ printk("\t\t%04x\t-->\t%04x\n",
+ hwreg_map->regdomain_id,
+ hwreg_map->regdomain_id_hw);
+ }
+ }
+ read_unlock(®_map_rwlock);
+}
+#else
+void print_regdomains(void)
+{
+ return;
+}
+void print_iso3166_reg_map(void)
+{
+ return;
+}
+void print_hwreg_reg_map(void)
+{
+ return;
+}
+#endif
+
+/* XXX: add this functionality using nl80211 */
+#ifdef CONFIG_D80211_REGULATORY_USER
+static int load_user_regdomains(void)
+{
+ return -ENOTSUPP;
+}
+#else
+static int load_user_regdomains(void)
+{
+ return 0;
+}
+#endif
+
+int get_ieee80211_regname(u32 regdomain_id, char *regdomain_name)
+{
+ struct ieee80211_regdomain *reg;
+ read_lock(®domain_rwlock);
+ list_for_each_entry(reg, &ieee80211_regdomains_list, list) {
+ if(regdomain_id == reg->regdomain_id) {
+ strcpy(regdomain_name, reg->regdomain_name);
+ read_unlock(®domain_rwlock);
+ return 0;
+ }
+ }
+ read_unlock(®domain_rwlock);
+ return -ENOTSUPP;
+}
+
+static int load_regdomain_defaults(void)
+{
+ int r = 0;
+ /* "World" complies with most regulatory domains */
+ r = add_regdomain_world();
+ r |= add_regdomain_fcc();
+ r |= add_regdomain_mkk();
+ /* Revise these and move them to their own routine, right now we are
+ * adding them with only one subband, assuming default power
+ * restrictions */
+#ifdef D80211_REGDOMAIN_ETSI
+ r |= add_regdomain_bga(REGDOMAIN_ETSI, "ETSI", 1, 13, 36, 165);
+#endif
+ //r |= add_regdomain_bga(REGDOMAIN_FRANCE, "France", 11, 13, 36, 165);
+ r |= add_regdomain_bga(REGDOMAIN_IC, "IC", 3, 11, 36, 165);
+ //r |= add_regdomain_bga(REGDOMAIN_SPAIN, "Spain", 10, 11, 36, 165);
+
+ return r;
+}
+
+static int update_ieee80211_regdomains(void)
+{
+ int r;
+ INIT_LIST_HEAD(&ieee80211_regdomains_list);
+ r = load_regdomain_defaults();
+ if(r) {
+ printk("error while trying to register "
+ "built-in regdomains\n");
+ return r;
+ }
+ r = load_user_regdomains();
+ return r;
+}
+
+static inline void setup_iso3166_reg_map(struct ieee80211_iso3166_reg_map *map,
+ char *alpha3, u32 regdomain_id)
+{
+ strcpy(map->alpha3, alpha3);
+ map->regdomain_id = regdomain_id;
+}
+
+inline int iso3166_to_reg_exists(char *alpha3)
+{
+ struct ieee80211_iso3166_reg_map *map;
+ read_lock(&iso3166_reg_rwlock);
+ list_for_each_entry(map, &iso3166_reg_map_list, list)
+ if(strcmp(map->alpha3, alpha3)==0) {
+ read_unlock(&iso3166_reg_rwlock);
+ return 1;
+ }
+ read_unlock(&iso3166_reg_rwlock);
+ return 0;
+}
+
+int iso3166_to_reg(char *alpha3, u32 regdomain_id)
+{
+ struct ieee80211_iso3166_reg_map *map;
+ read_lock(&iso3166_reg_rwlock);
+ list_for_each_entry(map, &iso3166_reg_map_list, list)
+ if(strcmp(map->alpha3, alpha3)==0) {
+ regdomain_id = map->regdomain_id;
+ read_unlock(&iso3166_reg_rwlock);
+ return 1;
+ }
+ read_unlock(&iso3166_reg_rwlock);
+ return 0;
+}
+
+int alpha3_valid(char *alpha3) {
+ if(strlen(alpha3) == ISOCOUNTRYSIZ3)
+ return 1;
+ return 0;
+}
+
+int add_iso3166_reg_map(char *alpha3, u32 regdomain_id)
+{
+ int r = 0;
+ struct ieee80211_iso3166_reg_map *map;
+ write_lock(&iso3166_reg_rwlock);
+ /* If not valid or, iso map does not exist or if already already present */
+ if(!alpha3_valid(alpha3) || !iso3166_1_exists(alpha3) ||
+ iso3166_to_reg_exists(alpha3)){
+ r = -EPERM;
+ goto unlock_and_exit;
+ }
+ map = kmalloc(sizeof(struct ieee80211_iso3166_reg_map), GFP_KERNEL);
+ if(map == NULL) {
+ r = -ENOMEM;
+ goto unlock_and_exit;
+ }
+ setup_iso3166_reg_map(map, alpha3, regdomain_id);
+ list_add_tail(&map->list, &iso3166_reg_map_list);
+unlock_and_exit:
+ write_unlock(&iso3166_reg_rwlock);
+ return r;
+}
+
+static inline int load_iso3166_regmap_fcc(void)
+{
+ int r = 0;
+ r |= add_iso3166_reg_map("USA", REGDOMAIN_FCC);
+ r |= add_iso3166_reg_map("COL", REGDOMAIN_FCC);
+ r |= add_iso3166_reg_map("DOM", REGDOMAIN_FCC);
+ r |= add_iso3166_reg_map("GTM", REGDOMAIN_FCC);
+ r |= add_iso3166_reg_map("MEX", REGDOMAIN_FCC);
+ r |= add_iso3166_reg_map("PAN", REGDOMAIN_FCC);
+ r |= add_iso3166_reg_map("PRI", REGDOMAIN_FCC);
+ return r;
+}
+
+static inline int load_iso3166_regmap_etsi(void)
+{
+ int r = 0;
+ r |= add_iso3166_reg_map("DNK", REGDOMAIN_ETSI);
+ r |= add_iso3166_reg_map("EST", REGDOMAIN_ETSI);
+ r |= add_iso3166_reg_map("FIN", REGDOMAIN_ETSI);
+ r |= add_iso3166_reg_map("DEU", REGDOMAIN_ETSI);
+ r |= add_iso3166_reg_map("ISL", REGDOMAIN_ETSI);
+ r |= add_iso3166_reg_map("IRL", REGDOMAIN_ETSI);
+ r |= add_iso3166_reg_map("ITA", REGDOMAIN_ETSI);
+ r |= add_iso3166_reg_map("LTU", REGDOMAIN_ETSI);
+ r |= add_iso3166_reg_map("LUX", REGDOMAIN_ETSI);
+ r |= add_iso3166_reg_map("NLD", REGDOMAIN_ETSI);
+ r |= add_iso3166_reg_map("NOR", REGDOMAIN_ETSI);
+ r |= add_iso3166_reg_map("POL", REGDOMAIN_ETSI);
+ r |= add_iso3166_reg_map("PRT", REGDOMAIN_ETSI);
+ r |= add_iso3166_reg_map("SVN", REGDOMAIN_ETSI);
+ r |= add_iso3166_reg_map("ZAF", REGDOMAIN_ETSI);
+ r |= add_iso3166_reg_map("SWE", REGDOMAIN_ETSI);
+ r |= add_iso3166_reg_map("GBR", REGDOMAIN_ETSI);
+ r |= add_iso3166_reg_map("FRA", REGDOMAIN_ETSI); /* France goes here? */
+ r |= add_iso3166_reg_map("ESP", REGDOMAIN_ETSI); /* Spain goes here? */
+ return r;
+}
+
+static inline int load_iso3166_regmap_misc(void)
+{
+ int r = 0;
+ r |= add_iso3166_reg_map("CAN", REGDOMAIN_IC);
+ r |= add_iso3166_reg_map("JPN", REGDOMAIN_MKK);
+ //r |= add_iso3166_reg_map("ESP", REGDOMAIN_SPAIN); /* or here? */
+ return r;
+}
+
+static int load_iso3166_reg_defaults(void)
+{
+ int r = 0;
+ r |= load_iso3166_regmap_fcc();
+ r |= load_iso3166_regmap_etsi();
+ r |= load_iso3166_regmap_misc();
+ return r;
+}
+
+static int update_iso3166_reg_map_list(void)
+{
+ int r;
+ INIT_LIST_HEAD(&iso3166_reg_map_list);
+ r = load_iso3166_reg_defaults();
+ if(r)
+ printk("error while trying to load iso3166-1 alpha3 country "
+ "code -> stack regdomain map\n");
+ return r;
+}
+
+static inline void setup_hwreg_map(struct ieee80211_hwreg_map *hwreg_map,
+ u32 regdomain_id, u32 regdomain_id_hw)
+{
+ hwreg_map->regdomain_id = regdomain_id;
+ hwreg_map->regdomain_id_hw = regdomain_id_hw;
+}
+
+static int add_hwreg_reg_map(struct ieee80211_regulatory_map *reg_map,
+ u32 regdomain_id, u32 regdomain_id_hw)
+{
+ struct ieee80211_hwreg_map *hwreg_map;
+ hwreg_map = kmalloc(sizeof(struct ieee80211_hwreg_map), GFP_KERNEL);
+ if (hwreg_map == NULL)
+ return -ENOMEM;
+ setup_hwreg_map(hwreg_map, regdomain_id, regdomain_id_hw);
+ list_add_tail(&hwreg_map->list, ®_map->hwreg_map_list);
+ return 0;
+}
+
+static inline int load_atheros_regulatory_map(void)
+{
+ int r = 0;
+ struct ieee80211_regulatory_map *reg_map;
+ reg_map = kmalloc(sizeof(struct ieee80211_regulatory_map), GFP_KERNEL);
+ if (reg_map == NULL)
+ return -ENOMEM;
+
+ strcpy(reg_map->hwreg_reg_mapname, "Atheros");
+ INIT_LIST_HEAD(®_map->hwreg_map_list);
+ r |= add_hwreg_reg_map(reg_map, REGDOMAIN_WORLD, REGDOMAIN_WORLD);
+ r |= add_hwreg_reg_map(reg_map, REGDOMAIN_FCC, REGDOMAIN_FCC);
+ r |= add_hwreg_reg_map(reg_map, REGDOMAIN_IC, REGDOMAIN_IC);
+ r |= add_hwreg_reg_map(reg_map, REGDOMAIN_ETSI, REGDOMAIN_ETSI);
+ // r |= add_hwreg_reg_map(reg_map, REGDOMAIN_SPAIN, REGDOMAIN_SPAIN);
+ // r |= add_hwreg_reg_map(reg_map, REGDOMAIN_FRANCE, REGDOMAIN_FRANCE);
+ r |= add_hwreg_reg_map(reg_map, REGDOMAIN_MKK, REGDOMAIN_MKK);
+
+ write_lock(®_map_rwlock);
+ list_add_tail(®_map->list, &ieee80211_reg_map_list);
+ write_unlock(®_map_rwlock);
+ return r;
+}
+
+static int load_hwreg_reg_maps_defaults(void) {
+ int r = 0;
+ r |= load_atheros_regulatory_map();
+ return r;
+}
+
+static int update_hwreg_reg_maps_list(void)
+{
+ int r;
+ INIT_LIST_HEAD(&ieee80211_reg_map_list);
+ r = load_hwreg_reg_maps_defaults();
+ if(r)
+ printk("error while trying to load hardware regulatory -> "
+ "stack regulatory domain map\n");
+ return r;
+}
+
+static int regdomains_init(void)
+{
+ int r;
+ printk("%s: %s v%s loaded\n", DRV_NAME, DRV_DESCRIPTION, DRV_VERSION);
+
+ /* Update regdomain list */
+ r = update_ieee80211_regdomains();
+ if(r)
+ goto free_regs;
+ print_regdomains();
+
+ /* Load iso->reg map */
+ r = update_iso3166_reg_map_list();
+ if(r)
+ goto free_iso_reg_map_list;
+ print_iso3166_reg_map();
+
+ /* Load hwreg->reg maps */
+ r = update_hwreg_reg_maps_list();
+ if(r)
+ goto free_hwreg_reg_maps_list;
+ print_hwreg_reg_map();
+
+ return r;
+free_hwreg_reg_maps_list:
+ free_hwreg_reg_maps(); /* TODO */
+free_iso_reg_map_list:
+ free_iso3166_reg_map_list();
+free_regs:
+ free_regdomains();
+ return r;
+}
+
+static void regdomains_exit(void)
+{
+ /* Regdomains */
+ write_lock(®domain_rwlock);
+ free_regdomains();
+ list_del(&ieee80211_regdomains_list);
+ write_unlock(®domain_rwlock);
+
+ /* Iso->reg map */
+ write_lock(&iso3166_reg_rwlock);
+ free_iso3166_reg_map_list();
+ list_del(&iso3166_reg_map_list);
+ write_unlock(&iso3166_reg_rwlock);
+ printk("%s: unloaded\n", DRV_NAME);
+}
+
+/* TODO: add get_reg_channels(regdomain_id, mode) returns array of channels */
+module_init(regdomains_init);
+module_exit(regdomains_exit);
+EXPORT_SYMBOL(print_regdomain);
+#ifdef CONFIG_D80211_DEBUG
+EXPORT_SYMBOL(print_regdomains);
+EXPORT_SYMBOL(print_iso3166_reg_map);
+EXPORT_SYMBOL(print_hwreg_reg_map);
+#endif
+EXPORT_SYMBOL(get_ieee80211_regname);
+
+EXPORT_SYMBOL(ieee80211_regdomains_list);
+EXPORT_SYMBOL(iso3166_reg_map_list);
+EXPORT_SYMBOL(ieee80211_reg_map_list);
+
+EXPORT_SYMBOL(regdomain_rwlock);
+EXPORT_SYMBOL(iso3166_reg_rwlock);
+EXPORT_SYMBOL(reg_map_rwlock);
+
+EXPORT_SYMBOL(alpha3_valid); /* Move to iso module */
+EXPORT_SYMBOL(iso3166_to_reg_exists);
+EXPORT_SYMBOL(iso3166_to_reg);
+EXPORT_SYMBOL(add_iso3166_reg_map);
^ permalink raw reply [flat|nested] 5+ messages in thread* Re: [RFC] [PATCH 2/3] adds ieee80211_regdomains support
2006-10-23 22:47 [RFC] [PATCH 2/3] adds ieee80211_regdomains support Luis R. Rodriguez
@ 2006-10-24 8:33 ` Johannes Berg
2006-10-24 17:10 ` Luis R. Rodriguez
2006-10-25 2:07 ` Anand Kumria
1 sibling, 1 reply; 5+ messages in thread
From: Johannes Berg @ 2006-10-24 8:33 UTC (permalink / raw)
To: Luis R. Rodriguez; +Cc: netdev, Jiri Benc, John W. Linville, Jean Tourrilhes
> and adds support for PtMP (Point
> to MultiPoint) and PtP (Point to Point) type restrictions.
What are those restrictions?
Similar comments here, why do you build the list at module init time
instead of having it static?
Also, do we really need all this data in the kernel?
johannes
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [RFC] [PATCH 2/3] adds ieee80211_regdomains support
2006-10-24 8:33 ` Johannes Berg
@ 2006-10-24 17:10 ` Luis R. Rodriguez
0 siblings, 0 replies; 5+ messages in thread
From: Luis R. Rodriguez @ 2006-10-24 17:10 UTC (permalink / raw)
To: Johannes Berg; +Cc: netdev, Jiri Benc, John W. Linville, Jean Tourrilhes
On 10/24/06, Johannes Berg <johannes@sipsolutions.net> wrote:
>
> > and adds support for PtMP (Point
> > to MultiPoint) and PtP (Point to Point) type restrictions.
>
> What are those restrictions?
I'm glad you asked. Here's a quote from:
http://university.cyberarmy.net/kb/tiki-index.php?page=The+Power+of+802.11
"In the 2.4Ghz ISM band the FCC stipulates that the creation of PtMP
links be subject to the following restrictions:
* EIRP must not exceed 4W (36dBm)
* IR must not exceed 1W (30dBm)
* For every 3dBi of antenna gain after the first 6 "free" dBi the
IR must be decreased by 3dBi (the 1:1 rule)
For PtP links that rule is thusly augmented:
* IR is limited to 1W (30dBm)
* For every 3dBi after the first 6 of antenna gain the IR must be
decreased by 1dBi (the 3:1 rule)
One thing to notice about the rules for the PtP link is that it does
not stipulate a maximum EIRP and significantly reduces the penalty for
adding antenna gain. In this situation it would be acceptable to have
an IR of 25dBm and with a directional antenna adding 21dBm of gain
giving us an EIRP of 46dBm or 40W. This is why it is very important to
stay away from the front of highly directional antennae. If you have
ever wondered what it would be like to squeeze yourself into a
microwave and have it turned on...
"
The restrictions defined in this regulatory module are designed first
to tackle PtMP links restrictions but keeps in mind PtP link subband
restrictions as well for further advancements. This would ultimately
complete regulatory domain support. To support PtP links well though
we'd need some further stack enhancements and modifications. Currently
I separate PtP and PtMP link restrictions by putting them on separate
subband linked list on the regulatory domain. Antenna gain is device
specific and for manufacturer's sake and user's hacker's sake we
should allow for:
1. Device specific definition of the manufacturer's default antenna gain and...
2. Allow the user to modify this antenna gain in case they modify the
antenna. Our due dillegence comes from at least providing built-in
regulatory framework and allowing the malleability of the malleable
components of such restrictions. If antenna gain is modified we should
accordingly modify the device's IR -- notice this requires changes
even for PtMP link restrictions as well but support without this was
what I was thinking for Phase I of this module.
(1) is covered under d80211.h on the ieee80211_conf struct, u8
antenna_max but this is a subband restriction not an entire device
restriction. If we want to add this support immediately we can add IR
to the subband definition.
(2) needs further enhancements on the stack, namely that making IR
dynamic based on the device's antenna gain.
All this requires a lot of changes. What I'd suggest first is to adopt
PtMP link restrictions without supporting dynamic IRs based on antenna
gains until Phase II. In Phase II I was hoping we'd tackle this and a
userspace daemon through nl80211/cfg80211. d80211 is due to go stable,
I was hoping regulatory domains under phase I would be one last
addition to it before going stable and Phase II can be the focus for a
v2 of a stable d80211.
> Similar comments here, why do you build the list at module init time
> instead of having it static?
It made the code cleaner, feel free to modify if there are benefits
through a static approach. I originally attempted a static array
approach here but ran into problems quickly due to the dynamic nature
of the data structures required for regulatory domains and was having
a headache dealing with all the nasty macros to build this statically.
I'd suggest we keep things as is unless we have a complete clear
understanding of all requirements of regulatory domains. Regulatory
domains are not really well documented and this perhaps is the best
break down of them that I've seen so far.
> Also, do we really need all this data in the kernel?
Another great question. At first I actually wanted all this in
userspace but after some consideration figured it'd be best to
introduce in the kernel instead. Here are some considerations made me
change my mindl:
1. Regulatory restrictions affects the PHY's behaviour directly
2. IEEE-802.11D is a standard which all wireless stacks should
hopefully and eventually support. It is based on regulatory domains
which dictate how the PHY should work.
3. I believe the benefit in speed of having the regulatory
restrictions in the kernel outweight the overhead of having this in
the kernel
4. Introduction of a userspace daemon to update all regulatory domains
seems like a heavy restriction to immediately force every distribution
on. Also there is simply no clear "World" regulatory domain that
everyone can live peacefully with. An easier way to introduce
regulatory domains would be to have the most popular regulatory
domains built-in and slowly support userspace communication to update
and manage the regulatory db.
So, ultimately userspace should be the place for all this but -- not
yet, and even after we've ironed out a new userpsace API for wireless
device communication (nl80211 and cfg80211 I'm hoping) we should still
consider if the benefits of having this in the kernel outweigh the
overhead. For now I think we should stick to supporting this in the
kernel with a list of most common regulatory domains defined and
supported as optional (as the supplied Kconfig defines). Another idea
that I didn't yet complete was to let the user supply the alpha3
country code at kernel config and depending on this select the
required regdomain. Current Kconfig implementation makes this pretty
messy though.
Luis
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [RFC] [PATCH 2/3] adds ieee80211_regdomains support
2006-10-23 22:47 [RFC] [PATCH 2/3] adds ieee80211_regdomains support Luis R. Rodriguez
2006-10-24 8:33 ` Johannes Berg
@ 2006-10-25 2:07 ` Anand Kumria
2006-10-25 15:16 ` Luis R. Rodriguez
1 sibling, 1 reply; 5+ messages in thread
From: Anand Kumria @ 2006-10-25 2:07 UTC (permalink / raw)
To: netdev
On Mon, 23 Oct 2006 18:47:25 -0400, Luis R. Rodriguez wrote:
> ieee80211_regdomains
>
> Breaks down regulatory domains into data structures which allow
> drivers to share channel and power contraints based on stack
> regulatory domain. This driver adds in-kernel support for common
> regulatory domains (such as FCC and ETSI), makes updating the
[snip]
+/* Stack regulatory domain values. Atheros seems to have started this
+ * convention and most hardware vendors followed their example.
+ * Although these are *very* common we allow for a hw-specific
+ * map between stack and device regdomain values. */
+enum stack_regdomain {
+ REGDOMAIN_WORLD = 0x00, /* World compliance, minimum set */
+ REGDOMAIN_FCC = 0x10, /* USA */
+ REGDOMAIN_IC = 0x20, /* Canada */
+ REGDOMAIN_ETSI = 0x30, /* Europe */
+ REGDOMAIN_SPAIN = 0x31, /* Spain */
+ REGDOMAIN_FRANCE = 0x32, /* France */
+ REGDOMAIN_MKK = 0x40, /* Japan */
+};
+
Why not pick either the country name or the organisation within the country that determines the frequency guidelines?
Regards,
Anand
^ permalink raw reply [flat|nested] 5+ messages in thread* Re: [RFC] [PATCH 2/3] adds ieee80211_regdomains support
2006-10-25 2:07 ` Anand Kumria
@ 2006-10-25 15:16 ` Luis R. Rodriguez
0 siblings, 0 replies; 5+ messages in thread
From: Luis R. Rodriguez @ 2006-10-25 15:16 UTC (permalink / raw)
To: Anand Kumria; +Cc: netdev
On 10/24/06, Anand Kumria <wildfire@progsoc.org> wrote:
> On Mon, 23 Oct 2006 18:47:25 -0400, Luis R. Rodriguez wrote:
>
> > ieee80211_regdomains
> >
> > Breaks down regulatory domains into data structures which allow
> > drivers to share channel and power contraints based on stack
> > regulatory domain. This driver adds in-kernel support for common
> > regulatory domains (such as FCC and ETSI), makes updating the
>
> [snip]
>
> +/* Stack regulatory domain values. Atheros seems to have started this
> + * convention and most hardware vendors followed their example.
> + * Although these are *very* common we allow for a hw-specific
> + * map between stack and device regdomain values. */
> +enum stack_regdomain {
> + REGDOMAIN_WORLD = 0x00, /* World compliance, minimum set */
> + REGDOMAIN_FCC = 0x10, /* USA */
> + REGDOMAIN_IC = 0x20, /* Canada */
> + REGDOMAIN_ETSI = 0x30, /* Europe */
> + REGDOMAIN_SPAIN = 0x31, /* Spain */
> + REGDOMAIN_FRANCE = 0x32, /* France */
> + REGDOMAIN_MKK = 0x40, /* Japan */
> +};
> +
>
> Why not pick either the country name or the organisation within the country
> that determines the frequency guidelines?
Ultimately I think this is the way this should work and this is why I
provide a alpha3 country code --> stack regulatory domain map.
Userpace should just let the user pick the country at say,
distribution install time, and the map then used to determine the
regulatory domain. Regulatory domains are what dictate the subband
restrictions and as such these are ultimately what we need in the
stack to decide what goes and what doesn't.
Luis
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2006-10-25 15:16 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-10-23 22:47 [RFC] [PATCH 2/3] adds ieee80211_regdomains support Luis R. Rodriguez
2006-10-24 8:33 ` Johannes Berg
2006-10-24 17:10 ` Luis R. Rodriguez
2006-10-25 2:07 ` Anand Kumria
2006-10-25 15:16 ` Luis R. Rodriguez
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).