aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/generic/patches-3.8/204-module_strip.patch
blob: df5c483ebc4e97348c429e52baf29d0771ab15c5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
From: Felix Fietkau <nbd@openwrt.org>
Subject: [PATCH] build: add a hack for removing non-essential module info

Signed-off-by: Felix Fietkau <nbd@openwrt.org>
---
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -82,7 +82,7 @@ void sort_extable(struct exception_table
 void sort_main_extable(void);
 void trim_init_extable(struct module *m);
 
-#ifdef MODULE
+#if defined(MODULE) && !defined(CONFIG_MODULE_STRIPPED)
 #define MODULE_GENERIC_TABLE(gtype,name)			\
 extern const struct gtype##_id __mod_##gtype##_table		\
   __attribute__ ((unused, alias(__stringify(name))))
@@ -93,9 +93,10 @@ extern const struct gtype##_id __mod_##g
 
 /* Generic info of form tag = "info" */
 #define MODULE_INFO(tag, info) __MODULE_INFO(tag, tag, info)
+#define MODULE_INFO_STRIP(tag, info) __MODULE_INFO_STRIP(tag, tag, info)
 
 /* For userspace: you can also call me... */
-#define MODULE_ALIAS(_alias) MODULE_INFO(alias, _alias)
+#define MODULE_ALIAS(_alias) MODULE_INFO_STRIP(alias, _alias)
 
 /*
  * The following license idents are currently accepted as indicating free
@@ -131,10 +132,10 @@ extern const struct gtype##_id __mod_##g
  * Author(s), use "Name <email>" or just "Name", for multiple
  * authors use multiple MODULE_AUTHOR() statements/lines.
  */
-#define MODULE_AUTHOR(_author) MODULE_INFO(author, _author)
+#define MODULE_AUTHOR(_author) MODULE_INFO_STRIP(author, _author)
   
 /* What your module does. */
-#define MODULE_DESCRIPTION(_description) MODULE_INFO(description, _description)
+#define MODULE_DESCRIPTION(_description) MODULE_INFO_STRIP(description, _description)
 
 #define MODULE_DEVICE_TABLE(type,name)		\
   MODULE_GENERIC_TABLE(type##_device,name)
@@ -155,7 +156,9 @@ extern const struct gtype##_id __mod_##g
 */
 
 #if defined(MODULE) || !defined(CONFIG_SYSFS)
-#define MODULE_VERSION(_version) MODULE_INFO(version, _version)
+#define MODULE_VERSION(_version) MODULE_INFO_STRIP(version, _version)
+#elif defined(CONFIG_MODULE_STRIPPED)
+#define MODULE_VERSION(_version) __MODULE_INFO_DISABLED(version)
 #else
 #define MODULE_VERSION(_version)					\
 	static struct module_version_attribute ___modver_attr = {	\
@@ -177,7 +180,7 @@ extern const struct gtype##_id __mod_##g
 /* Optional firmware file (or files) needed by the module
  * format is simply firmware file name.  Multiple firmware
  * files require multiple MODULE_FIRMWARE() specifiers */
-#define MODULE_FIRMWARE(_firmware) MODULE_INFO(firmware, _firmware)
+#define MODULE_FIRMWARE(_firmware) MODULE_INFO_STRIP(firmware, _firmware)
 
 /* Given an address, look for it in the exception tables */
 const struct exception_table_entry *search_exception_tables(unsigned long add);
--- a/include/linux/moduleparam.h
+++ b/include/linux/moduleparam.h
@@ -16,6 +16,16 @@
 /* Chosen so that structs with an unsigned long line up. */
 #define MAX_PARAM_PREFIX_LEN (64 - sizeof(unsigned long))
 
+/* This struct is here for syntactic coherency, it is not used */
+#define __MODULE_INFO_DISABLED(name)					  \
+  struct __UNIQUE_ID(name) {}
+
+#ifdef CONFIG_MODULE_STRIPPED
+#define __MODULE_INFO_STRIP(tag, name, info) __MODULE_INFO_DISABLED(name)
+#else
+#define __MODULE_INFO_STRIP(tag, name, info) __MODULE_INFO(tag, name, info)
+#endif
+
 #ifdef MODULE
 #define __MODULE_INFO(tag, name, info)					  \
 static const char __UNIQUE_ID(name)[]					  \
@@ -23,8 +33,7 @@ static const char __UNIQUE_ID(name)[]
   = __stringify(tag) "=" info
 #else  /* !MODULE */
 /* This struct is here for syntactic coherency, it is not used */
-#define __MODULE_INFO(tag, name, info)					  \
-  struct __UNIQUE_ID(name) {}
+#define __MODULE_INFO(tag, name, info) __MODULE_INFO_DISABLED(name)
 #endif
 #define __MODULE_PARM_TYPE(name, _type)					  \
   __MODULE_INFO(parmtype, name##type, #name ":" _type)
@@ -32,7 +41,7 @@ static const char __UNIQUE_ID(name)[]
 /* One for each parameter, describing how to use it.  Some files do
    multiple of these per line, so can't just use MODULE_INFO. */
 #define MODULE_PARM_DESC(_parm, desc) \
-	__MODULE_INFO(parm, _parm, #_parm ":" desc)
+	__MODULE_INFO_STRIP(parm, _parm, #_parm ":" desc)
 
 struct kernel_param;
 
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -1708,6 +1708,13 @@ config MODULE_SIG_SHA512
 
 endchoice
 
+config MODULE_STRIPPED
+	bool "Reduce module size"
+	depends on MODULES
+	help
+	  Remove module parameter descriptions, author info, version, aliases,
+	  device tables, etc.
+
 endif # MODULES
 
 config INIT_ALL_POSSIBLE
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -2682,6 +2682,7 @@ static struct module *setup_load_info(st
 
 static int check_modinfo(struct module *mod, struct load_info *info, int flags)
 {
+#ifndef CONFIG_MODULE_STRIPPED
 	const char *modmagic = get_modinfo(info, "vermagic");
 	int err;
 
@@ -2708,6 +2709,7 @@ static int check_modinfo(struct module *
 		       " the quality is unknown, you have been warned.\n",
 		       mod->name);
 	}
+#endif
 
 	/* Set up license info based on the info section */
 	set_license(mod, get_modinfo(info, "license"));
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -1736,7 +1736,9 @@ static void read_symbols(char *modname)
 		symname = info.strtab + sym->st_name;
 
 		handle_modversions(mod, &info, sym, symname);
+#ifndef CONFIG_MODULE_STRIPPED
 		handle_moddevtable(mod, &info, sym, symname);
+#endif
 	}
 	if (!is_vmlinux(modname) ||
 	     (is_vmlinux(modname) && vmlinux_section_warnings))
@@ -1859,7 +1861,9 @@ static void add_header(struct buffer *b,
 	buf_printf(b, "#include <linux/vermagic.h>\n");
 	buf_printf(b, "#include <linux/compiler.h>\n");
 	buf_printf(b, "\n");
+#ifndef CONFIG_MODULE_STRIPPED
 	buf_printf(b, "MODULE_INFO(vermagic, VERMAGIC_STRING);\n");
+#endif
 	buf_printf(b, "\n");
 	buf_printf(b, "struct module __this_module\n");
 	buf_printf(b, "__attribute__((section(\".gnu.linkonce.this_module\"))) = {\n");
@@ -1876,16 +1880,20 @@ static void add_header(struct buffer *b,
 
 static void add_intree_flag(struct buffer *b, int is_intree)
 {
+#ifndef CONFIG_MODULE_STRIPPED
 	if (is_intree)
 		buf_printf(b, "\nMODULE_INFO(intree, \"Y\");\n");
+#endif
 }
 
 static void add_staging_flag(struct buffer *b, const char *name)
 {
+#ifndef CONFIG_MODULE_STRIPPED
 	static const char *staging_dir = "drivers/staging";
 
 	if (strncmp(staging_dir, name, strlen(staging_dir)) == 0)
 		buf_printf(b, "\nMODULE_INFO(staging, \"Y\");\n");
+#endif
 }
 
 /**
@@ -1977,11 +1985,13 @@ static void add_depends(struct buffer *b
 
 static void add_srcversion(struct buffer *b, struct module *mod)
 {
+#ifndef CONFIG_MODULE_STRIPPED
 	if (mod->srcversion[0]) {
 		buf_printf(b, "\n");
 		buf_printf(b, "MODULE_INFO(srcversion, \"%s\");\n",
 			   mod->srcversion);
 	}
+#endif
 }
 
 static void write_if_changed(struct buffer *b, const char *fname)
@@ -2204,7 +2214,9 @@ int main(int argc, char **argv)
 		add_staging_flag(&buf, mod->name);
 		err |= add_versions(&buf, mod);
 		add_depends(&buf, mod, modules);
+#ifndef CONFIG_MODULE_STRIPPED
 		add_moddevtable(&buf, mod);
+#endif
 		add_srcversion(&buf, mod);
 
 		sprintf(fname, "%s.mod.c", mod->name);
a id='n648' href='#n648'>648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875
--- a/net80211/ieee80211_scan_sta.c
+++ b/net80211/ieee80211_scan_sta.c
@@ -317,147 +317,6 @@ found:
 #undef ISPROBE
 }
 
-static struct ieee80211_channel *
-find11gchannel(struct ieee80211com *ic, int i, int freq)
-{
-	struct ieee80211_channel *c;
-	int j;
-
-	/*
-	 * The normal ordering in the channel list is b channel
-	 * immediately followed by g so optimize the search for
-	 * this.  We'll still do a full search just in case.
-	 */
-	for (j = i+1; j < ic->ic_nchans; j++) {
-		c = &ic->ic_channels[j];
-		if (c->ic_freq == freq && IEEE80211_IS_CHAN_ANYG(c))
-			return c;
-	}
-	for (j = 0; j < i; j++) {
-		c = &ic->ic_channels[j];
-		if (c->ic_freq == freq && IEEE80211_IS_CHAN_ANYG(c))
-			return c;
-	}
-	return NULL;
-}
-static const u_int chanflags[] = {
-	IEEE80211_CHAN_B,	/* IEEE80211_MODE_AUTO */
-	IEEE80211_CHAN_A,	/* IEEE80211_MODE_11A */
-	IEEE80211_CHAN_B,	/* IEEE80211_MODE_11B */
-	IEEE80211_CHAN_PUREG,	/* IEEE80211_MODE_11G */
-	IEEE80211_CHAN_FHSS,	/* IEEE80211_MODE_FH */
-	IEEE80211_CHAN_A,	/* IEEE80211_MODE_TURBO_A */ /* for turbo mode look for AP in normal channel */
-	IEEE80211_CHAN_PUREG,	/* IEEE80211_MODE_TURBO_G */
-	IEEE80211_CHAN_ST,	/* IEEE80211_MODE_TURBO_STATIC_A */
-};
-
-static void
-add_channels(struct ieee80211com *ic,
-	struct ieee80211_scan_state *ss,
-	enum ieee80211_phymode mode, const u_int16_t freq[], int nfreq)
-{
-	struct ieee80211_channel *c, *cg;
-	u_int modeflags;
-	int i;
-
-	KASSERT(mode < ARRAY_SIZE(chanflags), ("Unexpected mode %u", mode));
-	modeflags = chanflags[mode];
-	for (i = 0; i < nfreq; i++) {
-		c = ieee80211_find_channel(ic, freq[i], modeflags);
-		if (c == NULL || isclr(ic->ic_chan_active, c->ic_ieee))
-			continue;
-		if (mode == IEEE80211_MODE_AUTO) {
-			/*
-			 * XXX special-case 11b/g channels so we select
-			 *     the g channel if both are present.
-			 */
-			if (IEEE80211_IS_CHAN_B(c) &&
-			    (cg = find11gchannel(ic, i, c->ic_freq)) != NULL)
-				c = cg;
-		}
-		if (ss->ss_last >= IEEE80211_SCAN_MAX)
-			break;
-		ss->ss_chans[ss->ss_last++] = c;
-	}
-}
-
-static const u_int16_t rcl1[] =		/* 8 FCC channel: 52, 56, 60, 64, 36, 40, 44, 48 */
-{ 5260, 5280, 5300, 5320, 5180, 5200, 5220, 5240 };
-static const u_int16_t rcl2[] =		/* 4 MKK channels: 34, 38, 42, 46 */
-{ 5170, 5190, 5210, 5230 };
-static const u_int16_t rcl3[] =		/* 2.4Ghz ch: 1,6,11,7,13 */
-{ 2412, 2437, 2462, 2442, 2472 };
-static const u_int16_t rcl4[] =		/* 5 FCC channel: 149, 153, 161, 165 */
-{ 5745, 5765, 5785, 5805, 5825 };
-static const u_int16_t rcl7[] =		/* 11 ETSI channel: 100,104,108,112,116,120,124,128,132,136,140 */
-{ 5500, 5520, 5540, 5560, 5580, 5600, 5620, 5640, 5660, 5680, 5700 };
-static const u_int16_t rcl8[] =		/* 2.4Ghz ch: 2,3,4,5,8,9,10,12 */
-{ 2417, 2422, 2427, 2432, 2447, 2452, 2457, 2467 };
-static const u_int16_t rcl9[] =		/* 2.4Ghz ch: 14 */
-{ 2484 };
-static const u_int16_t rcl10[] =	/* Added Korean channels 2312-2372 */
-{ 2312, 2317, 2322, 2327, 2332, 2337, 2342, 2347, 2352, 2357, 2362, 2367, 2372 };
-static const u_int16_t rcl11[] =	/* Added Japan channels in 4.9/5.0 spectrum */
-{ 5040, 5060, 5080, 4920, 4940, 4960, 4980 };
-#ifdef ATH_TURBO_SCAN
-static const u_int16_t rcl5[] =		/* 3 static turbo channels */
-{ 5210, 5250, 5290 };
-static const u_int16_t rcl6[] =		/* 2 static turbo channels */
-{ 5760, 5800 };
-static const u_int16_t rcl6x[] =		/* 4 FCC3 turbo channels */
-{ 5540, 5580, 5620, 5660 };
-static const u_int16_t rcl12[] =		/* 2.4Ghz Turbo channel 6 */
-{ 2437 };
-static const u_int16_t rcl13[] =		/* dynamic Turbo channels */
-{ 5200, 5240, 5280, 5765, 5805 };
-#endif /* ATH_TURBO_SCAN */
-
-struct scanlist {
-	u_int16_t	mode;
-	u_int16_t	count;
-	const u_int16_t	*list;
-};
-
-#define	IEEE80211_MODE_TURBO_STATIC_A	IEEE80211_MODE_MAX
-#define	X(a)	.count = sizeof(a)/sizeof(a[0]), .list = a
-
-static const struct scanlist staScanTable[] = {
-	{ IEEE80211_MODE_11B,   		X(rcl3) },
-	{ IEEE80211_MODE_11A,   		X(rcl1) },
-	{ IEEE80211_MODE_11A,   		X(rcl2) },
-	{ IEEE80211_MODE_11B,   		X(rcl8) },
-	{ IEEE80211_MODE_11B,   		X(rcl9) },
-	{ IEEE80211_MODE_11A,   		X(rcl4) },
-#ifdef ATH_TURBO_SCAN
-	{ IEEE80211_MODE_TURBO_STATIC_A,	X(rcl5) },
-	{ IEEE80211_MODE_TURBO_STATIC_A,	X(rcl6) },
-	{ IEEE80211_MODE_TURBO_A,		X(rcl6x) },
-	{ IEEE80211_MODE_TURBO_A,		X(rcl13) },
-#endif /* ATH_TURBO_SCAN */
-	{ IEEE80211_MODE_11A,			X(rcl7) },
-	{ IEEE80211_MODE_11B,			X(rcl10) },
-	{ IEEE80211_MODE_11A,			X(rcl11) },
-#ifdef ATH_TURBO_SCAN
-	{ IEEE80211_MODE_TURBO_G,		X(rcl12) },
-#endif /* ATH_TURBO_SCAN */
-	{ .list = NULL }
-};
-
-#undef X
-
-static int
-checktable(const struct scanlist *scan, const struct ieee80211_channel *c)
-{
-	int i;
-
-	for (; scan->list != NULL; scan++) {
-		for (i = 0; i < scan->count; i++)
-			if (scan->list[i] == c->ic_freq)
-				return 1;
-	}
-	return 0;
-}
-
 /*
  * Start a station-mode scan by populating the channel list.
  */
@@ -466,81 +325,14 @@ sta_start(struct ieee80211_scan_state *s
 {
 	struct ieee80211com *ic = vap->iv_ic;
 	struct sta_table *st = ss->ss_priv;
-	const struct scanlist *scan;
 	enum ieee80211_phymode mode;
 	struct ieee80211_channel *c;
 	int i;
 
 	ss->ss_last = 0;
-	/*
-	 * Use the table of ordered channels to construct the list
-	 * of channels for scanning.  Any channels in the ordered
-	 * list not in the master list will be discarded.
-	 */
-	for (scan = staScanTable; scan->list != NULL; scan++) {
-		mode = scan->mode;
-		if (vap->iv_des_mode != IEEE80211_MODE_AUTO) {
-			/*
-			 * If a desired mode was specified, scan only 
-			 * channels that satisfy that constraint.
-			 */
-			if (vap->iv_des_mode != mode) {
-				/*
-				 * The scan table marks 2.4Ghz channels as b
-				 * so if the desired mode is 11g, then use
-				 * the 11b channel list but upgrade the mode.
-				 */
-				if (vap->iv_des_mode != IEEE80211_MODE_11G ||
-				    mode != IEEE80211_MODE_11B)
-					continue;
-				mode = IEEE80211_MODE_11G;	/* upgrade */
-			}
-		} else {
-			/*
-			 * This lets ieee80211_scan_add_channels
-			 * upgrade an 11b channel to 11g if available.
-			 */
-			if (mode == IEEE80211_MODE_11B)
-				mode = IEEE80211_MODE_AUTO;
-		}
-		/* XR does not operate on turbo channels */
-		if ((vap->iv_flags & IEEE80211_F_XR) &&
-		    (mode == IEEE80211_MODE_TURBO_A ||
-		     mode == IEEE80211_MODE_TURBO_G))
-			continue;
-		/*
-		 * Add the list of the channels; any that are not
-		 * in the master channel list will be discarded.
-		 */
-		add_channels(ic, ss, mode, scan->list, scan->count);
-	}
-
-	/*
-	 * Add the channels from the ic (from HAL) that are not present
-	 * in the staScanTable.
-	 */
-	for (i = 0; i < ic->ic_nchans; i++) {
-		c = &ic->ic_channels[i];
-		/*
-		 * scan dynamic turbo channels in normal mode.
-		 */
-		if (IEEE80211_IS_CHAN_DTURBO(c))
-			continue;
-		mode = ieee80211_chan2mode(c);
-		if (vap->iv_des_mode != IEEE80211_MODE_AUTO) {
-			/*
-			 * If a desired mode was specified, scan only 
-			 * channels that satisfy that constraint.
-			 */
-			if (vap->iv_des_mode != mode)
-				continue;
-
-		}
-		if (!checktable(staScanTable, c))
-			ss->ss_chans[ss->ss_last++] = c;
-	}
-
+	ieee80211_scan_add_channels(ic, ss, vap->iv_des_mode);
 	ss->ss_next = 0;
+
 	/* XXX tunables */
 	/* 
 	 * The scanner will stay on station for ss_maxdwell ms (using a 
@@ -749,17 +541,7 @@ match_bss(struct ieee80211vap *vap,
 	fail = 0;
 	if (isclr(ic->ic_chan_active, ieee80211_chan2ieee(ic, se->se_chan)))
 		fail |= 0x01;
-	/*
-	 * NB: normally the desired mode is used to construct
-	 * the channel list, but it's possible for the scan
-	 * cache to include entries for stations outside this
-	 * list so we check the desired mode here to weed them
-	 * out.
-	 */
-	if (vap->iv_des_mode != IEEE80211_MODE_AUTO &&
-	    (se->se_chan->ic_flags & IEEE80211_CHAN_ALLTURBO) !=
-	    chanflags[vap->iv_des_mode])
-		fail |= 0x01;
+
 	if (vap->iv_opmode == IEEE80211_M_IBSS) {
 		if ((se->se_capinfo & IEEE80211_CAPINFO_IBSS) == 0)
 			fail |= 0x02;
@@ -1168,78 +950,6 @@ static const struct ieee80211_scanner st
 	.scan_default		= ieee80211_sta_join,
 };
 
-/*
- * Start an adhoc-mode scan by populating the channel list.
- */
-static int
-adhoc_start(struct ieee80211_scan_state *ss, struct ieee80211vap *vap)
-{
-	struct ieee80211com *ic = vap->iv_ic;
-	struct sta_table *st = ss->ss_priv;
-	const struct scanlist *scan;
-	enum ieee80211_phymode mode;
-
-	ss->ss_last = 0;
-	/*
-	 * Use the table of ordered channels to construct the list
-	 * of channels for scanning.  Any channels in the ordered
-	 * list not in the master list will be discarded.
-	 */
-	for (scan = staScanTable; scan->list != NULL; scan++) {
-		mode = scan->mode;
-		if (vap->iv_des_mode != IEEE80211_MODE_AUTO) {
-			/*
-			 * If a desired mode was specified, scan only 
-			 * channels that satisfy that constraint.
-			 */
-			if (vap->iv_des_mode != mode) {
-				/*
-				 * The scan table marks 2.4Ghz channels as b
-				 * so if the desired mode is 11g, then use
-				 * the 11b channel list but upgrade the mode.
-				 */
-				if (vap->iv_des_mode != IEEE80211_MODE_11G ||
-				    mode != IEEE80211_MODE_11B)
-					continue;
-				mode = IEEE80211_MODE_11G;	/* upgrade */
-			}
-		} else {
-			/*
-			 * This lets ieee80211_scan_add_channels
-			 * upgrade an 11b channel to 11g if available.
-			 */
-			if (mode == IEEE80211_MODE_11B)
-				mode = IEEE80211_MODE_AUTO;
-		}
-		/* XR does not operate on turbo channels */
-		if ((vap->iv_flags & IEEE80211_F_XR) &&
-		    (mode == IEEE80211_MODE_TURBO_A ||
-		     mode == IEEE80211_MODE_TURBO_G))
-			continue;
-		/*
-		 * Add the list of the channels; any that are not
-		 * in the master channel list will be discarded.
-		 */
-		add_channels(ic, ss, mode, scan->list, scan->count);
-	}
-	ss->ss_next = 0;
-	/* XXX tunables */
-	ss->ss_mindwell = msecs_to_jiffies(200);	/* 200ms */
-	ss->ss_maxdwell = msecs_to_jiffies(200);	/* 200ms */
-
-#ifdef IEEE80211_DEBUG
-	if (ieee80211_msg_scan(vap)) {
-		printk("%s: scan set ", vap->iv_dev->name);
-		ieee80211_scan_dump_channels(ss);
-		printk(" dwell min %ld max %ld\n",
-			ss->ss_mindwell, ss->ss_maxdwell);
-	}
-#endif /* IEEE80211_DEBUG */
-
-	st->st_newscan = 1;
-
-	return 0;
-}
 
 /*
  * Select a channel to start an adhoc network on.
@@ -1405,7 +1115,7 @@ static const struct ieee80211_scanner ad
 	.scan_name		= "default",
 	.scan_attach		= sta_attach,
 	.scan_detach		= sta_detach,
-	.scan_start		= adhoc_start,
+	.scan_start		= sta_start,
 	.scan_restart		= sta_restart,
 	.scan_cancel		= sta_cancel,
 	.scan_end		= adhoc_pick_bss,
--- a/net80211/ieee80211.c
+++ b/net80211/ieee80211.c
@@ -278,6 +278,11 @@ ieee80211_ifattach(struct ieee80211com *
 			("channel with bogus ieee number %u", c->ic_ieee));
 		setbit(ic->ic_chan_avail, c->ic_ieee);
 
+		if (c->ic_scanflags & IEEE80211_NOSCAN_DEFAULT)
+			c->ic_scanflags |= IEEE80211_NOSCAN_SET;
+		else
+			c->ic_scanflags &= ~IEEE80211_NOSCAN_SET;
+
 		/* Identify mode capabilities. */
 		if (IEEE80211_IS_CHAN_A(c))
 			ic->ic_modecaps |= 1 << IEEE80211_MODE_11A;
--- a/net80211/_ieee80211.h
+++ b/net80211/_ieee80211.h
@@ -132,6 +132,11 @@ enum ieee80211_scanmode {
 	IEEE80211_SCAN_FIRST	= 2,	/* take first suitable candidate */
 };
 
+enum ieee80211_scanflags {
+	IEEE80211_NOSCAN_DEFAULT = (1 << 0),
+	IEEE80211_NOSCAN_SET     = (1 << 1),
+};
+
 /*
  * Channels are specified by frequency and attributes.
  */
@@ -142,6 +147,7 @@ struct ieee80211_channel {
 	int8_t ic_maxregpower;	/* maximum regulatory tx power in dBm */
 	int8_t ic_maxpower;	/* maximum tx power in dBm */
 	int8_t ic_minpower;	/* minimum tx power in dBm */
+	u_int8_t ic_scanflags;
 };
 
 #define	IEEE80211_CHAN_MAX	255
--- a/net80211/ieee80211_ioctl.h
+++ b/net80211/ieee80211_ioctl.h
@@ -555,6 +555,7 @@ struct ieee80211req_scan_result {
 #define	IEEE80211_IOCTL_WDSADDMAC	(SIOCIWFIRSTPRIV+26)
 #define	IEEE80211_IOCTL_WDSDELMAC	(SIOCIWFIRSTPRIV+28)
 #define	IEEE80211_IOCTL_KICKMAC		(SIOCIWFIRSTPRIV+30)
+#define	IEEE80211_IOCTL_SETSCANLIST	(SIOCIWFIRSTPRIV+31)
 
 enum {
 	IEEE80211_WMMPARAMS_CWMIN       = 1,
--- a/net80211/ieee80211_scan_ap.c
+++ b/net80211/ieee80211_scan_ap.c
@@ -129,131 +129,7 @@ struct ap_state {
 
 static int ap_flush(struct ieee80211_scan_state *);
 static void action_tasklet(IEEE80211_TQUEUE_ARG);
-static struct ieee80211_channel *find11gchannel(struct ieee80211com *ic, 
-		int i, int freq);
 
-static const u_int chanflags[] = {
-	IEEE80211_CHAN_B,	/* IEEE80211_MODE_AUTO */
-	IEEE80211_CHAN_A,	/* IEEE80211_MODE_11A */
-	IEEE80211_CHAN_B,	/* IEEE80211_MODE_11B */
-	IEEE80211_CHAN_PUREG,	/* IEEE80211_MODE_11G */
-	IEEE80211_CHAN_FHSS,	/* IEEE80211_MODE_FH */
-	IEEE80211_CHAN_A,	/* IEEE80211_MODE_TURBO_A */ /* for turbo mode 
-							      * look for AP in 
-							      * normal channel 
-							      */
-	IEEE80211_CHAN_PUREG,	/* IEEE80211_MODE_TURBO_G */
-	IEEE80211_CHAN_ST,	/* IEEE80211_MODE_TURBO_STATIC_A */
-};
-
-static const u_int16_t rcl1[] =		/* 8 FCC channel: 52, 56, 60, 64, 
-					 *                36, 40, 44, 48 */
-{ 5260, 5280, 5300, 5320, 5180, 5200, 5220, 5240 };
-static const u_int16_t rcl2[] =		/* 4 MKK channels: 34, 38, 42, 46 */
-{ 5170, 5190, 5210, 5230 };
-static const u_int16_t rcl3[] =		/* 2.4Ghz ch: 1,6,11,7,13 */
-{ 2412, 2437, 2462, 2442, 2472 };
-static const u_int16_t rcl4[] =		/* 5 FCC channel: 149, 153, 161, 165 */
-{ 5745, 5765, 5785, 5805, 5825 };
-static const u_int16_t rcl7[] =		/* 11 ETSI channel: 100, 104, 108, 112,
-					 *                  116, 120, 124, 128, 
-					 *                  132, 136, 140 */
-{ 5500, 5520, 5540, 5560, 5580, 5600, 5620, 5640, 5660, 5680, 5700 };
-static const u_int16_t rcl8[] =		/* 2.4Ghz ch: 2,3,4,5,8,9,10,12 */
-{ 2417, 2422, 2427, 2432, 2447, 2452, 2457, 2467 };
-static const u_int16_t rcl9[] =		/* 2.4Ghz ch: 14 */
-{ 2484 };
-static const u_int16_t rcl10[] =	/* Added Korean channels 2312-2372 */
-{ 2312, 2317, 2322, 2327, 2332, 2337, 2342, 2347, 2352, 2357, 2362, 2367, 2372 };
-static const u_int16_t rcl11[] =	/* Added Japan channels in 4.9/5.0 spectrum */
-{ 5040, 5060, 5080, 4920, 4940, 4960, 4980 };
-#ifdef ATH_TURBO_SCAN
-static const u_int16_t rcl5[] =		/* 3 static turbo channels */
-{ 5210, 5250, 5290 };
-static const u_int16_t rcl6[] =		/* 2 static turbo channels */
-{ 5760, 5800 };
-static const u_int16_t rcl6x[] =		/* 4 FCC3 turbo channels */
-{ 5540, 5580, 5620, 5660 };
-static const u_int16_t rcl12[] =		/* 2.4Ghz Turbo channel 6 */
-{ 2437 };
-static const u_int16_t rcl13[] =		/* dynamic Turbo channels */
-{ 5200, 5240, 5280, 5765, 5805 };
-#endif /* ATH_TURBO_SCAN */
-
-struct scanlist {
-	u_int16_t	mode;
-	u_int16_t	count;
-	const u_int16_t	*list;
-};
-
-#define	IEEE80211_MODE_TURBO_STATIC_A	IEEE80211_MODE_MAX
-#define	X(a)	.count = ARRAY_SIZE(a), .list = a
-
-static const struct scanlist staScanTable[] = {
-	{ IEEE80211_MODE_11B,   		X(rcl3)  },
-	{ IEEE80211_MODE_11A,   		X(rcl1)  },
-	{ IEEE80211_MODE_11A,   		X(rcl2)  },
-	{ IEEE80211_MODE_11B,   		X(rcl8)  },
-	{ IEEE80211_MODE_11B,   		X(rcl9)  },
-	{ IEEE80211_MODE_11A,   		X(rcl4)  },
-#ifdef ATH_TURBO_SCAN
-	{ IEEE80211_MODE_TURBO_STATIC_A,	X(rcl5)  },
-	{ IEEE80211_MODE_TURBO_STATIC_A,	X(rcl6)  },
-	{ IEEE80211_MODE_TURBO_A,		X(rcl6x) },
-	{ IEEE80211_MODE_TURBO_A,		X(rcl13) },
-#endif /* ATH_TURBO_SCAN */
-	{ IEEE80211_MODE_11A,			X(rcl7)  },
-	{ IEEE80211_MODE_11B,			X(rcl10) },
-	{ IEEE80211_MODE_11A,			X(rcl11) },
-#ifdef ATH_TURBO_SCAN
-	{ IEEE80211_MODE_TURBO_G,		X(rcl12) },
-#endif /* ATH_TURBO_SCAN */
-	{ .list = NULL }
-};
-
-#undef X
-/* This function must be invoked with locks acquired */
-static void
-add_channels(struct ieee80211com *ic,
-	struct ieee80211_scan_state *ss,
-	enum ieee80211_phymode mode, const u_int16_t freq[], int nfreq)
-{
-	struct ieee80211_channel *c, *cg;
-	u_int modeflags;
-	int i;
-
-	KASSERT(mode < ARRAY_SIZE(chanflags), ("Unexpected mode %u", mode));
-	modeflags = chanflags[mode];
-	for (i = 0; i < nfreq; i++) {
-		c = ieee80211_find_channel(ic, freq[i], modeflags);
-		if ((c == NULL) || isclr(ic->ic_chan_active, c->ic_ieee))
-			continue;
-		if (mode == IEEE80211_MODE_AUTO) {
-			/* XXX special-case 11b/g channels so we select
-			 *     the g channel if both are present. */
-			if (IEEE80211_IS_CHAN_B(c) &&
-			    (cg = find11gchannel(ic, i, c->ic_freq)) != NULL)
-				c = cg;
-		}
-		if (ss->ss_last >= IEEE80211_SCAN_MAX)
-			break;
-		ss->ss_chans[ss->ss_last++] = c;
-	}
-}
-
-/* This function must be invoked with locks acquired */
-static int
-checktable(const struct scanlist *scan, const struct ieee80211_channel *c)
-{
-	int i;
-
-	for (; scan->list != NULL; scan++) {
-		for (i = 0; i < scan->count; i++)
-			if (scan->list[i] == c->ic_freq)
-				return 1;
-	}
-	return 0;
-}
 
 /*
  * Attach prior to any scanning work.
@@ -327,29 +203,6 @@ saveie(u_int8_t **iep, const u_int8_t *i
 		ieee80211_saveie(iep, ie);
 }
 
-/* This function must be invoked with locks acquired */
-static struct ieee80211_channel *
-find11gchannel(struct ieee80211com *ic, int i, int freq)
-{
-	struct ieee80211_channel *c;
-	int j;
-
-	/* The normal ordering in the channel list is b channel
-	 * immediately followed by g so optimize the search for
-	 * this.  We'll still do a full search just in case. */
-	for (j = i + 1; j < ic->ic_nchans; j++) {
-		c = &ic->ic_channels[j];
-		if ((c->ic_freq == freq) && IEEE80211_IS_CHAN_ANYG(c))
-			return c;
-	}
-	for (j = 0; j < i; j++) {
-		c = &ic->ic_channels[j];
-		if ((c->ic_freq == freq) && IEEE80211_IS_CHAN_ANYG(c))
-			return c;
-	}
-	return NULL;
-}
-
 /*
  * Start an ap scan by populating the channel list.
  */
@@ -358,8 +211,6 @@ ap_start(struct ieee80211_scan_state *ss
 {
 	struct ap_state *as 	    = ss->ss_priv;
 	struct ieee80211com *ic     = NULL;
-	const struct scanlist *sl   = NULL;
-	struct ieee80211_channel *c = NULL;
 	int i;
 	unsigned int mode = 0;
 
@@ -368,80 +219,8 @@ ap_start(struct ieee80211_scan_state *ss
 	/* Determine mode flags to match, or leave zero for auto mode */
 	as->as_vap_desired_mode = vap->iv_des_mode;
 	as->as_required_mode    = 0;
-	if (as->as_vap_desired_mode != IEEE80211_MODE_AUTO) {
-		as->as_required_mode = chanflags[as->as_vap_desired_mode];
-		if ((vap->iv_ath_cap & IEEE80211_ATHC_TURBOP) && 
-		    (as->as_required_mode != IEEE80211_CHAN_ST)) {
-			/* Fixup for dynamic turbo flags */
-			if (as->as_vap_desired_mode == IEEE80211_MODE_11G)
-				as->as_required_mode = IEEE80211_CHAN_108G;
-			else
-				as->as_required_mode = IEEE80211_CHAN_108A;
-		}
-	}
-
-	ss->ss_last = 0;
-	/* Use the table of ordered channels to construct the list
-	 * of channels for scanning.  Any channels in the ordered
-	 * list not in the master list will be discarded. */
-	for (sl = staScanTable; sl->list != NULL; sl++) {
-		mode = sl->mode;
-
-		/* The scan table marks 2.4Ghz channels as b
-		 * so if the desired mode is 11g, then use
-		 * the 11b channel list but upgrade the mode. */
-		if (as->as_vap_desired_mode &&
-		    (as->as_vap_desired_mode != mode) && 
-		    (as->as_vap_desired_mode == IEEE80211_MODE_11G) && 
-		    (mode == IEEE80211_MODE_11B))
-			mode = IEEE80211_MODE_11G;
-
-		/* If we are in "AUTO" mode, upgrade the mode to auto. 
-		 * This lets add_channels upgrade an 11b channel to 
-		 * 11g if available. */
-		if (!as->as_vap_desired_mode && (mode == IEEE80211_MODE_11B))
-			mode = IEEE80211_MODE_AUTO;
-
-		/* Add the list of the channels; any that are not
-		 * in the master channel list will be discarded. */
-		add_channels(ic, ss, mode, sl->list, sl->count);
-	}
-
-	/* Add the channels from the ic (from HAL) that are not present
-	 * in the staScanTable, assuming they pass the sanity checks... */
-	for (i = 0; i < ic->ic_nchans; i++) {
-		c = &ic->ic_channels[i];
-
-		/* XR is not supported on turbo channels */
-		if (IEEE80211_IS_CHAN_TURBO(c) && vap->iv_flags & IEEE80211_F_XR)
-			continue;
+	ieee80211_scan_add_channels(ic, ss, vap->iv_des_mode);
 
-		/* Dynamic channels are scanned in base mode */
-		if (!as->as_required_mode && !IEEE80211_IS_CHAN_ST(c))
-			continue;
-
-		/* Use any 11g channel instead of 11b one. */
-		if (vap->iv_des_mode == IEEE80211_MODE_AUTO && 
-		    IEEE80211_IS_CHAN_B(c) &&
-		    find11gchannel(ic, i, c->ic_freq))
-			continue;
-
-		/* Do not add channels already put into the scan list by the
-		 * scan table - these have already been filtered by mode
-		 * and for whether they are in the active channel list. */
-		if (checktable(staScanTable, c))
-			continue;
-
-		/* Make sure the channel is active */
-		if ((c == NULL) || isclr(ic->ic_chan_active, c->ic_ieee))
-			continue;
-
-		/* Don't overrun */
-		if (ss->ss_last >= IEEE80211_SCAN_MAX)
-			break;
-
-		ss->ss_chans[ss->ss_last++] = c;
-	}
 	ss->ss_next = 0;
 	/* XXX tunables */
 	ss->ss_mindwell = msecs_to_jiffies(200);	/* 200ms */
@@ -761,13 +540,6 @@ pick_channel(struct ieee80211_scan_state
 		if (IEEE80211_IS_CHAN_RADAR(c->chan))
 			continue;
 
-		/* Do not select 802.11a ST if mode is specified and is not 
-		 * 802.11a ST */
-		if (as->as_required_mode &&
-		    IEEE80211_IS_CHAN_STURBO(c->chan) &&
-		    (as->as_vap_desired_mode != IEEE80211_MODE_TURBO_STATIC_A))
-			continue;
-
 		/* Verify mode matches any fixed mode specified */
 		if((c->chan->ic_flags & as->as_required_mode) != 
 				as->as_required_mode)
--- a/net80211/ieee80211_scan.c
+++ b/net80211/ieee80211_scan.c
@@ -958,6 +958,80 @@ ieee80211_scan_flush(struct ieee80211com
 	}
 }
 
+static const u_int chanflags[] = {
+	0,	/* IEEE80211_MODE_AUTO */
+	IEEE80211_CHAN_A,	/* IEEE80211_MODE_11A */
+	IEEE80211_CHAN_B,	/* IEEE80211_MODE_11B */
+	IEEE80211_CHAN_PUREG,	/* IEEE80211_MODE_11G */
+	IEEE80211_CHAN_FHSS,	/* IEEE80211_MODE_FH */
+	IEEE80211_CHAN_A,	/* IEEE80211_MODE_TURBO_A */ /* for turbo mode look for AP in normal channel */
+	IEEE80211_CHAN_PUREG,	/* IEEE80211_MODE_TURBO_G */
+	IEEE80211_CHAN_ST,	/* IEEE80211_MODE_TURBO_STATIC_A */
+};
+
+static struct ieee80211_channel *
+find11gchannel(struct ieee80211com *ic, int i, int freq)
+{
+	struct ieee80211_channel *c;
+	int j;
+
+	/*
+	 * The normal ordering in the channel list is b channel
+	 * immediately followed by g so optimize the search for
+	 * this.  We'll still do a full search just in case.
+	 */
+	for (j = i+1; j < ic->ic_nchans; j++) {
+		c = &ic->ic_channels[j];
+		if (c->ic_freq == freq && IEEE80211_IS_CHAN_ANYG(c))
+			return c;
+	}
+	for (j = 0; j < i; j++) {
+		c = &ic->ic_channels[j];
+		if (c->ic_freq == freq && IEEE80211_IS_CHAN_ANYG(c))
+			return c;
+	}
+	return NULL;
+}
+
+
+void
+ieee80211_scan_add_channels(struct ieee80211com *ic,
+	struct ieee80211_scan_state *ss,
+	enum ieee80211_phymode mode)
+{
+	struct ieee80211_channel *c, *cg;
+	u_int modeflags;
+	int i;
+
+	KASSERT(mode < ARRAY_SIZE(chanflags), ("Unexpected mode %u", mode));
+	modeflags = chanflags[mode];
+	for (i = 0; i < ic->ic_nchans; i++) {
+		c = &ic->ic_channels[i];
+		if (c == NULL || isclr(ic->ic_chan_active, c->ic_ieee))
+			continue;
+		if (c->ic_scanflags & IEEE80211_NOSCAN_SET)
+			continue;
+		if (modeflags &&
+			((c->ic_flags & IEEE80211_CHAN_ALLTURBO) !=
+			 (modeflags & IEEE80211_CHAN_ALLTURBO)))
+			continue;
+		if (mode == IEEE80211_MODE_AUTO) {
+			/*
+			 * XXX special-case 11b/g channels so we select
+			 *     the g channel if both are present.
+			 */
+			if (IEEE80211_IS_CHAN_B(c) &&
+			    (cg = find11gchannel(ic, i, c->ic_freq)) != NULL)
+				continue;
+		}
+		if (ss->ss_last >= IEEE80211_SCAN_MAX)
+			break;
+		ss->ss_chans[ss->ss_last++] = c;
+	}
+}
+EXPORT_SYMBOL(ieee80211_scan_add_channels);
+
+
 /*
  * Execute radar channel change. This is called when a radar/dfs
  * signal is detected.  AP mode only.  Return 1 on success, 0 on
--- a/net80211/ieee80211_scan.h
+++ b/net80211/ieee80211_scan.h
@@ -219,4 +219,7 @@ void ieee80211_scanner_register(enum iee
 void ieee80211_scanner_unregister(enum ieee80211_opmode,
 	const struct ieee80211_scanner *);
 void ieee80211_scanner_unregister_all(const struct ieee80211_scanner *);
+void ieee80211_scan_add_channels(struct ieee80211com *ic,
+	struct ieee80211_scan_state *ss,
+	enum ieee80211_phymode mode);
 #endif /* _NET80211_IEEE80211_SCAN_H_ */
--- a/net80211/ieee80211_wireless.c
+++ b/net80211/ieee80211_wireless.c
@@ -3873,6 +3873,106 @@ ieee80211_ioctl_kickmac(struct net_devic
 	return ieee80211_ioctl_setmlme(dev, info, w, (char *)&mlme);
 }
 
+static inline void setflag(struct ieee80211_channel *c, int flag)
+{
+	if (flag)
+		c->ic_scanflags |= IEEE80211_NOSCAN_SET;
+	else
+		c->ic_scanflags &= ~IEEE80211_NOSCAN_SET;
+}
+
+static void setscanflag(struct ieee80211com *ic, int min, int max, int set)
+{
+	int i;
+
+	for (i = 0; i < ic->ic_nchans; i++) {
+		struct ieee80211_channel *c = &ic->ic_channels[i];
+
+		if (min == -1) {
+			if (!(c->ic_scanflags & IEEE80211_NOSCAN_DEFAULT))
+				setflag(c, set);
+		} else if ((c->ic_freq >= min) && (c->ic_freq <= max)) {
+			setflag(c, set);
+		}
+	}
+}
+
+static int
+ieee80211_ioctl_setscanlist(struct net_device *dev,
+	struct iw_request_info *info,
+	struct iw_point *data, char *extra)
+{
+	struct ieee80211vap *vap = dev->priv;
+	struct ieee80211com *ic = vap->iv_ic;
+	char *s, *next;
+	int val = 1;
+
+	if (data->length <= 0)
+		return -EINVAL;
+
+	s = kmalloc(data->length + 1, GFP_KERNEL);
+	if (!s)
+		return -ENOMEM;
+
+	memset(s, 0, data->length + 1);
+	if (copy_from_user(s, data->pointer, data->length))
+		return -EFAULT;
+
+	s[data->length - 1] = '\0';		/* ensure null termination */
+
+	switch(*s) {
+		case '-':
+			val = 1;
+			break;
+		case '+':
+			val = 0;
+			break;
+		default:
+			goto error;
+	}
+	s++;
+	next = s;
+	do {
+		next = strchr(s, ',');
+		if (next) {
+			*next = 0;
+			next++;
+		}
+		if (!strcmp(s, "ALL")) {
+			setscanflag(ic, 0, 10000, val);
+		} else if (!strcmp(s, "REG")) {
+			setscanflag(ic, -1, -1, val);
+		} else {
+			int min, max;
+			char *n, *end = NULL;
+
+			n = strchr(s, '-');
+			if (n) {
+				*n = 0;
+				n++;
+			}
+			min = simple_strtoul(s, &end, 10);
+			if (end && *end)
+				goto error;
+			if (n) {
+				max = simple_strtoul(n, &end, 10);
+				if (end && *end)
+					goto error;
+			} else {
+				max = min;
+			}
+			setscanflag(ic, min, max, val);
+		}
+		s = next;
+	} while (next);
+	return 0;
+
+error:
+	if (s)
+		kfree(s);
+	return -EINVAL;
+}
+
 static int
 ieee80211_ioctl_addmac(struct net_device *dev, struct iw_request_info *info,
 	void *w, char *extra)
@@ -5656,6 +5756,8 @@ static const struct iw_priv_args ieee802
 	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "minrate"},
 	{IEEE80211_PARAM_MINRATE,
 	 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_minrate"},
+	{ IEEE80211_IOCTL_SETSCANLIST,
+	 IW_PRIV_TYPE_CHAR | 255, 0, "setscanlist"},
 
 #ifdef ATH_REVERSE_ENGINEERING
 	/*
@@ -5753,6 +5855,7 @@ static const iw_handler ieee80211_priv_h
 	set_priv(IEEE80211_IOCTL_WDSADDMAC, ieee80211_ioctl_wdsmac),
 	set_priv(IEEE80211_IOCTL_WDSDELMAC, ieee80211_ioctl_wdsdelmac),
 	set_priv(IEEE80211_IOCTL_KICKMAC, ieee80211_ioctl_kickmac),
+	set_priv(IEEE80211_IOCTL_SETSCANLIST, ieee80211_ioctl_setscanlist),
 #ifdef ATH_REVERSE_ENGINEERING
 	set_priv(IEEE80211_IOCTL_READREG, ieee80211_ioctl_readreg),
 	set_priv(IEEE80211_IOCTL_WRITEREG, ieee80211_ioctl_writereg),